为什么GCC不尝试内存泄漏检查?

jvlzgdj9  于 2023-06-23  发布在  其他
关注(0)|答案(3)|浏览(125)

虽然我很少使用C语言,但我一直在思考我总是被告知的规则,“如果你调用malloc()(或new),你必须调用free()(或delete)”。这让我想知道GCC(或其他C编译器)是否试图执行任何类型的内存并警告用户潜在的问题。我从来没有听说过,所以我怀疑不是这样的,但我想知道。
下面是我使用的示例:

#include <stdlib.h>

int main() {
  int* first = malloc(sizeof(int) *  10);
  int* second = malloc(sizeof(int) * 10);

  int i = 0;
  for (; i < 10; i++) {
    first[i] = i * 2;
    second[i] = i * 10;
  }

  free(first);  /* Forgot to free second */
  return 0;
}

使用gcc -Wall free_test.c编译时,未生成任何警告。虽然我可以理解为什么编译器不能提供一个完美的答案,因为你正在处理堆内存,并在运行时管理它,为什么编译器似乎没有试图提供一个警告,可能有一个内存泄漏?
我的一些想法,为什么包括:
1.编译器可能没有一个完美的方法来告诉内存何时被释放。例如,如果其中一个指针被传递到函数中并从函数中释放,编译器可能无法分辨。
1.如果一个不同的线程获得了内存的所有权,编译器将无法判断是否有其他线程正在释放内存。

x6yk4ghg

x6yk4ghg1#

通过静态分析(更不用说通过琐碎的静态分析)无法检测到的案例远远多于那些能够检测到的案例。编译器的作者大概认为,给GCC增加这种额外复杂性的好处远远超过了成本。

zpgglvta

zpgglvta2#

这比计算freemalloc调用要复杂一些。假设有一个库,其中一些库函数假定库调用malloc,但假定库的用户将调用free

wb1gzix0

wb1gzix03#

GCC有一个特殊的-fanalyze模式which does a number of different checks,包括用于malloc泄漏。
出于演示的目的,我不得不修改您的代码,将其转移到一个单独的foo()函数中,因为当它在main()中时,malloc的抱怨就消失了。我假设GCC假定从main返回无论如何都会释放内存。我还必须添加一个-Wno-analyzer-possible-null-dereference,以消除关于malloc()的结果可能是NULL * 的警告(以避免不必要地修改问题的代码)*。
代码:

#include <stdlib.h>

int foo() {
  int* first = malloc(sizeof(int) *  10);
  int* second = malloc(sizeof(int) * 10);

  int i = 0;
  for (; i < 10; i++) {
    first[i] = i * 2;
    second[i] = i * 10;
  }

  free(first);  /* Forgot to free second */
  return 0;
}

int main() {
  return foo();
}

结果:

λ gcc test.c -o a -fanalyzer -Wno-analyzer-possible-null-dereference                  
test.c: In function ‘foo’:
test.c:14:10: warning: leak of ‘second’ [CWE-401] [-Wanalyzer-malloc-leak]
   14 |   return 0;
      |          ^
  ‘foo’: events 1-9
    |
    |    5 |   int* second = malloc(sizeof(int) * 10);
    |      |                 ^~~~~~~~~~~~~~~~~~~~~~~~
    |      |                 |
    |      |                 (1) allocated here
    |......
    |    8 |   for (; i < 10; i++) {
    |      |          ~~~~~~  
    |      |            |
    |      |            (2) following ‘true’ branch (when ‘i <= 9’)...
    |      |            (5) following ‘true’ branch (when ‘i <= 9’)...
    |      |            (7) following ‘false’ branch (when ‘i > 9’)...
    |    9 |     first[i] = i * 2;
    |      |          ~       
    |      |          |
    |      |          (3) ...to here
    |      |          (6) ...to here
    |   10 |     second[i] = i * 10;
    |      |     ~~~~~~~~~~~~~~~~~~
    |      |               |
    |      |               (4) assuming ‘second’ is non-NULL
    |......
    |   13 |   free(first);  /* Forgot to free second */
    |      |   ~~~~~~~~~~~    
    |      |   |
    |      |   (8) ...to here
    |   14 |   return 0;
    |      |          ~       
    |      |          |
    |      |          (9) ‘second’ leaks here; was allocated at (1)

相关问题