Chapter 13. Errors When Using Standard C Libraries

As we discussed in Chapter 1, C++ inherited the C philosophy and its corresponding problems. But that’s not all. It also inherited the standard C library, which is unsafe in several ways, and consequently all its associated problems, sometimes leading to unpredictable behavior up to and including program crashes. For the final chapter in this part of the book, we’ll discuss the possible dangers that await you when you use some of the functions that programmers frequently depend on in these libraries.

When we try to use the C string libraries declared in string.h or functions such as sprintf() declared in stdio.h, we may face the following problems:

  • The functions that take pointers to character arrays (char *) crash when given a NULL instead of a pointer to a valid C string (for example, strlen(NULL) will crash).

  • Some of the functions writing into a buffer might overwrite past the end of the buffer, thus leading to unpredictable application behavior including crashes.

  • The safer versions of the same functions will not overwrite the buffer, but will stop writing into a buffer just before it ends, thus silently truncating the result—probably not the behavior one would want.

There are several potential ways to address these problems:

  • Provide versions of the functions that do all the necessary sanity checks and treat the NULL pointers the same way as they would handle an empty string (const char* empty_string = "";).

  • For those applications where the speed of these string operations should not be compromised, provide versions with temporary sanity checks that are active only during testing.

However, the best possible solution to this problem is not to use the C string libraries at all. Use the classes provided by C++ instead. For example:

  • Instead of strlen(my_c_string), you can use my_cpp_string.size().

  • Instead of strcpy(), just copy the strings using string’s assignment operator (i.e., =).

To concatenate two strings, two functions in the C library are available. strcat() blindly adds a string to the end of an existing string in a buffer without ever knowing where the buffer ends. By contrast, strncat() adds no more than the specified number of bytes, which seems like a step in the right direction, but it still does not know anything about the size of the buffer it adds to. The programmer is responsible for allocating the right amount of space and calculating how many bytes to add.

Instead of strcat() or strncat(), use either:

#include <sstream> // ostringstream
#include <string>

  ostringsream buffer;
  buffer << first_string;
  buffer << additional_string;
  string result = buffer.str();

or, even shorter:

#include <string>

  string result = first_string;
  result += additional_string;

Not only are these more readable and safer, they are actually faster for long strings than strcat()! There are no buffers to allocate and overwrite.

If you are working with std::string and provide a NULL as an argument in a constructor:

std::string empty_string(NULL);

the program does not crash. Instead it throws an exception with a human-readable (well, almost human-readable) explanation of what happened:

basic_string::_S_construct NULL not valid

which translates into plain English as “the constructor of std::string found a NULL as an argument where it expected a valid C string.”

The rule for this chapter to avoid buffer overflows and crashes when using C string library functions is to avoid using C string libraries.

  • They are not safe and sometimes not even as fast as the corresponding C++ classes, such as std::string and std::ostringstream. Use C++ classes and you will avoid a number of possible errors leading to program crashes or other unpredictable behavior.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.37.191