【问题标题】:Valgrind array overrun within objectsValgrind 数组在对象内溢出
【发布时间】:2017-12-02 14:15:51
【问题描述】:

我有一个简单的程序如下。

struct Test
{
    int a[5];
    int b;
};

int main()
{
    Test* t = new Test;
    t->b = 1;
    t->a[5] = 5;          //This is an illegal write
    cout << t->b << endl; //Output is 5
    return 0;
}

用 Valgrind Memcheck 运行它并没有报告非法内存写入。

我注意到 Valgrind 声称 Memcheck 工具无法检测全局或堆栈数组溢出,但这个数组在堆中,对吗?只是数组在一个对象中。

是 Valgrind 真的无法检测到这种错误还是我做错了什么?如果前者是真的,那么有没有其他工具可以检测到这种类型的错误?

================================================ =============================

更新:

我使用的编译命令是g++ -O0 -g main.ccvalgrind 命令只是 valgrind ./a.out,默认情况下应该调用 memcheck 工具。

编译器版本为gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)valgrind版本为valgrind-3.5.0

运行此程序时的 Valgrind 输出:

==7759== Memcheck, a memory error detector
==7759== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==7759== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==7759== Command: ./a.out
==7759== 
5
==7759== 
==7759== HEAP SUMMARY:
==7759==     in use at exit: 24 bytes in 1 blocks
==7759==   total heap usage: 1 allocs, 0 frees, 24 bytes allocated
==7759== 
==7759== LEAK SUMMARY:
==7759==    definitely lost: 24 bytes in 1 blocks
==7759==    indirectly lost: 0 bytes in 0 blocks
==7759==      possibly lost: 0 bytes in 0 blocks
==7759==    still reachable: 0 bytes in 0 blocks
==7759==         suppressed: 0 bytes in 0 blocks
==7759== Rerun with --leak-check=full to see details of leaked memory
==7759== 
==7759== For counts of detected and suppressed errors, rerun with: -v
==7759== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)

【问题讨论】:

  • 你的程序在 Valgrind 上运行时会死掉吗?
  • Valgrind 应该能够检测到这一点,因为t get 分配在堆栈上。你在'-O0'上编译吗?在 '-O1' 及以上,编译器将删除整个Test-thing 并直接将字符“5”放入cout
  • @leolong:请使用compilervalgrind 命令以及所有选项更新您的问题?你没有收到任何反对你分配Test的消息吗?因为没有delete反对你的“新”?
  • @Milind 抱歉回复晚了。不,无论是否使用 Valgrind,程序都不会死。
  • @Azeem 谢谢。但我认为编译时警告对我来说不是一个解决方案,因为我猜测当索引是一个只能在运行时确定值的变量时,它无法警告更复杂的情况。

标签: c++ valgrind overrun


【解决方案1】:

我想下面这句话,你已经找到了:

Memcheck 无法检测您的程序存在的所有内存错误。为了 例如,它无法检测超出范围的对数组的读取或写入 静态分配或在堆栈上分配。但它应该检测到许多 可能导致程序崩溃的错误(例如,导致分段错误)。

如果你的类定义应该这样解释: 虽然类对象是动态分配的,但数组本身是静态分配的

我已经验证了几个案例:

如果动态分配数组,Valgrind 将报告无效写入:

struct Test
{
    int *a;
    int b;
};

int main()
{
    Test* t = new Test;
    t->a = new int[5];
    t->b = 1;
    t->a[5] = 5;          //This is an illegal write
    cout << t->b << endl; //Output is 5
    delete [] t->a;
    delete t;
    return 0;
}

如果将成员的顺序更改为:也会报错:

struct Test
{
  int b;  
  int a[5];
};

这是因为在尝试写入 a[5] 时,我们已经落后于动态分配的对象。

如果您尝试写入 a[6],则使用原始类定义 - 因为那时我们落后于 b,所以落后于动态分配的对象。


更新:gcc sanitizer(我也怀疑 clang)通过编译在运行时检测到这种越界访问:

g++ -fno-omit-frame-pointer -fsanitize=bounds m.cpp

输出:

m.cpp:15:7: runtime error: index 5 out of bounds for type 'int [5]'

【讨论】:

  • 感谢您的回复。我也做了这些测试,所以在我看来,Valgrind 无法检测到“带有”对象的数组溢出。您知道任何可以完成此任务的工具吗?谢谢。
  • 非常感谢。看起来消毒剂必须是要走的路。我一直担心它们对性能的影响。但至少影响比 Valgrind 小得多。我想这是最好的选择。谢谢。
猜你喜欢
  • 2013-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多