0

我在下面有这个代码片段,它在“str”中的分配过程中崩溃,这是一个动态分配。

  char *str;
  int file_size;
  FILE *fptr;
  if (!(fptr = fopen(filename, "r"))) goto error1;
  if ((fseek(fptr, 0L, SEEK_END) != 0)) goto error2;
  if (!(file_size=ftell(fptr))) goto error2;
  if ((fseek(fptr, 0L, SEEK_SET) != 0)) goto error2;
  str =  (char*)malloc(file_size+1);
  if (fread(str, file_size, 1, fptr) != 1) {
    free(str);
    goto error2;
  }
  str[file_size] = '\0';
  fclose(fptr);

file_size 是非零、非负小于 140 的值

我正在使用 ARM。这实际上适用于我的英特尔电脑,但不适用于手臂机器。

4

7 回答 7

7

您可以在手册中看到这一点 - ftell() 在错误时返回 -1,而不是零。

于 2009-06-05T09:17:54.413 回答
3

打印你的变量,特别是file_size在你使用它们之前。你可能会得到一个惊喜。

于 2009-06-05T09:18:39.340 回答
2

返回的值是ftell(fptr)多少?也许它太大了?如果它确实返回 long int,那么它可能会溢出你的 int 并且你会在那里得到一个负值。

于 2009-06-05T09:19:36.000 回答
2

malloc 需要一个 size_t 作为参数。size_t 是 unsigned int 或 unsigned long 的 typedef(取决于平台),这里的关键是 UNSIGNED。

您使用一个 int 表示 file_size,而一个 int 可能只有 16 位(您使用的是 ARM,所以我认为这是一个 MCU)。带符号的 16 位只能支持 32,768 字节的文件大小(以字节为单位),因此,如果您有一个大文件(实际上并没有那么大,只是 >32K),file_size 会溢出。

我认为编译器告诉了你,但你选择忽略它......现在 mallow 接受一个无符号参数,所以它会自动转换你对 filesize+1 的签名评估(即使它被深度溢出,一个有符号的大时间负数)并尝试分配内存。这可能意味着您尝试分配的内存比此嵌入式应用程序多得多。不能(不应该崩溃)。

我真的没有看到崩溃的原因(除了一个坏的库,在嵌入式 C 中很常见,由于用户基础反馈低),但我看到了导致不良行为的错误。

我什至不会去问“为什么要使用 goto 东西”,因为答案会引发很多激烈的评论。

于 2009-06-05T10:23:41.677 回答
1

在不正确的地址上执行缓冲区溢出或 free() 之前的某个地方!!!-)

于 2009-06-05T10:37:25.377 回答
0

从一般意义上说...我根本没有要抨击的意思,但是您的代码有点糟糕。使用编码标准通常会让事情变得更清楚......也就是说,尼尔可能得到了答案。

于 2009-06-05T10:07:01.740 回答
0

这不太可能是您的问题,但您是否记得

#include <stdlib.h>

这样malloc的原型就在范围内了吗?在这种情况下,编译器不会警告你,因为它的返回值是免费的。在 C 中,没有理由强制转换 malloc 的返回值。所以:

str =  malloc(file_size + 1);

顺便说一句,空白是免费的。

最后,如果您希望能够在多个平台上以这种方式推断文件的大小,则应该以二进制模式打开文件。

基于:

str[file_size] = '\0';

您似乎隐含地假设该文件不能包含嵌入的 \0 字符。如果你确实做到了,这让我觉得这是一个危险的假设。

于 2009-06-05T11:27:20.907 回答