Russ Allbery > Eagle's Path > October 2017 | Bundle haul > |
I said that I was going to start writing these regularly, so I'm going to stick to it, even when the results are rather underwhelming. One of the goals is to make the time for more free software work, and I do better at doing things that I record.
The only piece of free software work for September was that I made rra-c-util compile cleanly with the Clang static analyzer. This was fairly tedious work that mostly involved unconfusing the compiler or converting (semi-intentional) crashes into explicit asserts, but it unblocks using the Clang static analyzer as part of the automated test suite of my other projects that are downstream of rra-c-util.
One of the semantic changes I made was that the vector utilities in
rra-c-util (which maintain a resizable array of strings) now always
allocate room for at least one string pointer. This wastes a small amount
of memory for empty vectors that are never used, but ensures that the
strings
struct member is always valid. This isn't, strictly
speaking, a correctness fix, since all the checks were correct, but after
some thought, I decided that humans might have the same problem that the
static analyzer had. It's a lot easier to reason about a field that's
never NULL. Similarly, the replacement function for a missing
reallocarray
now does an allocation of size 1 if given a size of 0,
just to avoid edge case behavior. (I'm sure the behavior of a realloc
with size 0 is defined somewhere in the C standard, but if I have to look
it up, I'd rather not make a human reason about it.)
I started on, but didn't finish, making rra-c-util compile without Clang
warnings (at least for a chosen set of warnings). By far the hardest
problem here are the Clang warnings for comparisons between unsigned and
signed integers. In theory, I like this warning, since it's the cause of
a lot of very obscure bugs. In practice, gah does C ever do this all over
the place, and it's incredibly painful to avoid. (One of the biggest
offenders is write
, which returns a ssize_t
that you almost
always want to compare against a size_t
.) I did a bunch of
mechanical work, but I now have a lot of bits of code like:
if (status < 0) return; written = (size_t) status; if (written < avail) buffer->left += written;
which is ugly and unsatisfying. And I also have a ton of casts, such as with:
buffer_resize(buffer, (size_t) st.st_size + used);
since st.st_size
is an off_t
, which may be signed. This is
all deeply unsatisfying and ugly, and I think it makes the code moderately
harder to read, but I do think the warning will potentially catch bugs and
even security issues.
I'm still torn. Maybe I can find some nice macros or programming styles to avoid the worst of this problem. It definitely requires more thought, rather than just committing this huge mechanical change with lots of ugly code.
Mostly, this kind of nonsense makes me want to stop working on C code and go finish learning Rust....
Anyway, apart from work, the biggest thing I managed to do last month that was vaguely related to free software was upgrading my personal servers to stretch (finally). That mostly went okay; only a few things made it unnecessarily exciting.
The first was that one of my systems had a very tiny / partition that was
too small to hold the downloaded debs for the upgrade, so I had to resize
it (VM disk, partition, and file system), and that was a bit exciting
because it has an old-style DOS partition table that isn't aligned (hmmm,
which is probably why disk I/O is so slow on those VMs), so I had to use
the obsolete fdisk -c=dos
mode because I wasn't up for replacing
the partition right then.
The second was that my first try at an upgrade died with a segfault during
the libc6 postinst and then every executable segfaulted. A mild panic and
a rescue disk later (and thirty minutes and a lot of swearing), I tracked
the problem down to libc6-xen. Nothing in the dependency structure
between jessie and stretch forces libc6-xen to be upgraded in lockstep or
removed, but it's earlier in the search path. So ld.so gets upgraded, and
then finds the old libc6 from the libc6-xen package, and the mismatch
causes immediate segfaults. A chroot dpkg --purge
from the rescue
disk solved the problem as soon as I knew what was going on, but that was
a stressful half-hour.
The third problem was something I should have known was going to be an
issue: an old Perl program that does some internal stuff for one of the
services I ran had a defined @array
test that has been warning for
eons and that I never fixed. That became a full syntax error with the
most recent Perl, and then I fixed it incorrectly the first time and had a
bunch of trouble tracking down what I'd broken. All sorted out now, and
everything is happily running stretch. (ejabberd, which other folks had
mentioned was a problem, went completely smoothly, although I suspect I
now have too many of the plugin packages installed and should do a
purging.)
Posted: 2017-10-15 21:47 — Why no comments?
Russ Allbery > Eagle's Path > October 2017 | Bundle haul > |