(1)type safety

Another characteristic of C that is worth mentioning is the lack of type safety. Type safety consists of two attributes: preservation and progress [Pfenning 04]. Preservation dictates that if a variable x has type t and x evaluates to a value v, then v also has type t. Progress tells us that evaluation of an expression does not get stuck in any unexpected way: either we have a value (and are done), or there is a way to proceed. In general, type safety implies that any operation on a particular type results in another value of that type. C was derived from two typeless languages and still shows many characteristics of a typeless or weakly typed language. For example, it is possible to use an explicit cast in C to convert from a pointer to one type to a pointer to a different type. If the resulting pointer is dereferenced, the results are undefined. Operations can legally act on signed and unsigned integers of differing lengths using implicit conversions and producing unrepresentable results. This lack of type safety leads to a wide range of security flaws and vulnerabilities.

由于C语言存在(隐式/显式)类型转换,所以容易产生许多安全问题。

(2)Unbounded String Copies

防止cin越界的方法:

1. #include <iostream>

2. int main(void) {
3.  char buf[12];

4.  cin.width(12);
5.  cin >> buf;
6.  cout << "echo: " << buf << endl;
7. }

The extraction operation can be limited to a specified number of characters (thereby avoiding the possibility of out-of-bounds write) if the field width inherited member (ios_base::width) is set to a value greater than 0. In this case, the extraction ends one character before the count of characters extracted reaches the value of field width leaving space for the ending null character. After a call to this extraction operation the value of the field width is reset to 0.

需要注意这个width是一次性的,每次调用 >> 后都会归0。

代码进行PCLint检查时常常提示strcpy不安全,有机会要整改一下。

(3)Off-by-One Errors

经典程序

 1. int main(int argc, char* argv[]) {
 2.   char source[10];
 3.   strcpy(source, "0123456789");
 4.   char *dest = (char *)malloc(strlen(source));
 5.   for (int i=1; i <= 11; i++) {
 6.     dest[i] = source[i];
 7.   }
 8.   dest[i] = '\0';//据书上说VC++ 6.0能编译通过
 9.   printf("dest = %s", dest);
10. }
  • The source character array (declared on line 2) is 10 bytes long, but strcpy() (line 3) copies 11 bytes, including a one-byte terminating null character.

  • The malloc() function (line 4) allocates memory on the heap of the length of the source string. However, the value returned by strlen() does not account for the null byte.

  • The index value i in the for loop (line 5) starts at 1, but the first position in a C array is indexed by 0.

  • The ending condition for the loop (line 5) is i <= 11. This means the loop will iterate one more time than the programmer likely intended.

  • The assignment on line 8 also causes an out-of-bounds write.

(4)Null-Termination Errors

依赖于编译器如何分配空间,了解各种编译器貌似一个大坑,还是别跳了,老老实实注意不要忘了'\0’