Live data from Hacker News

Deconstructing "K&R C"

c.learncodethehardway.org

71–80 of 136 posts

Re: Deconstructing "K&R C"

#71
post #49

Earlier quoted context omitted.

The built-in "strcpy" function has the exact same limitation. Does the author have a problem with it as well? Yes. From the linked chapter: we avoided classic style C strings in this book From an earlier chapter on strings: The source of almost all bugs in C come from forgetting to have enough space, or forgetting to put a '\0' at the end of a string. In fact it's so common and hard to get right that the majority of…

I didn't see it yet from a quick skim of the available chapters, but I'm going to guess that his preferred alternative is 'bstr - The Better String Library' - http://bstring.sourceforge.net/ I've used it the past, and I try to include it in any project that isn't immediately trivial, although the to/from integration with just about all library code ever is a bit of a hassle.

I use bstring but there's a few others. Generally it's the easiest way to avoid some common buffer overflows and other problems.

Re: Deconstructing "K&R C"

#72
post #52
post #49

Earlier quoted context omitted.

I didn't see it yet from a quick skim of the available chapters, but I'm going to guess that his preferred alternative is 'bstr - The Better String Library' - http://bstring.sourceforge.net/ I've used it the past, and I try to include it in any project that isn't immediately trivial, although the to/from integration with just about all library code ever is a bit of a hassle.

It's not just that the to/from is a hassle, it's also that you have to deeply understand the gotchas of ASCIIZ strings to safely do that bridging at all --- so pretending it doesn't exist is probably not a good teaching strategy. (I have no opinion about the article and am only commenting on this thread because I like C).

I do not pretend anything about null-terminated strings in the book. In fact, I have many exercises and assignments where they use Valgrind to buffer overflow C strings repeatedly and don't introduce bstring until much later.

Re: Deconstructing "K&R C"

#73

Earlier quoted context omitted.

"the majority of good C code just doesn't use C style strings..." Nice. In the 23 years I have worked on C language products, I've never worked on "good C code" by this definition. The cool thing about this guys book, I guess, is that by avoiding all the things about the language he doesn't like, any reader will be wholly unprepared for C in the Real World after this book.

This chapter is explicitly teaching people what the author's idea of bad C code is: It has them read some, then tells them specifically what the gotchas are, then asks them to code up test cases for the flaws and run them through Valgrind. Where's the "avoiding" here? And which of the skills being exercised - imagining what kinds of bad things could happen, writing executable test cases, detecting segfaults - are not…

That's basically the point of this chapter. It's getting people to think like a hacker and try to break the code in unintended ways. That makes them better programmers and helps when avoiding common mistakes in C code.

Using K&R to do this is to give people a set of known good C code samples and show how even those can be broken and misused.

Re: Deconstructing "K&R C"

#74
post #13
post #9

I don't see what the big deal is here. He throws inputs at a function not meant to handle them and gets a segfault. Isn't this more-or-less expected from all C functions? On careful examination of his example code, you can see that there's no attempt to terminate the buffer (though he misidentifies it as an "off by one" error). Throwing arbitrary buffers into functions meant for null-terminate strings will cause erro…

Agreed, the example used seems very strange. Every function makes functions about it's parameters and in C null terminated string are to be assumed unless otherwise noted. The std library strcpy would just behave in an identical way. Yeah, I'm all about checking your assumptions and defensive programming but k&r is hardly as fault because you throw garbage at a random function and it segfaults. I find the idea of tea…

You should go read about fuzzing. It's amazing what throwing "random garbage" at programs can break.

Re: Deconstructing "K&R C"

#75

This is just the first section of the chapter, right? It seems a little premature to be distributing or discussing it here.

Good point. But that's the most inspiring approach I can remember ever seeing in such a book. If only all of my technical books were written with such a mindset.

Thanks, I do like breaking things.

Re: Deconstructing "K&R C"

#76

Kind-of a long-winded way to point out the (very well known) fact that passing non-terminated strings to functions that expect terminated strings is fraught with danger, isn't it?

Nope, and what I'm actually doing is fuzzing the input to this function, which is a common breaking technique.

