You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 8 Next »

Local, automatic variables can assume unexpected values if they are used before they are initialized. The current C specification states "If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate." [ISO/IEC 9899, 6.7.8 Initialization] In practice, this value is what ever is on the stack. This may cause variables to take on unintended values. Consequently, a program this can cause a program to behave in an unpredictable or unplanned manner, and may provide an avenue for attack. Some compilers warn about unitialized variables, but the warning is inconsistent and can be ignored by the programmer. As a result, it is necessary to guarantee that all local variables are initialized with a default value. The value assigned should be documented as the "default value" for that variable in the comments associated with that variable's declaration.

Non-compliant Code Example 1

In this example, two functions are called one after another. The first function, func1(...)}}is passed an integer entered by a user. That integer is stored in variable: {{i for the duration of the function. The second function func2()}}declares a local integer variable: {{j. j is not initialized before being checked against a constant value, CONDITION_CHECK. Since {{j}}was not initialized, it assumes whatever value is at that location in the stack, in this case the value of i from func1(). Thus is the user entered 42, the condition the statement if (j == CONDITION_CHECK) succeeds.

#define CONDITION_CHECK  42
void  func1 (int arg) { int i = arg; }
void  func2 (void) {
    int j;

    if (j == CONDITION_CHECK) printf("Condition passed!!\n");
    else printf("ERROR: Condition failed\n");
}
int main(int argc, char **argv) {
    func1(atoi(argv[1]));
    func2();
}

Compliant Solution 1

The local, automatic variable j should be initialized to a default value.

#define CONDITION_CHECK  42
void  func1 (int arg) { int i = arg; }
void  func2 (void) {
    int j = 0; 	/* initialize j to 0 */

    if (j == CONDITION_CHECK) printf("Condition passed!!\n");
    else printf("ERROR: Condition failed\n");
}
int main(int argc, char **argv) {
    func1(atoi(argv[1]));
    func2();
}

Non-compliant Code Example 2

In this example, user input is copied to a buffer, buf. The first function, logit() copies the user input to another buffer, buffer, and prints it to standard output. Next, the runit() routine is called. This routine declares an array of 50 characters, buf, and a character pointer, ptr.

However, since ptr is not initialized it references data used by the last function called. In this case, the contents of the user controlled data copied in the logit() function. When the data referred to by ptr is copied to buf using an unbounded strcpy(), ptr is dereferenced and the data in that location is copied to buf. If that data at that location is longer than 50 bytes without a null byte, a buffer overflow will occur.

#define BUF_SIZE 150

void runit(void) {
    char buf[50];
    char *ptr;

    memset(buf,0,50);
    strcpy(buf,ptr);
}

void logit(char *str) {
    char buffer[BUF_SIZE];

    strcpy(buffer, str);
    printf("The message: %s\nhas been logged\n",buffer);
}

int main(int argc, char *argv[]) {
    char buf[BUF_SIZE];

    strcpy(buf, argv[1]);
    logit(buf);
    runit();
}

Compliant Solution 2

The local variable ptr should be initialized to a default value.

#define BUF_SIZE 150

void runit(void) {
    char buf[50];
    char *ptr = NULL; /* initialize ptr to 0 */

    memset(buf,0,50);
    strcpy(buf,ptr);
}

void logit(char *str) {
    char buffer[BUF_SIZE];
    int i;
    for (i=0; i < BUF_SIZE; ++i) buffer[i] = '\0';

    strcpy(buffer, str);
    printf("The message: %s\nhas been logged\n",buffer);
}

int main(int argc, char *argv[]) {
    char buf[BUF_SIZE];

    strcpy(buf, argv[1]);
    logit(buf);
    runit();
}

References

  • No labels