Comment by alexfoo

1 day ago

Yet software developed in C, with all of the foibles of its string routines, has been sold and running for years with trillions of USD is total sales.

A library that records how much memory is allocated to a string along with the pointer isn't a necessity.

Most people who write in C professionally are completely used to it although the footgun is (and all of the others are) always there lurking.

You'd generally just see code like this:-

    char hostname[20];
    ...
    strncpy( hostname, input, 20 );
    hostname[19]=0;

The problem obviously comes if you forget the line to NUL that last byte AND you have a input that is greater than 19 characters long.

(It's also very easy to get this wrong, I almost wrote `hostname[20]=0;` first time round.)

I remember debugging a problem 20+ years ago on a customer site with some software that used Sybase Open/Server that was crashing on startup. The underlying TDS communications protocol (https://www.freetds.org/tds.html) had a fixed 30 byte field for the hostname and the customer had a particularly long FQDN that was being copied in without any checks on its length. An easy fix once identified.

Back then though the consequences of a buffer overrun were usually just a mild annoyance like a random crash or something like the Morris worm. Nowadays such a buffer overrun is deadly serious as it can easily lead to data exfiltration, an RCE and/or a complete compromise.

Heartbleed and Mongobleed had nothing to do with C string functions. They were both caused by trusting user supplied payload lengths. (C string functions are still a huge source of problems though.)

> Yet software developed in C, with all of the foibles of its string routines, has been sold and running for years with trillions of USD is total sales.

This doesn't seem very relevant. The same can be said of countless other bad APIs: see years of bad PHP, tons of memory safety bugs in C, and things that have surely led to significant sums of money lost.

> It's also very easy to get this wrong, I almost wrote `hostname[20]=0;` first time round.

Why would you do this separately every single time, then?

The problem with bad APIs is that even the best programmers will occasionally make a mistake, and you should use interfaces (or...languages!) that prevent it from happening in the first place.

The fact we've gotten as far as we have with C does not mean this is a defensible API.

  • Sure, the post I was replying to made it sound like it's a surprise that anything written in C could ever have been a success.

    Not many people starting a new project (commercial or otherwise) are likely to start with C, for very good reason. I'd have to have a very compelling reason to do so, as you say there are plenty of more suitable alternatives. Years ago many of the third party libraries available only had C style ABIs and calling these from other languages was clumsy and convoluted (and would often require implementing cstring style strings in another language).

    > Why would you do this separately every single time, then?

    It was just an illustration or what people used to do. The "set the trailing NUL byte after a strncpy() call" just became a thing lots of people did and lots of people looked for in code reviews - I've even seen automated checks. It was in a similar bucket to "stuff is allocated, let me make sure it is freed in every code path so there aren't any memory leaks", etc.

    Many others would have written their own function like `curlx_strcopy()` in the original article, it's not a novel concept to write your own function to implement a better version of an API.

I learned C in about 1989/1990 and have used it a lot since then. I have worked on a fair amount of rotten commercial C code, sold at a high price, in which every millimeter of extra functionality was bought with sweat and blood. I once spent a month finding a memory corruption issue that happened every 2 weeks with a completely different stack trace which, in the end, required a 1-line fix.

The effort was usually out of proportion with the achievement.

I crashed my own computer a lot before I got Linux. Do you remember far pointers? :-( In those days millions of dollars were made by operating systems without memory protection that couldn't address more than 640k of memory. One accepted that programs sometimes crashed the whole computer - about once a week on average.

Despite considering myself an acceptable programmer I still make mistakes in C quite easily and I use valgrind or the sanitizers quite heavily to save myself from them. I think the proliferation of other languages is the result of all this.

In spite of this I find C elegant and I think 90% of my errors are in string handling so therefore if it had a decent string handling library it would be enormously better. I don't really think pure ASCIIZ strings are so marvelous or so fast that we have to accept their bullshit.

  • > I learned C in about 1989/1990 and have used it a lot since then. I have worked on a fair amount of rotten commercial C code, sold at a high price, in which every millimeter of extra functionality was bought with sweat and blood. I once spent a month finding a memory corruption issue that happened every 2 weeks with a completely different stack trace which, in the end, required a 1-line fix.

    That sums up one of my old roles where this kind of thing accounted for about 10% of my time over a 10 year period.

    Heisenbug, mutating stack traces, weeks between occurrences, 1 line fix, do some other interesting work before the next weird thing comes along.

    I think the longest running one I had (several years) was some weird interaction between pthread_cond_wait() and pthread_cond_broadcast(). Ugh.

> The underlying TDS communications protocol (https://www.freetds.org/tds.html) had a fixed 30 byte field for the hostname and the customer had a particularly long FQDN that was being copied in without any checks on its length. An easy fix once identified.

I had to file a bug with a vendor because their hostname handling had a similar issue: I think it was 64 max.

There was some pushback about if it was "really" a problem, so I ended up quoting the relevant RFCs to argue that they were not compliant with Internet standards, and eventually they fixed the issue.

> Yet software developed in C, with all of the foibles of its string routines, has been sold and running for years with trillions of USD is total sales.

Even with the premise that sales of software is a good metric for analyzing design of the language (which I think is arguable at best), we don't know that even more money might have been made with better strings in C. You coming justify pretty much anything with that argument. MongoDB (which indicentally is on C++ and presumably makes plenty of use of std::string) made millions of dollars despite having the bug you mention, so why bother fixing it?

  • That wasn't really the point I was making.

    It was more a response to the OP's comment of:

    > I've always wondered at the motivatons of the various string routines in C - every one of them seems to have some huge caveat which makes them useless.

    Which, to me, sounded like it was a surprise that anything written in C could be a success at all given that something as basic as the string handling (which is pretty fundamental) is bordering on useless.

    As I put in my other comment, there were plenty of reasons way back in the 80s/90s why C was chosen for a lot of software, and hardly any (if any at all) of those reasons remain nowadays.

    > MongoDB (which indicentally is on C++ and presumably makes plenty of use of std::string) made millions of dollars despite having the bug you mention, so why bother fixing it?

    Again, that's not the point I was making, no-one said anything about not fixing something because of how much money it has made.

    All it comes down to is that a lot of very successful software is very shoddily written, in a variety of languages, not just notoriously memory-unsafe languages like C. Well written software, or software written in a "better" language, might have a better chance of "succeeding" (whatever that means), but that doesn't mean that awful software can't succeed.

    • >> I've always wondered at the motivatons of the various string routines in C - every one of them seems to have some huge caveat which makes them useless.

      > Which, to me, sounded like it was a surprise that anything written in C could be a success at all given that something as basic as the string handling (which is pretty fundamental) is bordering on useless.

      I guess to me that seems like pretty big logical leap. It seems equally plausible that they consider C successful and not going anywhere, so they care about improving the way strings are handled (and therefore gave an example of something they would consider better). Your response seems to be trying to defend against an implication that wasn't apparent in what you were responding to, so it wasn't clear at all to me what point you were trying to make.

>>(It's also very easy to get this wrong, I almost wrote `hostname[20]=0;` first time round.)

Impossible to get wrong with a modern compiler that will warn you on that or LSP that will scream the moment you type ; and hit enter/esc.