Live data from Hacker News

C Strings and my slow descent to madness

deusinmachina.net

281–290 of 329 posts

Re: C Strings and my slow descent to madness

#281

Earlier quoted context omitted.

> You can printf non-null terminated strings too. Check printf("%. s", length, strptr).* I haven't checked yet, but I'm about 90% confident that's UB. Is printf() guaranteed not to read to the end of the string when you give it a length?

Yes, it is. From the C11 spec: > Characters from the array are written up to (but not including) the terminating null character. If the precision is specified, no more than that many bytes are written. If the precision is not specified or is greater than the size of the array, the array shall contain a null character.

Thanks! I guess I didn't realize expressio unius est exclusio alterius applies in the C standard :D

Re: C Strings and my slow descent to madness

#282

Earlier quoted context omitted.

no, because the size argument is only an upper bound on how many bytes can be written into the destination. snprintf (huge_buf, huge_buffer_size, "%d", 1); will write two bytes into huge_buf, regardless of huge_buffer_size (assuming it is 2 or larger).

It’s in the other direction, snprintf(small_buf, small_size, “%s”, huge_string) will need to iterate the whole string.

why? snprintf() will just write as many bytes from huge_string as necessary, up to the smaller of small_size and strlen (huge_string).

what makes you believe it will iterate the whole of huge_string?

Re: C Strings and my slow descent to madness

#283

