I have been writing a program that converts a series of strings from the command line into one case based on the case of the first letter. The program itself works and runs fine, but when I use the address sanitizer, it keeps saying I am trying to read outside of my buffer.
Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
void print_list(char **data);
int main(int argc, char *argv[]) {
if(argv[1] == NULL) {
fprintf(stderr, "Error: No strings were entered\n");
return EXIT_FAILURE;
}
int arg_num = 1;
char *output[argc - 1];
while (argv[arg_num] != NULL) {
int count = 0;
char *line;
line = malloc(sizeof(char));
int size = sizeof(char);
int word_flag = FALSE;
int upper_flag = FALSE;
int lower_flag = FALSE;
while (argv[arg_num][count] != '\0') {
size = size + sizeof(char);
line = realloc(line, size);
if (argv[arg_num][count] >= 65 && argv[arg_num][count] <= 90) {
if (word_flag == FALSE && upper_flag == FALSE) {
word_flag = TRUE;
upper_flag = TRUE;
line[count] = argv[arg_num][count];
}
else if (word_flag == TRUE && upper_flag == FALSE) {
line[count] = (argv[arg_num][count] + 32);
}
else {
line[count] = argv[arg_num][count];
}
}
else if (argv[arg_num][count] >= 97 && argv[arg_num][count] <= 122) {
if (word_flag == FALSE && lower_flag == FALSE) {
word_flag = TRUE;
lower_flag = TRUE;
line[count] = argv[arg_num][count];
}
else if (word_flag == TRUE && lower_flag == FALSE) {
line[count] = (argv[arg_num][count] - 32);
}
else {
line[count] = argv[arg_num][count];
}
}
else if (argv[arg_num][count] == ' ' || argv[arg_num][count] == '\t') {
word_flag = FALSE;
upper_flag = FALSE;
lower_flag = FALSE;
line[count] = argv[arg_num][count];
}
else {
line[count] = argv[arg_num][count];
}
count++;
}
line[count] = '\0';
output[arg_num - 1] = line;
arg_num++;
}
print_list(output);
return EXIT_SUCCESS;
}
void print_list(char **data) {
int count = 0;
while (data[count] != NULL) {
printf("%s\n", data[count]);
free(data[count]);
count++;
}
}
And here is the output from the sanitizer:
==222362==ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address 0x7ffc487cc7a8 at pc 0x000000401f8f bp 0x7ffc487cc740 sp 0x7ffc487cc738
READ of size 8 at 0x7ffc487cc7a8 thread T0
#0 0x401f8e in print_list (/home/evanlewis/Documents/School/CS/306/Homework/Assignment 2/a.out+0x401f8e)
#1 0x401e87 in main (/home/evanlewis/Documents/School/CS/306/Homework/Assignment 2/a.out+0x401e87)
#2 0x7f0e7364a50f in __libc_start_call_main (/lib64/libc.so.6+0x2750f)
#3 0x7f0e7364a5c8 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x275c8)
#4 0x401144 in _start (/home/evanlewis/Documents/School/CS/306/Homework/Assignment 2/a.out+0x401144)
Address 0x7ffc487cc7a8 is located in stack of thread T0
SUMMARY: AddressSanitizer: dynamic-stack-buffer-overflow (/home/evanlewis/Documents/School/CS/306/Homework/Assignment 2/a.out+0x401f8e) in print_list
Shadow bytes around the buggy address:
0x1000090f18a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000090f18b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000090f18c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000090f18d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000090f18e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1000090f18f0: ca ca ca ca 00[cb]cb cb cb cb cb cb 00 00 00 00
0x1000090f1900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000090f1910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000090f1920: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000090f1930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000090f1940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==222362==ABORTING
According to the sanitizer, the problem is in print_list, the function that prints the strings from the array storing them post-conversion. It insists that I am trying to read outside of my buffer even though I would think the while loop would prevent that from happening. After all the strings have been printed, data[count] should equate to NULL, as there are only as many rows as strings. Is there something I am misunderstanding?
Your print_list method relies on the data array ending with a NULL pointer, but your code in main doesn't put a NULL pointer into that array, and doesn't have enough space in the array for a final null pointer.
For example, if you pass one argument to the program, argc will be 2 (one for the program name and one for the argument). This line:
char *output[argc - 1];
will create an array with space for 1 entry.
When your loop in print_list loops around, it will read past the end of the array as soon as count is > 0
while (data[count] != NULL) {
One way to fix this would be to ensure your array is large enough, and ensure that the last entry is always null.
char *output[argc];
output[argc - 1] = null;