Valgrind 抱怨“大小 8 的写入无效”

发布于 2024-12-08 09:58:50 字数 4276 浏览 0 评论 0原文

我正在开发一个小型爱好项目(www.github.com/AzP/GLSL-Validate) 我采用了旧代码(根据我自己的口味,太多的 c 和很少的 c++,但是嘿,你能做什么?),我正在尝试让它在 Linux 和 Windows 上运行。我遇到过几次崩溃(希望现在已修复),但自从我开始运行 Valgrind 来查找问题后,我就一直想解决收到的投诉。

关于 Valgrind 的投诉,我只是看不出这段代码有什么问题(除了它很难阅读,因为到处都是漂亮的“神奇数字”)。

我使用以下命令运行 Valgrind valgrind --track-origins=yes ./Program

291 //
292 //   Malloc a string of sufficient size and read a string into it.
293 //
294 # define MAX_SOURCE_STRINGS 5
295 char** ReadFileData(char *fileName)
296 {
297     FILE *in = fopen(fileName, "r");
298     char *fdata;
299     int count = 0;
300     char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1);
301 
302     //return_data[MAX_SOURCE_STRINGS]=NULL;
303     if (!in) {
304         printf("Error: unable to open input file: %s\n", fileName);
305         return 0;
306     }
307 
308     // Count size of file by looping through it
309     while (fgetc(in) != EOF)
310         count++;
311 
312     fseek(in, 0, SEEK_SET);
313 
314 
315     if (!(fdata = (char *)malloc(count+2))) {
316             printf("Error allocating memory\n");
317             return 0;
318     }
319     if (fread(fdata, sizeof(char), count, in) != count) {
320             printf("Error reading input file: %s\n", fileName);
321             return 0;
322     }
323     fdata[count] = '\0';
324     fclose(in);
325     if(count==0){
326         return_data[0]=(char*)malloc(count+2);
327         return_data[0][0]='\0';
328         OutputMultipleStrings=0;
329         return return_data;
330     }
331 
332     int len = (int)(ceil)((float)count/(float)OutputMultipleStrings);
333     int ptr_len=0,i=0;
334     while(count>0){
335         return_data[i]=(char*)malloc(len+2);
336         memcpy(return_data[i],fdata+ptr_len,len);
337         return_data[i][len]='\0';
338         count-=(len);
339         ptr_len+=(len);
340         if(count<len){
341             if(count==0){
342                OutputMultipleStrings=(i+1);
343                break;
344             }
345            len = count;
346         }
347         ++i;
348     }
349     return return_data;
350 }

这里是 Valgrind 输出。 在大小为 6 的块内分配了 0 个字节是否意味着我可以忽略它?我的意思是“0 字节”听起来并不危险?但既然我在这里发布了这个问题,我想你可以看到我认为我应该关注它。

==10570== Invalid write of size 8
==10570==    at 0x401602: ReadFileData(char*) (StandAlone.cpp:335)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570==  Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd
==10570==    at 0x4C2880D: malloc (vg_replace_malloc.c:236)
==10570==    by 0x401475: ReadFileData(char*) (StandAlone.cpp:300)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570== 
==10570== Invalid read of size 8
==10570==    at 0x401624: ReadFileData(char*) (StandAlone.cpp:336)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570==  Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd
==10570==    at 0x4C2880D: malloc (vg_replace_malloc.c:236)
==10570==    by 0x401475: ReadFileData(char*) (StandAlone.cpp:300)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570== 
==10570== Invalid read of size 8
==10570==    at 0x40163F: ReadFileData(char*) (StandAlone.cpp:337)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570==  Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd
==10570==    at 0x4C2880D: malloc (vg_replace_malloc.c:236)
==10570==    by 0x401475: ReadFileData(char*) (StandAlone.cpp:300)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)

编辑:我需要在 C++ 编译器中编译代码,这就是为什么我必须保留 malloc 的所有转换。

I'm working on a small hobby project (www.github.com/AzP/GLSL-Validate) where I've taken old code (too much c and to little c++ for my own taste, but hey, what can you do?) and I'm trying to get it up and running on Linux and Windows. I've had a couple of crashes (fixed now hopefully), but since I started running Valgrind to find the issues, I got stuck with wanting to fix the complaints I get.

