Live data from Hacker News

Deconstructing "K&R C"

c.learncodethehardway.org

61–70 of 136 posts

Re: Deconstructing "K&R C"

#61
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…

> but no function with that signature could possibly work in this case.

This is the source of the bugs in C. People write functions that only work given all calls to them are never changed, which is absurd. Good modern C code involves trying to protect against bad usage and adding defensive checks.

So yes, the built-in strcpy is crap which is why most competent C doesn't use it except in a few rare cases where it's required.

And this does demonstrate actual bugs in the code. I wrote a test case that causes it, which incidentally is a common bug in C code called a buffer overflow. It's because of code examples like this that get copied to other situations that we have these defects.

Re: Deconstructing "K&R C"

#62
To be honest, I was never that impressed with the K&R book as an introduction. Coming from a higher level language (Pascal) in college after several years back down to C was painful. K&R (borrowed from a classmate) presumed too much obviousness in what assembly language constructs were being abbreviated by a given piece of C code, and what the other pieces of C code around the example to be explained did.

Later in the semester I picked up a copy of the first edition of this book:

http://books.google.com/books/about/C_an_advanced_introducti...

This book did a much better job of explaining what the hell was going on, particularly in regards to managing memory / strings / arrays / (C) pointers and understanding their placement.

Sure, Pascal had pointers, when you asked for them :-)

Yeah, throw the K&R book at newbs you hate.

Re: Deconstructing "K&R C"

#63

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…

"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.

Yes, they'll be pretty good at C unlike you because they'll read the whole book instead of just this one half-finished chapter.

Re: Deconstructing "K&R C"

#64
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…

The inputs I'm throwing at it are a common problem mistake in C programming which demonstrates a buffer overflow. K&R's code assumes that it will only be used in each program they've written, but it usually get copied out into other software and that causes the bugs. As I said, the programs are correct, the functions are not.

And no, most of the clever convoluted code in K&R is antiquated and the only reason it's a common C idiom is because nobody questions whether it's good style. It's more of a habit than an idiom.

Re: Deconstructing "K&R C"

#65

> 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) /…

> Braces have a cognitive load, particularly if they're given whole lines to themselves. Which is easier to read,

Checking braces has a higher load when they aren't there and when they aren't consistently used. But, without evidence both of our points are pointless. So, in my book I'm pushing the standards of always use braces except in a few little cases.

Re: Deconstructing "K&R C"

#66
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…

Huh? My C programming is in the distant past, so I might be forgetting. But strcpy does assume a terminal zero, doesn't it? E.g., http://linux.die.net/man/3/strcpy . It sounds like you are talking about strncpy or memcpy.

Yes, strcpy is almost universally understood as a security problem. In fact, here's a nice regex to apply to some C code to find buffer overflows:

LC_ALL=C egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|r?index[^.]|a?sn?printf|byte_)' src/*.c

Taken from the really well researched and secure andhttpd:

http://www.and.org/and-httpd/#secure

Run that regex on some C code, then go look at how the inputs to those functions are used, and then you can probably create some of your own buffer overflows. It's like magic.

Re: Deconstructing "K&R C"

#67

I don't see his point, really. Yes, C doesn't have a statically testable string type. And yes, the convention is that a C "string" is just an array of character data with a trailing NUL-Byte. He constructs an array without a trailing NUL-Byte - so that's not a string, but an array of characters. The fact that copy() now happily runs through memory is the expected result of the bug in the calling code. No, it's not us…

> I don't see his point, really.

The point is three fold:

1. K&R has defects in it when the functions in it are used out of context because they didn't include defensive programming practices considered standard today.

2. People can learn a lot about writing good code by critiquing other code, even from masters, so I'm taking them through doing that.

3. There should be no sacred cows, and people hold K&R on a pedestal without questioning what's in it. This is really what causes #1, so I have them do #2.

That's it really.

Re: Deconstructing "K&R C"

#68

> 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.

Steve McConnell makes a pretty good case for Whitesmith's formatting in this book (at least the first edition) in the code formatting chapter:

http://books.google.com/books/about/Code_complete.html?id=Qn...

Of course, he presents most of the major styles, pretending to be "fair and balanced", but if you read between the lines of the "abstract block" argument, it's clear that the other styles which align keywords or grouping symbols at a different level other than the compound statements they delimit are brain damaged, or at least visually misleading.

Re: Deconstructing "K&R C"

#69
post #57

The function copy expects a C style string but he pass a buffer to some data. If you pass it the proper argument you'll get a proper result, it's that simple. I see the complaint is more about C style strings in general because it's easy to corrupt them by overwriting NULL at the end rather than a complaint about "K&R C" book. I don't get why he decided to put it under this title.

The problem is in the word "expects". This function expects certain things but doesn't assert that they're happening. Because of this you get bugs when you try to use that function in other code, which is what beginners do.

And yes, the solution is to require a size with every string buffer, which is what I do nearly all the time now. But, the best way to learn why that's solution is to try to hack something with this kind of defect.

Re: Deconstructing "K&R C"

#70
post #50

"Before the switch to heap memory, this program probably ran just fine because the stack allocated memory will probably have a '\0' character at the end on accident." Stack memory is not preinitialized to '0' either so using stack memory would show this 'defect' as well (as others have pointed out this is a defect in the calling code, not in copy).

I think that depends on compiler, although it's been a while since I've done C, so I might be wrong.

It's fairly vague in the standard, but most of the time this is what happens so nobody hits the bug. Also, many OS are notorious for being loose with the stack and strict on the heap for various reasons.
Post reply on HN