[TUHS] C vs the world (was Re: Hypothetical: Could MULTICS have been written in C, if available?)

Dan Cross via TUHS tuhs at tuhs.org
Thu May 28 07:07:28 AEST 2026


On Tue, May 27, 2026 Larry McVoy via TUHS <tuhs at tuhs.org> wrote:
> On Wed, May 27, 2026 at 11:50:34AM -0400, Dan Cross wrote:
> > On Tue, May 26, 2026 at 10:02???AM Larry McVoy via TUHS <tuhs at tuhs.org> wrote:
> > > [snip BLS's comments about cars, instruments, and programs]
> > > Amen to all of this.  And I think I've posted this but it is worth a repeat
> > > since you mentioned sports cars.
> > >
> > > When Travis was looking at C, I told him that C is like driving a sports
> > > car on a narrow, twisty road with no guard rails and a there is a cliff
> > > on one side of the road.  So it is not for people who want to look at their
> > > phone while driving, that's how you die.  On the other hand, if you are a
> > > good driver, that narrow, twisty road and that car are glorious.
> >
> > But you have also said that if you take someone out on your boat, and
> > they won't wear a flotation device, that's the last time they're going
> > out on your boat.
>
> Yep.  It's a liability thing, if I don't get them home safe, I can be
> sued for loss of life.

One hopes the consequences for a crashing program are not nearly so dire.

However, we find software running in all sorts of strange places now;
how many of the regulars on this list have code running on Mars? I'll
bet more than one has something that made it onto a rover.

> > If the sports car goes off the side of the mountain, 99 times out of
> > 100 the only one who ends up in the morgue is the driver: tragic,
> > perhaps, but one's own damn fault. On the other hand, if the school
> > bus goes off the road, the consequences are far worse. Most of the
> > time software is Not a sports car; it's more like a school bus loaded
> > with kids.
>
> Fair point.
>
> > On the other hand, it's super easy to inadvertently stumble into
> > undefined behavior and segfaults, even in extremely well-written C.
> > Here's an example from the bitkeeper source. I randomly looked at
> > https://github.com/bitkeeper-scm/bitkeeper/blob/master/src/port/bkd_server.c,
> > and notice the following on lines 58 and 59:
> >
> > ```
> > |        while (nav[i++] = av[j++]);
> > |        assert(i < 100);
> > ```
>
> We have regression tests that throw all sort of random noise at every bk
> command.

I believe you. The code I'm looking at is good, solid, readable C. It
also has errors. But that's not a dig on bitkeeper; pretty much any
large source base has errors.

> > Here, the contents of the string array `av` are copied into `nav`,
> > which is defined as, `char *nav[100];`. Near as I can tell, this is
> > called directly with an only slightly-modified version of the
> > arguments to `main`, but nothing checks that the input argument vector
> > will not overflow `nav` before the loop.  The `assert` is obviously
> > meant to catch this, but since it happens _after_ the loop, by the
> > time you run into it, you've probably already clobbered what was
> > around `nav` on the stack; indeed, I can trigger this on a local
> > build, and the resulting stack frame is junk.  Moreover, the code as
> > written is wrong: the array has space for 100 elements, thus indices
> > 0..99 are valid. Suppose that i==99'th element is the terminating nil
> > pointer, then the `i++` index expression would set nav[99] and then
> > set i to 100; that's perfectly valid, but in that case, the `assert`
> > will still fire: that is, the last element in `nav` is inaccessible as
> > written.
>
> And yet, that code has been running for decades with out problems.  Yeah,
> it could be cleaner, but we had other work to do.  You are all worked up
> about a non-problem.

I am hardly "all worked up about" it. It was just something I saw when
I casually looked at the code and it jumped out to me as clearly a
bug. If I saw it in a code review, I would flag it, whether it was
likely to happen in practice or not.

> > Of course, this is kind of a silly example: only a jerk is going to
> > give more than 100 arguments to `bk` in order to trigger this bug, but
> > the point is, you're going to invariably find this kind of thing in
> > _any_ large C code base, even ones written by legitimate experts
> > extremely familiar with the language.
>
> Indeed.  Except it was not ever a problem.  Your stance reminds me a little
> of Bart Miller's fuzz paper.  Yep, you pass random garbage to every program
> in /usr/bin and you will find all sorts of bugs.  But is that useful
> information if everyone is using those programs without triggering those
> bugs?

That's the thing: `gets` wasn't a serious problem until rtm used it to
overflow the stack and execute arbitrary code on a bunch of VAXen and
Sun3s. So it is with most software bugs; they're never really a
problem until they are. The argument that an unrealized bug isn't
really a bug feels compelling until you realize that it might be a
timebomb waiting to happen; and in particular when you consider that
software is often used in ways that no one foresees when it's first
written (see Paul's note).

It's easy to deride Miller's thing as impractical or frivolous, but
that is cold comfort if a bug hsi report highlighted turned into a
root exploit because someone exec'ed an affected program from a setuid
binary with unsanitized user input. Surely we all remember the bugs
back in the 1990s where people got root by setting `$PATH` and `$IFS`
before running a setuid binary that invoked `system()` or `popen()`?
One wonders how many of the bugs Miller mentioned ended up used in
exploits after the stack smashing paper 6 years later?

> Back in the day, Coverity used BitKeeper and we got to use their tool on
> our source base.  It was useless, it found all sorts of stuff, but it was
> all like your example, a bug in theory but not in practice.

*Yet*.  A bug in theory but not in practice *yet*. But this begs the
question, why `assert` at all? The `assert` here is simply not
correct.

Besides, fixing this is trivial:

|        while (i < 100 && nav[i++] = av[j++]);
|        assert(0 < i && i <= 100 && nav[i - 1] == NULL);

Or even better:

|/* stuff this in a header somewhere */
|#define nitems(A) (sizeof(A)/sizeof((A)[0]))
|
|   ...
|
|        while (i < nitems(nav) && nav[i++] = av[j++]);
|        assert(0 < i && i <= nitems(nav) && nav[i - 1] == NULL);

Anyway, it seems to me that if you have a tool flagging things like
that, where the fixes are easy, there's no reason not to just
implement them. I consider it an insurance policy against the future.

The situation is even worse in C, because the language is only
informally specified, the specification is not tied to the behavior of
real computers, UB is so non-obvious, and for whatever weird reason,
the compiler people now have this sadistic hatred of their users and
will take advantage of any and every instance of UB to make a
microbenchmark go faster at the expense of real world code. That
program that's worked _perfectly_ for decades may well delete a bunch
of data when built with some point revision of a compiler and invoked
in an unexpected way that wasn't covered in the test suite, all
because there was some random bit of UB lurking somewhere. And if you
complain to the compiler people? "Tough; you're the one who added the
UB." No matter how we may feel about the language, this is a real
problem. See also, Yodaiken's paper: https://arxiv.org/pdf/2201.07845

Though in defense of C, people who are fed up with the situation are
joining the committee and trying to address this. There's a UB working
group that's actively trying to reduce it the amount of it in the
language and the effects it can actually have.

> If it had found any real bugs, we would have been pleased.  It did not.

See above. Bluntly, this sounds like hubris.

> You are welcome to Rust, given the caliber of many programmers today, I can
> see the value.  I took a different approach, we hired excellent programmers
> and our stuff worked.

I have every confidence that the team was stellar, that it did work,
and beyond that that it worked very, very well.

That said, there is a tendency on this list to comment on the "caliber
of many programmers today", and not in a good way. I would invite
people who do that to perhaps take a moment to consider their
preconceptions, and to reflect on whether things are really as
different now as they were back then, and to the extent that they are,
ask what has actually changed?

Perhaps it's less that the kids these days are lacking the intrinsic
motivation, focus, and intestinal fortitude to competently program in
C, but that they're doing so in an environment that is actively
hostile to them, and is far, far more complex than it was 30 years
ago. The blunt reality is that the C of today is not the C of your (or
even my: I have no brown left in my hair; this color is silver, thank
you very much) youth. Anyway, all I'm really saying is that maybe,
just maybe, the folks in the trenches have a perspective worth more
than I often see it given credit for.

        - Dan C.


More information about the TUHS mailing list