malloc分配的char*出现随机内容及栈溢出问题咨询
关于C语言
print_file_results函数的内存异常与栈溢出问题 问题代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <getopt.h> int bytes_flag,lines_flag, words_flag; int arg_in; static struct option long_opts [] = { {"bytes", no_argument, 0, 'c'}, {"lines", no_argument, 0, 'l'}, {0,0,0,0} }; int count_bytes(const char *filename){ FILE * file_stream; int byte_count = 0; file_stream = fopen(filename, "r"); if (file_stream == NULL){ printf("File could not be opened.\n"); } else{ while (getc(file_stream) != EOF){ byte_count ++; } fclose(file_stream); } return byte_count; } void print_file_results(const int bytes, const int lines, const int words, const char *filename, const int size){ char * results = malloc(size * 2 + 1); printf(results); printf("\n"); char int_buffer[4]; if (bytes != 0) { sprintf(int_buffer, "%d ", bytes); strcpy(results, int_buffer); printf(results); printf("\n"); } if (lines != 0) { //TODO } if (words != 0) { //TODO } printf("%s%s\n", results, filename); free(results); return; } int main (int argc, char * argv[]) { while(1){ arg_in = getopt_long (argc, argv, "cl", long_opts, NULL); if (arg_in == -1){ break; } switch(arg_in){ case 'c': printf("Byte count\n"); bytes_flag = 1; break; case 'l': printf("Line count\n"); lines_flag = 1; break; default: abort(); } } if (optind < argc){ while (optind < argc){ int bytes_total = 0; int lines_total = 0; int words_total = 0; printf("Current file %s\n", argv[optind]); if ( bytes_flag ){ bytes_total = count_bytes(argv[optind]); } if (lines_flag){ continue; } if (words_flag){ continue; } print_file_results(bytes_total, lines_total, words_total, argv[optind] , bytes_flag+lines_flag+words_flag); optind++; } } else { printf("No files given\n"); exit(1); } exit(0); }
运行命令与异常输出
❯ ./ccwc.o -c test.txt Byte count Current file test.txt ation is committed to coa 342190 342190 test.txt *** stack smashing detected ***: terminated [1] 125314 IOT instruction (core dumped) ./ccwc.o -c test.txt
问题原因分析
1. results出现随机文本的原因
malloc分配的内存块是未初始化的,保留着之前程序遗留的垃圾数据。你在strcpy初始化results之前就调用printf(results),直接输出了这块未初始化内存的随机内容,这就是看到的乱码。- 你用
bytes_flag+lines_flag+words_flag作为内存计算的size参数,当仅启用-c时,size值为1,分配的内存只有3字节。但sprintf(int_buffer, "%d ", bytes)生成的字符串(比如示例中的"342190 ")长度远超3字节,strcpy(results, int_buffer)会直接超出results的内存范围,写入相邻内存区域,导致内存越界,产生不可预测的内容。
2. 栈溢出检测触发的原因
- 你定义的
int_buffer[4]仅4字节,但当bytes值为342190时,"%d "格式化后会生成7个字符(含空终止符),sprintf会把这些内容写入int_buffer,超出其容量,直接破坏栈上的其他数据(比如栈帧返回地址),触发栈溢出检测机制。
修复方案
- 初始化堆内存:用
calloc代替malloc,或者分配后用memset(results, 0, required_size)初始化,避免输出未初始化的垃圾数据。 - 动态计算内存需求:不要用标志位数量计算内存,而是通过
snprintf(NULL, 0, format_str)获取格式化后的字符串长度,再分配对应大小的内存。 - 避免栈缓冲区溢出:不要固定
int_buffer的大小,要么动态分配,要么使用snprintf限制写入长度,防止越界。
修改后的print_file_results示例:
void print_file_results(const int bytes, const int lines, const int words, const char *filename){ // 先计算所需总长度 int total_len = 0; if (bytes != 0) { total_len += snprintf(NULL, 0, "%d ", bytes); } if (lines != 0) { total_len += snprintf(NULL, 0, "%d ", lines); } if (words != 0) { total_len += snprintf(NULL, 0, "%d ", words); } total_len += strlen(filename) + 1; // 文件名加终止符 char *results = malloc(total_len); if (!results) { // 检查内存分配是否成功 perror("malloc failed"); return; } results[0] = '\0'; // 初始化空字符串 if (bytes != 0) { snprintf(results + strlen(results), total_len - strlen(results), "%d ", bytes); } if (lines != 0) { snprintf(results + strlen(results), total_len - strlen(results), "%d ", lines); } if (words != 0) { snprintf(results + strlen(results), total_len - strlen(results), "%d ", words); } strcat(results, filename); printf("%s\n", results); free(results); }
同时修改main中的调用,去掉最后一个size参数:
print_file_results(bytes_total, lines_total, words_total, argv[optind]);
内容的提问来源于stack exchange,提问作者Caleb Renfroe
相关产品推荐
相关产品推荐

