"I am reasonably certain that the only reason (today) that everyone uses Windows is because everyone uses Windows."
I'm reasonably certain that you're wrong.
Personally I use windows because I choose to. Why? Better hardware support, apps I don't want to do without and the occasional game.
This is because everyone uses Windows. Companies and software developers tend to focus their attention on the larger population of consumers/users. Few people use Linux as their desktop OS, therefore fewer desktop programs are available on Linux, and those that are available on Linux are generally less "polished". For most major efforts aimed at the desktop user, Windows compatibility is priorty #1, because that's where the users are.
Unfortunately, it's a vicious cycle. If the OS has more apps and better support, then it will probably draw more users. More users means more attention from the software suppliers, yielding more apps and better support, and so forth and so on.
If Microsoft even starts to contemplate charging royalties on every single program that people write and distribute for the operating system, I can bet we'll see one of the largest shifts to Linux development in history.
You're absolutely right. Unfortunately, this would only happen if Microsoft enlisted a team of chimpanzees to make its corporate decisions.
I'm not sure what your definition of "knowing the language" is. If someone asked me to rate my C++ skills from 1 to 10, I would give myself a 4 or a 5. Anyone that rates themselves a 7 or higher is either named Sutter, Alexandrescu, Glassborow, or Stroustroup. Or is either grossly unfamiliar with the scope of C++ or flat out lying.
Wow, you're allocating the top 40% of the scale to less than 1% of the C++ programmer population? Don't you think that's a bit extreme? Those guys are all 10s, IMHO. What good is a scale from 1-10 if interviewees can only use the lower 1-6?
The point is that the format of the test aids in the streaming of the Perl 6 syntax, thus improving the programmer's experience when he/she is using "exception-handling"-like development in the customary fashion and enabling him/her to use OO-style methodologies in a RAD-enabled, but somewhat I/O-bound, manner.
An unlocked door is safe until someone sees you lock it. Therefore everybody just leave all your door unlocked, since we do not know that they're unlocked there is no danger.
A better analogy: It's more likely that a robber will be able to break into your home if he heard you explain how the lock on your door doesn't work terribly well. This sounds more reasonable, and is more like the point he was trying to make.
Re:Change one thing at a time
on
Debugging
·
· Score: 3, Insightful
I particularly liked the rule about "Quit thinking and look". I worked with a guy who used what I call the "Zen method of debugging". He would keep staring at the code, trying to determine what was going on. I, on the other hand, would throw in some print statements so I could see what was going on.
Sometimes reading the code is enough. If you're good at reading code, then sometimes all you have to do is briefly look over what you wrote to spot the bug. YMMV, of course. If you've looked at the code for a few minutes and nothing looks obviously wrong, then it's probably time to use the debugger/add print statements. I've found that this is the most efficient way to go bug-hunting, because a quick re-read can find a lot of the "easy" bugs. This is similar to having a code review, but in this case you, the author, are the only reviewer. If there is another coder nearby, go ahead and ask him/her to give it a quick look as well, because he/she will probably have an easier time spotting the error.
I've met people who skip this step, and it drives me up the wall to see them waste their time (sometimes hours!) poking around in a debugger/writing print statements when the code they are debugging is simple. If it's a small, straightforward bit of code, then a quick look should uncover the bug. I suppose this falls under rule #1 (understand the system), but my point is more specific: understand the code.
None of the above is particularly groundbreaking, of course, and probably doesn't deserve to be mentioned in the book. These are more like "things you do before debugging".
"Basically, the information goes into government, and that's the dead end," says Sean Moulton, a senior policy analyst at OMB Watch. "Aside from encouraging the companies to do something, as far as my reading of the statute, they don't have much authority at all, and they can't warn the public."
(Setting: the school playground where government and corporations play) Government: I can keep a secret. Tell me all your nasty mistakes and I won't tell anyone. Company: Ok, but you have to promise that you won't tell Joe Consumer! Pinky swear!
This seems a tad scary to me. I'd prefer to have the government require that all companies must disclose information about vulnerabilities to the public. After all, aren't other companies outside of IT required to do this? How many times have we read about lawsuits where the public discovered that X company (tobacco, automobile, or otherwise) refused to disclose information about the hazards of their products to the public?
Jack: A new car built by my company leaves somewhere travelling at 60 mph. The rear differential locks up. The car crashes and burns with everyone trapped inside. Now: should we initiate a recall? Take the number of vehicles in the field, A, multiply by the probable rate of failure, B, multiply by the average out-of-court settlement, C. A times B times C equals X. If X is less than the cost of a recall, we don't do one.
Single Serving Friend: Are there a lot of these kinds of accidents?
Jack: You wouldn't believe.
Single Serving Friend: Which car company do you work for?
Jack: A major one.
For those who don't recognize this bit of dialog: this is from the movie "Fight Club". It's a great movie, but the quote is almost entirely unrelated to the main plot of the film.
To produce bugless software we need to start with software designs that are provably correct and then produce code that is provably in line with the design. Using more objects that more closely model the "real world" is an invitation to producing larger number of bugs as the ambiguity of the real world infects the design and implementation of the program.
You're absolutely right. Some people think that turning to the "real world" for guidance a good idea, but I've found that it only confuses things. Nobody knows how to model real-world objects and relationships inside a computer in a way that suits all potential uses of that model. I've found that most discussions about software models for the real world in OO projects tend to degrade into analyzing the structure of various English sentences and considering the plethora of ways that a person _could_ understand a relationship. If there are tons of ways to represent the real world, how is the real world supposed to help produce bug-free software? Why should I believe that the answer lies in the real world instead of the software development process itself?
Re:Nice language, bad motives
on
How C# Was Made
·
· Score: 1
C# is just a language, it doesn't lock you into Windows at all. Mono supports the entire C# language.
I seriously doubt this. Unless C# remains unchanged for many years, Mono will always have to play catch-up to C# and the.NET framework. It may work as a poor man's version of.NET, but let's not kid ourselves by implying that it is a full-fledged portable replacement for Microsoft's implementation.
It's the classes you choose to use that lock you onto a specific platform. You can't blame C# if people want to use classes that aren't available on other platforms.
And does Microsoft document all of the classes that are not supported on other platforms? Are they at at least attempting to make their framework portable? Why should they? Unlike Sun, they are not striving to produce a spec for a complete solution (with tons of libraries) that other companies can implement on other platforms. They want you to use Windows and other MS products, plain and simple.
Its like saying that C++ sucks because DirectX doesn't work on Linux.
This is more accurate, IMHO:
Saying that.NET sucks on linux is like saying that C++ sucks because DirectX doesn't work on Linux.
The difference is that DirectX is a documented windows-only API, whereas.NET is an MS-specific framework masquerading as a "portable" solution. Don't buy into the "potential for portability" hype, especially if you're focusing mostly on the incomplete Mono implementation.
As a video game developer, I've been involved in many "code upgrades", as well as rewrites. As long as the rewrite is being done by people who wrote the original code...
(emphasis mine)
Excellent point. That eliminates the "NIH rewrite", which is usually caused by programmer hubris. Sometimes maintenance programmers rewrite code for the sake of "clarity", when in actuality they are falling prey to their own pride. Of course, the end product looks clearer to them, but that's probably because they wrote it. It may or may not be clearer in an objective sense, and it might contain more bugs.
Excellent rewrite. I found this post to be much clearer and more concise than the original article, while still maintaining the same message. I'm now convinced that rewrites can be A Good Thing.
I thought Heller's "mistake" was defensible even if you don't agree with it. Heller's goal was to provide a string class that would be usable and not too confusing for beginners. I don't think there is any perfect solution to the problem he was trying to solve.
I didn't get the impression that he realized that his class was a poor design decision. If he realized this, then that's good. Even so, I don't see how a beginner could be confused by string utility functions. Functions are (arguably) simpler than classes.
I've been preaching this song for the better part of 20 years. But people got very keen on putting everything in classes and hierarchies. I've seen the Date problem solved by having a base class Date with some operations on it and the data protected, with utility functions provided by deriving a new class and adding the utility functions. You get really messy systems like that, and there's no reason for having the utility functions in derived classes. You want the utility functions to the side so you can combine them freely. How else to I get your utility functions and my utility functions also? The utility functions you wrote are independent from the ones I wrote, and so they should be independent in the code. If I derive from class Date, and you derive from class Date, a third person won't be able to easily use both of our utility functions, because we have built dependencies in that didn't need to be there. So you can overdo this class hierarchy stuff.
Bjarne talks about this problem a little in his book (TC++PL), but I'm glad that he mentioned it here. Putting utility functions in derived classes is a mistake that is made far too often. How many times have you seen someone write something like this:
class MyString : public std::string { public: size_type find_no_case(const char *subStr) const;//... };
Stop it! That should be a free-standing function. There is absolutely no benefit to using inheritance in the above code. The only thing it yields is a warm fuzzy feeling from using member functions instead of free-standing functions. Some coders just enjoy writing
MyString s("foobar"); i = s.find_no_case("foo");
instead of
std::string s("foobar"); i = find_no_case(s,"foo");
because it "feels right", even though it limits the reusability of the function. C++ programmers, please take note. It is a mistake that even book authors like Steve Heller make (Link)
This is something that novice programmers are well advised to listen to. I constantly am asked by junior programmers 'What happens when I do x', where x is something simple, like try to print out an array.
Half the time, the problem can be answered by simply trying it. And the other half of the time, you end up with a better question...
Unfortunately, C++ is complex, and undefined behavior will upset most attempts at experimentation. For example, suppose a beginning C++ programmer wants to change a string's contents so it contains the text "Count is $count" (Perl-ish code). Most of the time they try stuff like:
int count =...; string s =...; sprintf( &s[0], "Count is %d", count ); sprintf( (char*)s.c_str(), "Count is %d", count );
Does that work? Well, maybe, but the code's not guaranteed to work, and it's dangerous. But the problems with the code will not be recognized by the beginner, and therefore experimentation can lead him to assume something is correct even when it is not. The generally accepted answer of
ostringstream oss; oss << "Count is " << count; string s = oss.str();
is not likely to be discovered through experimentation.
In general, I agree that experimentation is good. C++ just isn't a safe environment and makes trial-and-error programming difficult.
Then where do all the buffer overruns come from? I'm not saying that developers are idiots, but every developer makes mistakes. Bugs are usually rooted in opportunities for error, so whatever your library can do to help trace brain farts is time and effort well spent.
I agree with what you've said. You're right, every developer makes mistakes, and bugs are rooted in opportunities for error. If a library can easily eliminate certain opportunities for error with minimal overhead, then it should probably do so. I'm a huge fan of C's assert() macro because it falls in line with the idea of minimal overhead (no performance penalty except when debugging). This doesn't mean that the library has to be bullet-proof. Library functions can accept their limitations and document them accordingly. It sounded like you wanted every function in the library to validate all input and define its behavior in all cases. I generally favor doing that only if the input "makes sense", but even if the function did not have well-defined behavior when the input was not handled by the function but "made sense" to me, I wouldn't curse it as long as it was clearly stated in the documentation.
No software should respond in an astonishing way when fed valid data that is outside of the domain of the function...
If a library function is fully documented and states that data within that range will not be handled by the function, then it can do whatever it likes if you pass it data within the invalid range. At that point, all bets are off, and it's your fault, not the function's fault. Libraries do not have to be idiot-proof, they just have to be fully documented and well-designed.
Developers are not idiots. Well, at least I know I'm not an idiot. I can't speak for everyone.
Rubbish. A library has to be bullet-proof too. For example, look at the bugs in the C library for malformed input - the worst ones result in buffer-overflows that result in remote exploits.
The post to which you replied is exactly right. Libraries are very different from applications because developers can be expected to deal with the erroneous conditions that a library cannot handle, whereas (in an ideal world) users should not be expected to work around an application's flaws. If the application encounters a scenario that it cannot handle, it is expected to deal with it gracefully. A library can simply document that it can't handle certain conditions and then expect the application developer to avoid those conditions before using functionality contained in the library.
The C library doesn't inherently contain bugs, but I suppose a particular implementation could have bugs. What you are talking about could most likely be classified as design flaws. For instance, gets() is inherently unsafe, and strncpy() has questionable behavior on certain input. These problems are not bugs, though, because the functions behave exactly as specified. As developers, we are expected to use the functions contained in the C library correctly.
If you are not happy with the C library, then wrap it. That way, you can create a library that meets your expectations without imposing such error checking on other developers who don't need it. Personally, I like it the way it is.
"I am reasonably certain that the only reason (today) that everyone uses Windows is because everyone uses Windows."
I'm reasonably certain that you're wrong.
Personally I use windows because I choose to. Why? Better hardware support, apps I don't want to do without and the occasional game.
This is because everyone uses Windows. Companies and software developers tend to focus their attention on the larger population of consumers/users. Few people use Linux as their desktop OS, therefore fewer desktop programs are available on Linux, and those that are available on Linux are generally less "polished". For most major efforts aimed at the desktop user, Windows compatibility is priorty #1, because that's where the users are.
Unfortunately, it's a vicious cycle. If the OS has more apps and better support, then it will probably draw more users. More users means more attention from the software suppliers, yielding more apps and better support, and so forth and so on.
If Microsoft even starts to contemplate charging royalties on every single program that people write and distribute for the operating system, I can bet we'll see one of the largest shifts to Linux development in history.
You're absolutely right. Unfortunately, this would only happen if Microsoft enlisted a team of chimpanzees to make its corporate decisions.
XP is just another way of designing software. If you have good programmers and managers it will work well. If you don't, it won't.
Some who argue against XP say that the above is true for any methodology.
I'm not sure what your definition of "knowing the language" is. If someone asked me to rate my C++ skills from 1 to 10, I would give myself a 4 or a 5. Anyone that rates themselves a 7 or higher is either named Sutter, Alexandrescu, Glassborow, or Stroustroup. Or is either grossly unfamiliar with the scope of C++ or flat out lying.
Wow, you're allocating the top 40% of the scale to less than 1% of the C++ programmer population? Don't you think that's a bit extreme? Those guys are all 10s, IMHO. What good is a scale from 1-10 if interviewees can only use the lower 1-6?
"stream the formatting through the test" What???
The point is that the format of the test aids in the streaming of the Perl 6 syntax, thus improving the programmer's experience when he/she is using "exception-handling"-like development in the customary fashion and enabling him/her to use OO-style methodologies in a RAD-enabled, but somewhat I/O-bound, manner.
Duh.
Mods, clue up!
Definitely.
Hmm, sounds like a motto for catster, dogster's competitor
This wasn't even marked as "Humor". I'm not laughing anyway.
Really? I see a foot icon.
How about...
"Ok, so what do you need, besides a license?"
"Hardware. Lots of Hardware."
An unlocked door is safe until someone sees you lock it. Therefore everybody just leave all your door unlocked, since we do not know that they're unlocked there is no danger.
A better analogy: It's more likely that a robber will be able to break into your home if he heard you explain how the lock on your door doesn't work terribly well. This sounds more reasonable, and is more like the point he was trying to make.
I particularly liked the rule about "Quit thinking and look". I worked with a guy who used what I call the "Zen method of debugging". He would keep staring at the code, trying to determine what was going on. I, on the other hand, would throw in some print statements so I could see what was going on.
Sometimes reading the code is enough. If you're good at reading code, then sometimes all you have to do is briefly look over what you wrote to spot the bug. YMMV, of course. If you've looked at the code for a few minutes and nothing looks obviously wrong, then it's probably time to use the debugger/add print statements. I've found that this is the most efficient way to go bug-hunting, because a quick re-read can find a lot of the "easy" bugs. This is similar to having a code review, but in this case you, the author, are the only reviewer. If there is another coder nearby, go ahead and ask him/her to give it a quick look as well, because he/she will probably have an easier time spotting the error.
I've met people who skip this step, and it drives me up the wall to see them waste their time (sometimes hours!) poking around in a debugger/writing print statements when the code they are debugging is simple. If it's a small, straightforward bit of code, then a quick look should uncover the bug. I suppose this falls under rule #1 (understand the system), but my point is more specific: understand the code.
None of the above is particularly groundbreaking, of course, and probably doesn't deserve to be mentioned in the book. These are more like "things you do before debugging".
"Basically, the information goes into government, and that's the dead end," says Sean Moulton, a senior policy analyst at OMB Watch. "Aside from encouraging the companies to do something, as far as my reading of the statute, they don't have much authority at all, and they can't warn the public."
(Setting: the school playground where government and corporations play)
Government: I can keep a secret. Tell me all your nasty mistakes and I won't tell anyone.
Company: Ok, but you have to promise that you won't tell Joe Consumer! Pinky swear!
This seems a tad scary to me. I'd prefer to have the government require that all companies must disclose information about vulnerabilities to the public. After all, aren't other companies outside of IT required to do this? How many times have we read about lawsuits where the public discovered that X company (tobacco, automobile, or otherwise) refused to disclose information about the hazards of their products to the public?
Jack: A new car built by my company leaves somewhere travelling at 60 mph. The rear differential locks up. The car crashes and burns with everyone trapped inside. Now: should we initiate a recall? Take the number of vehicles in the field, A, multiply by the probable rate of failure, B, multiply by the average out-of-court settlement, C. A times B times C equals X. If X is less than the cost of a recall, we don't do one.
Single Serving Friend: Are there a lot of these kinds of accidents?
Jack: You wouldn't believe.
Single Serving Friend: Which car company do you work for?
Jack: A major one.
For those who don't recognize this bit of dialog: this is from the movie "Fight Club". It's a great movie, but the quote is almost entirely unrelated to the main plot of the film.
I just don't get it. What is this obsession of Geeks and Haiku?
Slashdot and Haikus:
A match, like Spring and flowers.
You must be new here.
To produce bugless software we need to start with software designs that are provably correct and then produce code that is provably in line with the design. Using more objects that more closely model the "real world" is an invitation to producing larger number of bugs as the ambiguity of the real world infects the design and implementation of the program.
You're absolutely right. Some people think that turning to the "real world" for guidance a good idea, but I've found that it only confuses things. Nobody knows how to model real-world objects and relationships inside a computer in a way that suits all potential uses of that model. I've found that most discussions about software models for the real world in OO projects tend to degrade into analyzing the structure of various English sentences and considering the plethora of ways that a person _could_ understand a relationship. If there are tons of ways to represent the real world, how is the real world supposed to help produce bug-free software? Why should I believe that the answer lies in the real world instead of the software development process itself?
C# is just a language, it doesn't lock you into Windows at all. Mono supports the entire C# language.
.NET framework. It may work as a poor man's version of .NET, but let's not kid ourselves by implying that it is a full-fledged portable replacement for Microsoft's implementation.
.NET sucks on linux is like saying that C++ sucks because DirectX doesn't work on Linux.
.NET is an MS-specific framework masquerading as a "portable" solution. Don't buy into the "potential for portability" hype, especially if you're focusing mostly on the incomplete Mono implementation.
I seriously doubt this. Unless C# remains unchanged for many years, Mono will always have to play catch-up to C# and the
It's the classes you choose to use that lock you onto a specific platform. You can't blame C# if people want to use classes that aren't available on other platforms.
And does Microsoft document all of the classes that are not supported on other platforms? Are they at at least attempting to make their framework portable? Why should they? Unlike Sun, they are not striving to produce a spec for a complete solution (with tons of libraries) that other companies can implement on other platforms. They want you to use Windows and other MS products, plain and simple.
Its like saying that C++ sucks because DirectX doesn't work on Linux.
This is more accurate, IMHO:
Saying that
The difference is that DirectX is a documented windows-only API, whereas
Great. This will give SCO some good PR ammo. Thanks guys.
Prediction: now the slashdot conspiracy theorists will say that it's likely that SCO wrote it themselves.
In a way it works a bit like a joke: first you set something up, and then, at the end, you deliver the punch line.
A man writes Perl code
Loaded with Perl idioms
And thinks it is clear
(That was a joke. I love perl.)
As a video game developer, I've been involved in many "code upgrades", as well as rewrites. As long as the rewrite is being done by people who wrote the original code...
(emphasis mine)
Excellent point. That eliminates the "NIH rewrite", which is usually caused by programmer hubris. Sometimes maintenance programmers rewrite code for the sake of "clarity", when in actuality they are falling prey to their own pride. Of course, the end product looks clearer to them, but that's probably because they wrote it. It may or may not be clearer in an objective sense, and it might contain more bugs.
The Problem: Rewrite Mania
... etc
Waaaaaaa!!
Excellent rewrite. I found this post to be much clearer and more concise than the original article, while still maintaining the same message. I'm now convinced that rewrites can be A Good Thing.
I thought Heller's "mistake" was defensible even if you don't agree with it. Heller's goal was to provide a string class that would be usable and not too confusing for beginners. I don't think there is any perfect solution to the problem he was trying to solve.
I didn't get the impression that he realized that his class was a poor design decision. If he realized this, then that's good. Even so, I don't see how a beginner could be confused by string utility functions. Functions are (arguably) simpler than classes.
I've been preaching this song for the better part of 20 years. But people got very keen on putting everything in classes and hierarchies. I've seen the Date problem solved by having a base class Date with some operations on it and the data protected, with utility functions provided by deriving a new class and adding the utility functions. You get really messy systems like that, and there's no reason for having the utility functions in derived classes. You want the utility functions to the side so you can combine them freely. How else to I get your utility functions and my utility functions also? The utility functions you wrote are independent from the ones I wrote, and so they should be independent in the code. If I derive from class Date, and you derive from class Date, a third person won't be able to easily use both of our utility functions, because we have built dependencies in that didn't need to be there. So you can overdo this class hierarchy stuff.
// ...
Bjarne talks about this problem a little in his book (TC++PL), but I'm glad that he mentioned it here. Putting utility functions in derived classes is a mistake that is made far too often. How many times have you seen someone write something like this:
class MyString : public std::string {
public:
size_type find_no_case(const char *subStr) const;
};
Stop it! That should be a free-standing function. There is absolutely no benefit to using inheritance in the above code. The only thing it yields is a warm fuzzy feeling from using member functions instead of free-standing functions. Some coders just enjoy writing
MyString s("foobar");
i = s.find_no_case("foo");
instead of
std::string s("foobar");
i = find_no_case(s,"foo");
because it "feels right", even though it limits the reusability of the function. C++ programmers, please take note. It is a mistake that even book authors like Steve Heller make (Link)
This is something that novice programmers are well advised to listen to. I constantly am asked by junior programmers 'What happens when I do x', where x is something simple, like try to print out an array.
...; ...;
Half the time, the problem can be answered by simply trying it. And the other half of the time, you end up with a better question...
Unfortunately, C++ is complex, and undefined behavior will upset most attempts at experimentation. For example, suppose a beginning C++ programmer wants to change a string's contents so it contains the text "Count is $count" (Perl-ish code). Most of the time they try stuff like:
int count =
string s =
sprintf( &s[0], "Count is %d", count );
sprintf( (char*)s.c_str(), "Count is %d", count );
Does that work? Well, maybe, but the code's not guaranteed to work, and it's dangerous. But the problems with the code will not be recognized by the beginner, and therefore experimentation can lead him to assume something is correct even when it is not. The generally accepted answer of
ostringstream oss;
oss << "Count is " << count;
string s = oss.str();
is not likely to be discovered through experimentation.
In general, I agree that experimentation is good. C++ just isn't a safe environment and makes trial-and-error programming difficult.
Then where do all the buffer overruns come from? I'm not saying that developers are idiots, but every developer makes mistakes. Bugs are usually rooted in opportunities for error, so whatever your library can do to help trace brain farts is time and effort well spent.
I agree with what you've said. You're right, every developer makes mistakes, and bugs are rooted in opportunities for error. If a library can easily eliminate certain opportunities for error with minimal overhead, then it should probably do so. I'm a huge fan of C's assert() macro because it falls in line with the idea of minimal overhead (no performance penalty except when debugging). This doesn't mean that the library has to be bullet-proof. Library functions can accept their limitations and document them accordingly. It sounded like you wanted every function in the library to validate all input and define its behavior in all cases. I generally favor doing that only if the input "makes sense", but even if the function did not have well-defined behavior when the input was not handled by the function but "made sense" to me, I wouldn't curse it as long as it was clearly stated in the documentation.
No software should respond in an astonishing way when fed valid data that is outside of the domain of the function...
If a library function is fully documented and states that data within that range will not be handled by the function, then it can do whatever it likes if you pass it data within the invalid range. At that point, all bets are off, and it's your fault, not the function's fault. Libraries do not have to be idiot-proof, they just have to be fully documented and well-designed.
Developers are not idiots. Well, at least I know I'm not an idiot. I can't speak for everyone.
Rubbish. A library has to be bullet-proof too. For example, look at the bugs in the C library for malformed input - the worst ones result in buffer-overflows that result in remote exploits.
The post to which you replied is exactly right. Libraries are very different from applications because developers can be expected to deal with the erroneous conditions that a library cannot handle, whereas (in an ideal world) users should not be expected to work around an application's flaws. If the application encounters a scenario that it cannot handle, it is expected to deal with it gracefully. A library can simply document that it can't handle certain conditions and then expect the application developer to avoid those conditions before using functionality contained in the library.
The C library doesn't inherently contain bugs, but I suppose a particular implementation could have bugs. What you are talking about could most likely be classified as design flaws. For instance, gets() is inherently unsafe, and strncpy() has questionable behavior on certain input. These problems are not bugs, though, because the functions behave exactly as specified. As developers, we are expected to use the functions contained in the C library correctly.
If you are not happy with the C library, then wrap it. That way, you can create a library that meets your expectations without imposing such error checking on other developers who don't need it. Personally, I like it the way it is.