You see, programmers tend to go around only using functions exactly as they were intended. Hackers come along and then use them in unintended ways, which causes bugs. The way to prevent this is to think like a hacker and try to use your code in unintended ways and then try to prevent them.

Re: Deconstructing "K&R C"

#77

> Braces Are Free, Use Them I disagree. Braces have a cognitive load, particularly if they're given whole lines to themselves. Which is easier to read, while ((len = getline(line, MAXLINE)) > 0) if (len > max) { max = len; copy(longest, line); } if (max > 0) /* there was a line */ printf("%s", longest); or while ((len = getline(line, MAXLINE)) > 0) { if (len > max) { max = len; copy(longest, line); } } if (max > 0) /…

I'll take the 2nd one, please. And twice on Sunday.

Re: Deconstructing "K&R C"

#78

> Braces Are Free, Use Them I disagree. Braces have a cognitive load, particularly if they're given whole lines to themselves. Which is easier to read, while ((len = getline(line, MAXLINE)) > 0) if (len > max) { max = len; copy(longest, line); } if (max > 0) /* there was a line */ printf("%s", longest); or while ((len = getline(line, MAXLINE)) > 0) { if (len > max) { max = len; copy(longest, line); } } if (max > 0) /…

I'm probably the last person in the world to prefer: while ((len = getline(line, MAXLINE)) > 0) if (len > max) { max = len; copy(longest, line); } if (max > 0) /* there was a line */ printf("%s", longest); I fear this may be literally true: this brace style is called Whitesmith's, and I was reporting bugs to the cc-mode indenter for emacs a while ago. BSD/Allman and K&R styles never made sense to me.

Add a new statement to the while-loop. Now you've figured out why that style isn't so hot. You now have to remember to go add the new braces, and typically people are mentally putting them in so they forget. Same with the last if-statement. You'll go, add the new line, indent and go "cool done". Then scratch your head for hours wondering why it's not working.

Re: Deconstructing "K&R C"

#79
post #53

Earlier quoted context omitted.

"Yes, there are problems with the whole approach of using a terminating value" And, of course, there are problems with the other approaches too. Using a single length byte at the beginning limits you to 255 characters and makes pointer manipulation less straightforward (since the actual data starts one byte further on). Using more than one byte for the string length wastes space (a serious issue at the time C was dev…

It's way worse than an extra byte, or the offset of 1 byte for pointers; it also means you need a whole copy of every substring with its own length delimiter, and can't tokenize in place. C code gets into just as much trouble with length-delimited data structures as it does with ASCIIZ; ASCIIZ is a red herring. People have declared over and over again that it's the single worst decision in C and the cause of every bu…

I partially agree with you, but in a different way. I feel that the real problem is the OS doesn't give code access to its own internal accounting of allocated memory. It already knows the size of any heap chunk you make, so why can't we ask it? In most C code we're carrying around either a null terminator (which can get clobbered) or a whole integer for the size.

Instead, there should be a way to ask the OS "how big is the crap this pointer is pointed at" and get a valid answer. Other useful things would be "how far inside the chunk pointed at by X is the pointer Y?" Or, "will pointing Y at J inside X cause an error?"

And it wouldn't even need to be the OS, just the allocator, probably a few macros, etc. But, for now I have to show people how to write bug resistant C code so this is the best way so far.

Re: Deconstructing "K&R C"

#80
post #8

I'm confused. What is the "defect" in K&R's "copy(char to[], char from[])" function? The author notes that "the second this function is called...without a trailing '\0' character, then you'll hit difficult to debug errors", but no function with that signature could possibly work in this case. The built-in "strcpy" function has the exact same limitation. Does the author have a problem with it as well? Null-termination…

It's a nice strawman, right? Especially when he points out that the original code, in context, is perfectly fine. His later complaint about the assignment-in-if statement is certainly something shared by modern C programmers (see compiler warnings about same), but it perfectly fits the original style and accomplishes its task. His criticisms seem to be rooted so far in stylistic issues and in taking the code out of c…

My criticisms are only partially stylistic, but also that people copy this code to other situations and it breaks. So, I'm showing them why it only works in that one specific context and how to break the code.
Post reply on HN