1. Suggestions on signed number and unsigned number
As we can see, implicit coercion of type conversions with signed numbers to unsigned numbers results in some non-intuitive behavior. These non-intuitive features often result in program errors, and this kind of error, which contains subtle differences in implicit coercion type conversions, is difficult to find. Because this coercion type conversion occurs without explicit instructions in the code, the programmer often ignores its impact. The following 3 examples illustrate some minor errors caused by implicit coercion of type conversions and unsigned data types.
1.1 Sum_elements
Consider the following code, which attempts to calculate the and of all the elements in array A, where the number of elements is given by the length of the parameter.
/* Warning:this is Buggy code */float sum_elements (float a[], unsigned length) {int i; float result = 0; for (i = 0; I <= length-1; i++) result + = A[i]; return result;}
When the parameter length equals 0 o'clock, running this code should return 0.0. In practice, however, the runtime encounters a memory error.
Modify the code as follows:
/* Warning:this is Right code */float sum_elements (float a[], unsigned length) {int i; float result = 0; for (i = 0; i < length; i++) result + = A[i]; return result;}
1.2 Strlonger
Write a function to determine whether a string is longer than the other. The function you wrote at the beginning is this:
/* Determine whether string s is longer than string T *//* warning:this function is buggy */int strlonger (char *s, char * T) {return strlen (s)-strlen (T) > 0;}
Note In header file stdio.h, the data type size_t is defined as unsigned int.
/* Prototype for library function strlen */size_t strlen (const char *s);
In fact, when s is shorter than T, the return value of the Strlonger function is also 1, why does this happen? The original strlen return value type defines size_t as unsigned int in the Size_t,c language, and when s is shorter than T, strlen (s)-strlen (t) is negative, but the result of an unsigned number of operations implicitly converts to an unsigned number becomes a large unsigned number 。 In order for the function to work correctly, the code should be modified as follows:
int Strlonger (char *s1, char *s2) {return strlen (S1) > strlen (S2); }
1.3 Security vulnerability of function getpeername
In 2002, programmers working on the FreeBSD open source operating system realized that there was a security vulnerability to the implementation of the Getpeername function. The simplified version of the code is as follows:
/* * illustration of code vulnerability similar to that found in * freebsd ' S implementation of getpeername () */ /* declaration of library function memcpy */ void *memcpy (void *dest, void &NBSP;*SRC,&NBSP;SIZE_T&NBSP;N); /* kernel memory region holding user-accessible data */ #define KSIZE 1024 char kbuf[KSIZE]; /* Copy at most maxlen bytes from kernel region to user buffer */ int copy_from_kernel (Void *user_dest, int maxlen) { /* byte count len is minimum of buffer size and maxlen */ int len = ksize < maxlen ? ksize : maxlen; memcpy (User_dest, kbuf, len); return len; }
In this code, line 7th gives a prototype of the library function memcpy, which is to copy a specified length of n bytes from one area of memory to another.
The function Copy_from_kernel starting from line 14th is to copy the data maintained by some operating system cores to the memory area that the specified user can access. For users, the data structures maintained by most cores should be unreadable because they may contain sensitive information about other users and other jobs running on the system, but the areas shown as kbuf are user-readable. The parameter maxlen gives the length of the buffer allocated to the user, which is indicated by the parameter user_dest. Then, the calculation of line 16th ensures that the copied byte data does not exceed the range available for the source or destination buffers. However, assuming that some malicious programmer used a negative value for MaxLen in the code calling Copy_from_kernel, the minimum value of line 16th would assign the value to Len, and Len would be passed to memcpy as parameter n.
Note, however, that the parameter n is declared as the data type size_t. This data type is declared in the library file Stdio.h (through a typedef). Typically, it is defined as unsigned int on a 32-bit machine. Since parameter n is unsigned, memcpy treats it as a very large positive integer and attempts to copy such multibyte data from the kernel zone to the user's buffer. Although copying so many bytes (at least 231) is not actually done, because the program encounters an error in the illegal address in the process, the program can still read the kernel memory area that is not authorized.
As we can see, this problem is caused by a mismatch in the data type: In one place, the length parameter is a signed number, and the other place, it is an unsigned number. As this example shows, such mismatches can be the cause of the flaw and even lead to security breaches. Fortunately, there is no case to report that a programmer has exploited this vulnerability on FreeBSD. They released a security recommendation, "Freebsd-sa-02:38.signed-error", that advises system administrators how to apply patches to eliminate this vulnerability. To fix this flaw, simply declare the Copy_from_kernel parameter maxlen as type size_t, which is the same as the parameter N of memcpy. Also, we should declare the local variable len and the return value as size_t.
Bit by bit--c language