OpenBSD Journal

p2k18 Hackathon report: Christian Weisgerber (naddy@) On clang 6 fallout, doing the right thing, and fixes for aarch64

Contributed by Peter N. M. Hansteen on from the clang goes the aarch64 dept.

Our next p2k18 report comes from Christian "naddy" Weisgerber, who writes:

By the time I arrived in Nantes, I was not in the best of moods. The French railroad strike had forced me to cancel my train tickets and book flights instead; the late evening leg of the journey was delayed by one and a half hours because the plane required repairs; and my luggage was nowhere to be found. (It would arrive the next day.) Plus, I had been too busy in the days before, so I had little idea what to work on other than vague intentions to fix the remaining clang 6 fallout, take care of a few overdue port updates, and then look at build failures on aarch64 (aka arm64). Not much of a plan, but it would prove a good plan.

About two weeks before p2k18, the base system compiler had been upgraded from clang 5 to clang 6. This broke a lot of ports, principally old C++ code. Much of this did not demand a deep understanding of C++ to fix. When gluing together string literals, clang 6 now requires whitespace between a plain literal and a preprocessor-defined one ("foo" BAR instead of "foo"BAR). The compiler no longer considers everything that is represented by zero bits as the same: NULL pointers, the character constant '\0', integral numbers 0, and false are not randomly interchangeable. This found some bugs: Is ptr == '\0' intended as ptr == NULL or *ptr == '\0'? Finally, clang 6 is more strict about assigning types with a larger range of values to those with a smaller one, necessitating explicit casts. There had been a push to fix all this fallout before the hackathon, but we ran out of steam as people had to prepare for travel, so I went back to work right away in Nantes and fixed the remaining stragglers until the whole tree built again on amd64.

When working on ports, there is frequently a conflict between doing things the right way and simply getting them done. Say you find a problem in a piece of software: Do you take the time to write a proper fix that can be submitted upstream, jump through whatever hoops are required to actually file a bug, and potentially argue with the upstream maintainer? Or do you simply fix the port and move on to the next one out of the dozens that need attention? Back in December a new version of GNU tar was released. A straightforward port, simple to update... but there were regression test failures. What do you do? Ignore them? Investigate? Prior experience suggests that this will be time-consuming and eventually frustrating, since the failures will likely turn out to be harmless and not indicate actual problems in functionality. I shelved the update for a later date. Well, almost half a year had passed, so I finally set down to deal with this. The first problem turned out to be of our own making. When we no longer required the fake step to run as root, the ports infrastructure added a dummy chown(8) command that does nothing. This had completely slipped my mind, so I spent an infuriating amount of time trying in vain to find a problem in a 58,000-line, m4(1)-generated shell script before I stumbled on our dummy replacement again. Sigh. The second problem was due to a basic system tool behaving differently on Linux than on BSD. The third problem was caused by gnulib changing functionality, which went unnoticed by the gtar maintainers because a corner case in the heavily #ifdef’ed code allowed it to still work on Linux. None of this actually affected gtar’s functioning. In the end, I sunk a day of work into what should have been a very simple port update. Doing the right thing doesn’t come cheap.

Having exhausted what little pre-planned work I had, I went to look at build failures on aarch64—and promptly got side-tracked by a compiler warning. Functions like fgetc(3), getc(3), getchar(3) and getopt(3) return an int value, because beyond returning every possible character they also need to signal an end condition like EOF or -1. Assigning their return value to a char and comparing this to the end condition is a mistake that will cause various problems, depending whether char defaults to signed or unsigned (aarch64, armv7, powerpc) on a particular hardware platform. For instance, this...

	char ch;
	while ((ch = getopt(argc, argv, "bf:")) != -1) {

... is an infinite loop on unsigned char platforms. Fortunately, clang complains about this, so I grepped a full set of aarch64 build logs for suspicious warnings and went on to fix some twenty ports. Frankly, this is elementary programming and not something I should still have to deal with in 2018.

As p2k18 started to draw to a close, I did some triaging of the port build failures on aarch64 and began fixing one particular type of error. When you call a library function from your program, say, sin(3), you need to explicitly link in the library that provides this function (here libm, thus cc ... -lm). With the ancient binutils 2.17 that most of our architectures still use, it is sufficient if some other library libfoo indirectly pulls in the required library. This no longer works with lld, which is LLVM’s new linker that we already use on aarch64 and eventually will elsewhere, too. Fixing such ports allows them to build on aarch64 now—and on amd64 tomorrow.

In the end I got a satisfying amount of work done, fueled by the excellent local cidre and galettes. Thanks to everybody who... oh, you know the formula. Au revoir, à la prochaine !

Thanks for the report, and all the excellent work, Naddy!

(Comments are closed)

Latest Articles


Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]