...
In this noncompliant code example, the set_flag()
function is intended to set the variable sign
to 1
if number
is positive and -1
if number
is negative. However, the programmer neglected to account for number
being 0
. If number
is 0
, then sign
remains uninitialized. Because sign
is uninitialized, and again assuming that the architecture makes use of a program stack, it uses whatever value is at that location in the program stack. This may lead to unexpected or otherwise incorrect program behavior.
Code Block |
---|
|
void set_flag(int number, int *sign_flag) {
if (sign_flag == NULL) {
return;
}
if (number > 0) {
*sign_flag = 1;
}
else if (number < 0) {
*sign_flag = -1;
}
}
void func(int number) {
int sign;
set_flag(number, &sign);
/* use sign */
}
|
...
This defect results from a failure to consider all possible data states (see MSC01-CPP. Strive for logical completeness). Once the problem is identified, it can be trivially repaired by accounting for the possibility that number
can be equal to 0.
Code Block |
---|
|
void set_flag(int number, int *sign_flag) {
if (sign_flag == NULL) {
return;
}
if (number >= 0) { /* account for number being 0 */
*sign_flag = 1;
} else {
assert(number < 0);
*sign_flag = -1;
}
}
void func(int number) {
int sign;
set_flag(number, &sign);
/* use sign */
}
|
...
Wiki Markup |
---|
In this noncompliant code example, the programmer mistakenly fails to set the local variable {{error_log}} to the {{msg}} argument in the {{report_error()}} function \[[mercy 06|AA. Bibliography#mercy 06]\]. Because {{error_log}} has not been initialized, on architectures making use of a program stack, it assumes the value already on the stack at this location, which is a pointer to the stack memory allocated to the {{password}} array. The {{sprintf()}} call copies data in {{password}} until a null byte is reached. If the length of the string stored in the {{password}} array is greater than the size of the {{buffer}} array, then a buffer overflow occurs. |
Code Block |
---|
|
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int do_auth(void) {
char *username;
char *password;
/* Get username and password from user, return -1 if invalid */
}
void report_error(const char *msg) {
const char *error_log;
char buffer[24];
sprintf(buffer, "Error: %s", error_log);
printf("%s\n", buffer);
}
int main(void) {
if (do_auth() == -1) {
report_error("Unable to login");
}
return 0;
}
|
...
In this noncompliant code example, the report_error()
function has been modified so that error_log
is properly initialized.
Code Block |
---|
|
void report_error(const char *msg) {
const char *error_log = msg;
char buffer[24];
sprintf(buffer, "Error: %s", error_log);
printf("%s\n", buffer);
}
|
...
In this solution, the magic number is abstracted and the buffer overflow is eliminated.
Code Block |
---|
|
enum {max_buffer = 24};
void report_error(const char *msg) {
const char *error_log = msg;
char buffer[max_buffer];
snprintf(buffer, sizeof( buffer), "Error: %s", error_log);
cout << buffer << endl;
}
|
...
A much simpler, less error prone, and better performing compliant solution is shown below.
Code Block |
---|
|
void report_error(const char *msg) {
cout << "Error: " << msg << endl;
}
|
...