我一直在编写一个程序,根据第一个字母的大小写将命令行中的一系列字符串转换为一个大小写。该程序本身可以正常运行,但是当我使用地址清理器时,它一直说我正在尝试读取缓冲区之外的内容。
这是我的代码:
#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++;
}
}
这是消毒剂的输出:
==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
根据消毒剂的说法,问题出在 print_list 中,该函数打印转换后存储字符串的数组中的字符串。它坚持认为我正在尝试读取缓冲区之外的内容,尽管我认为 while 循环会阻止这种情况发生。打印完所有字符串后,data[count] 应等于 NULL,因为行数与字符串一样多。我有什么误解吗?
您的 print_list 方法依赖于以 NULL 指针结尾的数据数组,但是您在 main 中的代码没有将 NULL 指针放入该数组,并且数组中没有足够的空间用于最终的空指针。
例如,如果您向程序传递一个参数,argc 将为 2(一个用于程序名称,一个用于参数)。 这一行:
char *output[argc - 1];
将创建一个包含 1 个条目空间的数组。
当 print_list 中的循环循环时,一旦 count > 0,它将读取数组末尾
while (data[count] != NULL) {
解决此问题的一种方法是确保您的数组足够大,并确保最后一个条目始终为空。
char *output[argc];
output[argc - 1] = null;