I just can't see what's wrong with this code (except that it's quite hard to read with nice "magic numbers" spread over the place) with regards to the Valgrind complaints.

I'm running Valgrind with the following command valgrind --track-origins=yes ./Program

291 //
292 //   Malloc a string of sufficient size and read a string into it.
293 //
294 # define MAX_SOURCE_STRINGS 5
295 char** ReadFileData(char *fileName)
296 {
297     FILE *in = fopen(fileName, "r");
298     char *fdata;
299     int count = 0;
300     char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1);
301 
302     //return_data[MAX_SOURCE_STRINGS]=NULL;
303     if (!in) {
304         printf("Error: unable to open input file: %s\n", fileName);
305         return 0;
306     }
307 
308     // Count size of file by looping through it
309     while (fgetc(in) != EOF)
310         count++;
311 
312     fseek(in, 0, SEEK_SET);
313 
314 
315     if (!(fdata = (char *)malloc(count+2))) {
316             printf("Error allocating memory\n");
317             return 0;
318     }
319     if (fread(fdata, sizeof(char), count, in) != count) {
320             printf("Error reading input file: %s\n", fileName);
321             return 0;
322     }
323     fdata[count] = '\0';
324     fclose(in);
325     if(count==0){
326         return_data[0]=(char*)malloc(count+2);
327         return_data[0][0]='\0';
328         OutputMultipleStrings=0;
329         return return_data;
330     }
331 
332     int len = (int)(ceil)((float)count/(float)OutputMultipleStrings);
333     int ptr_len=0,i=0;
334     while(count>0){
335         return_data[i]=(char*)malloc(len+2);
336         memcpy(return_data[i],fdata+ptr_len,len);
337         return_data[i][len]='\0';
338         count-=(len);
339         ptr_len+=(len);
340         if(count<len){
341             if(count==0){
342                OutputMultipleStrings=(i+1);
343                break;
344             }
345            len = count;
346         }
347         ++i;
348     }
349     return return_data;
350 }

And here comes the Valgrind output. Does the is 0 bytes inside a block of size 6 alloc'd mean that I can disregard it? I mean '0 bytes' doesn't sound dangerous? But since I posted the question here, I guess you can see that I think that I should pay attention to it.

==10570== Invalid write of size 8
==10570==    at 0x401602: ReadFileData(char*) (StandAlone.cpp:335)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570==  Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd
==10570==    at 0x4C2880D: malloc (vg_replace_malloc.c:236)
==10570==    by 0x401475: ReadFileData(char*) (StandAlone.cpp:300)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570== 
==10570== Invalid read of size 8
==10570==    at 0x401624: ReadFileData(char*) (StandAlone.cpp:336)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570==  Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd
==10570==    at 0x4C2880D: malloc (vg_replace_malloc.c:236)
==10570==    by 0x401475: ReadFileData(char*) (StandAlone.cpp:300)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570== 
==10570== Invalid read of size 8
==10570==    at 0x40163F: ReadFileData(char*) (StandAlone.cpp:337)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)
==10570==  Address 0x5f627a0 is 0 bytes inside a block of size 6 alloc'd
==10570==    at 0x4C2880D: malloc (vg_replace_malloc.c:236)
==10570==    by 0x401475: ReadFileData(char*) (StandAlone.cpp:300)
==10570==    by 0x4013D8: CompileFile(char*, void*, int, TBuiltInResource const*) (StandAlone.cpp:255)
==10570==    by 0x401016: main (StandAlone.cpp:152)

EDIT: I need the code to compile in a c++ compiler, that's why I have to keep all the casts of malloc.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

叫嚣ゝ 2024-12-15 09:58:50

这看起来是错误的:

char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1);

可能应该是:(

char **return_data = malloc ( (MAX_SOURCE_STRINGS+1) * sizeof *return_data );

为了方便起见添加了空格)。

编辑:一些额外的解释:
当您说 return_data[i]=... 时,您正在尝试向 return_data[i] 中写入一些内容。现在,return_datachar**,因此 return_data[i]char*。所以你正在将一个指针写入内存中的某个位置。

看起来您的指针有 8 个字节长(这很好),但您只分配了 6 个字节:MAX_SOURCE_STRING+1。所以有一个问题。

事实上,你试图将其写入偏移量 0 并不重要 - 你仍然试图写入比缓冲区可以容纳的更多的数据,这就是 valgrind 所抱怨的。

为了解决这个问题,您应该分配足够的空间来容纳指针数组。每个指针都采用 sizeof(char*),也可以写为 sizeof(*return_data)sizeof *return_data。因此,您总共应该分配 n * sizeof *return_data 字节,其中 n 是(在您的情况下)幻数 6。

This looks wrong:

char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1);

Should probably be:

char **return_data = malloc ( (MAX_SOURCE_STRINGS+1) * sizeof *return_data );

(spaces added for convenience).

EDIT: Some additional explanation:
When you say return_data[i]=... you are trying to write something into return_data[i]. Now, return_data is char**, so return_data[i] is char*. So you are writing a pointer into some location in memory.

It looks like your pointers are 8 bytes long (which is fine), but you've only allocated 6 bytes: MAX_SOURCE_STRING+1. So there is a problem.

The fact that you're trying to write it into offset 0 doesn't matter - you're still trying to write more data than the buffer can take, and that's what valgrind is complaining about.

To solve the problem, you should allocate enough space to hold an array of pointers. Each pointer takes sizeof(char*), which can also be written as sizeof(*return_data) or sizeof *return_data. So in total you should allocate n * sizeof *return_data bytes, where n is (in your case) the magic number 6.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文