gcc编译器有没有任何选项可以在编译时识别内存损坏?

6
#include <stdio.h>
#include <string.h>

int main()
{
  char arrDst[5] = {0};
  char arrSrc[10] = "123456";
  memcpy( arrDst, arrSrc, sizeof( arrSrc ) );
  return 0;
}

在这个程序中很明显存在内存损坏问题。是否有gcc编译器的选项能够在编译时就识别出这个问题?注意:我已经使用了valgrind --leak-check=full,但没有帮助。

3
这不是内存泄漏,而是缓冲区溢出。只有当你使用“malloc()”分配缓冲区时,Valgrind 才能发现这些问题。 - Aaron Digulla
你为什么认为内存损坏是明显的?编译器可能不会对memcpy的语义做出任何假设。 - swegi
@swegi: 编译器非常清楚memcpy的语义; 这个名称是由C标准保留用于实现,即使你编写自己的memcpy函数并执行不同的操作,编译器也可以忽略它,并假定你正在调用<string.h>函数。 - Stephen Canon
2个回答

7
$ gcc -Wall -O1 t.c 
In file included from /usr/include/string.h:642:0,
                 from t.c:3:
In function ‘memcpy’,
    inlined from ‘main’ at t.c:13:9:
/usr/include/bits/string3.h:52:3: warning: call to __builtin___memcpy_chk
   will always overflow destination buffer [enabled by default]

GCC可以识别其中的一些。通常需要开启优化(至少-01)和警告(-Wall,还要添加-Wextra)。


3
-Wall 应该成为默认选项 :-) - Aaron Digulla

2

虽然它可能无法适用于您真正感兴趣的大型程序,但您可以使用Frama-C找到此错误:

$ frama-c -cpp-command "gcc -C -E -I`frama-c -print-share-path`/libc/ -nostdinc" mem.c `frama-c -print-share-path`/libc/fc_runtime.c -val
...
[value] computing for function memcpy <- main.
    Called from mem.c:13.
.../libc/string.h:54:[value] Function memcpy: precondition got status invalid.

这条消息意味着您正在使用不符合memcpy()合同的参数进行调用。在这种情况下,失败的前提条件是列表中的第一个,即目标写入的有效性:

/*@ requires \valid(((char*)dest)+(0..n - 1));                                                                                                                   
  @ requires \valid_read(((char*)src)+(0..n - 1));                                                                                                               
  @ requires \separated(((char *)dest)+(0..n-1),((char *)src)+(0..n-1));                                                                                         
  @ assigns ((char*)dest)[0..n - 1] \from ((char*)src)[0..n-1];                                                                                                  
  @ assigns \result \from dest;                                                                                                                                  
  @ ensures memcmp((char*)dest,(char*)src,n) == 0;                                                                                                               
  @ ensures \result == dest;                                                                                                                                     
  @*/
extern void *memcpy(void *restrict dest,
                    const void *restrict src, size_t n);

1
这个框架看起来很有趣。如果它能像“前置条件‘requires \valid(((char*)dest)+(0..n - 1));’失败”一样产生有用的错误信息就好了.... :-) - Aaron Digulla
1
@AaronDigulla我将把这个建议作为一个功能请求提交。谢谢!(易用性很难做到完美。当你经常使用某个东西时,你会习惯它的工作方式,就看不到这些缺点了) - Pascal Cuoq
2
为了使其可用,我建议给每个要求命名,例如“目标足够大”,“源足够大”,“无重叠”。 - Aaron Digulla
1
这些信息已经在Frama-C的GUI中可用(将frama-c替换为frama-c-gui)。您可以通过左键单击memcpy名称并选择“转到定义”来导航到memcpy函数。然后立即就会知道哪个前提条件无效。 - byako

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接