Pop quiz, which of these is safe, given "char buf[80]" and arbitrary user input in argv[1]? gets(buf); scanf("%s", buf); strcpy(buf, argv[1]); scanf("%80s", buf); strncpy(buf, argv[1], 80); snprintf(buf, 80, argv[1]); ---- The delightful answer is none of them . The first three have no bounds checking at all, meaning that they will happily overflow the buffer to an arbitrary extent (gets, at least, will usually trigg…

snprintf(buf, 80, “%s”, argv[1]); Should work.

As long as you replace the 'smart'-quotes with actual quotes.

-Emily

Re: C Strings and my slow descent to madness

#284

Pop quiz, which of these is safe, given "char buf[80]" and arbitrary user input in argv[1]? gets(buf); scanf("%s", buf); strcpy(buf, argv[1]); scanf("%80s", buf); strncpy(buf, argv[1], 80); snprintf(buf, 80, argv[1]); ---- The delightful answer is none of them . The first three have no bounds checking at all, meaning that they will happily overflow the buffer to an arbitrary extent (gets, at least, will usually trigg…

Dude, your last one is not even the correct way of calling snprintf, what the hell are you talking about?

I mean, none of these are correct. But they will all compile, often with no warnings at all. The format string doesn’t need to be a literal string: this is useful for situations like localization.

Re: C Strings and my slow descent to madness

#285

Pop quiz, which of these is safe, given "char buf[80]" and arbitrary user input in argv[1]? gets(buf); scanf("%s", buf); strcpy(buf, argv[1]); scanf("%80s", buf); strncpy(buf, argv[1], 80); snprintf(buf, 80, argv[1]); ---- The delightful answer is none of them . The first three have no bounds checking at all, meaning that they will happily overflow the buffer to an arbitrary extent (gets, at least, will usually trigg…

Dude, your last one is not even the correct way of calling snprintf, what the hell are you talking about?

No surprise that this completely unjustified vitriolic reaction comes from someone arguing about C.

Re: C Strings and my slow descent to madness

#286
post #275

Earlier quoted context omitted.

You are right, sizeof is the other big difference. I think these differences are small enough that it was a mistake separate the two. The similarities / differences do make them confusing.

How would you express a 2D memory layout with only pointers?

An array of pointers to arrays? Basically, a `T**` C#'s "jagged" arrays are like this, and to get a "true" 2D array, you use different syntax (a comma in the indexer):

    int[][] jagged; // an array of `int[]` (i.e. each element is a pointer to a `int[]`)
    int[,] multidimensional; // a "true" 2D array laid out in memory sequentially

    // allocate the jagged array; each `int[]` will be null until allocated separately
    jagged = new int[][10];
    Debug.Assert(jagged.All(elem => elem == null));
    for (int i = 0; i 

Re: C Strings and my slow descent to madness

#287

Pop quiz, which of these is safe, given "char buf[80]" and arbitrary user input in argv[1]? gets(buf); scanf("%s", buf); strcpy(buf, argv[1]); scanf("%80s", buf); strncpy(buf, argv[1], 80); snprintf(buf, 80, argv[1]); ---- The delightful answer is none of them . The first three have no bounds checking at all, meaning that they will happily overflow the buffer to an arbitrary extent (gets, at least, will usually trigg…

> The delightful answer is none of them. No. Sorry. This is bad programming. C'mon. I started programming back in the 8080, 8085, 6502, etc. days. I had to program some prototype computers using a hex keypad while entering raw machine code (not even assembler). I still own a couple of these: https://i.imgur.com/ZsIJj1p.png In a couple of cases I had to take this approach to bootstrap Forth on a 6502, then write a ful…

God, this attitude reeeallllyy grinds my gears.

This is precisely why C has outstayed its welcome in so many areas of software development.

Every time some kid looking for a self-confidence boost buys into the idea that using a language with a minefield of archaically-named string manipulation functions somehow makes them a ‘real’, ‘smart’, developer, we are all left a little worse off.

No, it’s not the fault of the language’s design. It’s not even the fault of history - the fact that C was conceived at a time when security wasn’t what it is. It’s these damn kids that only know Python and JavaScript! Why can’t they be as smart as us C developers!

This is all completely ignoring the fact that in 2023 we have no shortage of string manipulation-related vulnerabilities in widely popular and supposedly battle-tested C code. All some version of the typical list completely justifiable human errors that anyone is bound to make writing C.

A language that is so popular but that so few people seem to be able to write secure code with, is not a very good language.

I’m immediately skeptical of anyone that’s not of the view that the single best thing we as an industry can do for security is to drastically reduce the amount of C code in circulation. It always comes down to “I’m set in my ways and I think I’m superhuman”.

My hope is that these modern, sensible systems programming languages successfully eat the world faster than the pool of C developers thins out, as people slowly retire, and more greenhorns clue into the fact that C is being used in more places than it ought to be.

Signed, someone that did learn C in school, and has written it professionally.

Re: C Strings and my slow descent to madness

#288

It's important to mention that strncpy (and also strncpy_s) are really not a strcpy replacement, it's not intended for the same usages. The name is a total misnomer. Do not use strncpy that way! In any case, strcpy_s (which is a good replacement for strcpy) is part of the C11 standard. I'm confused how that isn't considered portable.

Yeah, I was a little confused by the strncpy "gotcha": "The answer is that the destination gets filled with all the characters of the source string with no room left for the null terminator."

Well, I mean, the docs specifically call that out: "If src is less than len characters long, the remainder of dst is filled with ‘\0’ characters. Otherwise, dst is not terminated."

So if you want null termination in all cases, you need to pass len-1, not len.

Re: C Strings and my slow descent to madness

#289

This is from a C fan: If you are going to do any string heavy work, please use anything else than C (Python is pretty nice for this sort of stuff for instance). And if you need to use C anyway, then please use anything else than the string functions from the standard library. The C stdlib is (mostly) a leftover from the K&R era when opinions about what makes a good API were very different from today, and C was a much…

As a newcomer to C, why is it that the C standard library doesn't get updated? Newer languages seem to place a lot of emphasis on getting their standard libraries as useful as possible. It's odd to be told not to use the standard library functions but to write my own instead. I'm really doubting I can just sit down and hammer out string functions superior to string.h.

Just my guess: C doesn't depend as much on its standard library as other languages (which has its good and bad sides), and this also means that fixing the standard library isn't very high on the priority list of the C committee, because everybody knows that for any serious work the stdlib isn't suitable anyway.

The C stdlib is basically the lowest common denominator which enables writing very simple UNIX-style mostly-cross-platform command line tools, but not much else. For anything serious you either call OS API functions directly, or resort to specialized third-party libs.

Attempting to 'fix' the stdlib would first mean agreement on what such a stdlib should actually contain and look like, and this has a real risk of ending up in C++ Commitee style busywork (e.g. lots of activity with little to show for).

Re: C Strings and my slow descent to madness

#290

Earlier quoted context omitted.

Maybe you could summarize this by saying that C strings are "strings of bytes", not "strings of characters".

It's better to say that, in C, characters are bytes. That's why coming at this from the modern perspective of "characters are the things on my screen" is always going to confuse you - C doesn't have bytes, only characters. C programmers (should) understand this the same way Lisp programmers understand that "CAR" and "CDR" refer to "first" and "rest" or Forth programmers understand that "the stack" is the data stack a…

So a "char" is a byte, but a "char" is perhaps not a "character", except as a funny coincidence of jargon.
Post reply on HN