【问题标题】:malloc() returning address that I cannot accessmalloc() 返回我无法访问的地址
【发布时间】:2014-09-02 11:26:35
【问题描述】:

我有一个 C++ 程序,它调用一些由 Flex / Bison 生成的 C 例程。

当我以 Windows 8.1 64 位平台为目标时,我在运行时遇到以下异常:

Unhandled exception at 0x0007FFFA70F2C39 (libapp.dll) in application.exe: 0xC0000005: 
Access violation writing location 0x000000005A818118.

我将此异常追溯到以下代码:

YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
{
   YY_BUFFER_STATE b;
   b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
   if ( ! b )
      YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
   b->yy_buf_size = size; // This access is what throws the exception
}

作为参考,在代码的其他地方(也由 Flex / Bison 生成),我们有:

typedef struct yy_buffer_state *YY_BUFFER_STATE;
struct yy_buffer_state
{
   FILE *yy_input_file;
   char *yy_ch_buf;
   char *yy_buf_pos;
   yy_size_t yy_buf_size;
   // ... other fields omitted,
   // total struct size is 56 bytes
}

static void *yy_flex_alloc( yy_size_t size )
{
   return (void *) malloc( size );
}

我回溯到malloc 调用并观察到malloc 本身正在返回地址0x000000005A818118。我也查了errno,但是调用malloc之后没有设置。

我的问题是:为什么malloc 给我一个我无法访问的地址,我怎样才能让它给我一个正确的地址?

注意:我只在 Windows 8.1 64 位中观察到这种行为。它与其他 32 位 Windows 变体以及 Windows 7 32 位一起通过。

编译信息:我在使用 Visual Studio 2012 的 64 位 Windows 8.1 机器上编译。

如果有帮助,这里是反汇编代码:

// b = (YY_BUFFER_STATE) yy_flex_alloc( ... )
0007FFFA75E2C12  call   yy_flex_alloc (07FFFA75E3070h)
0007FFFA75E2C17  mov    qword ptr [b],rax
// if ( ! b ) YY_FATAL_ERROR( ... )
0007FFFA75E2C1C  cmp    qword ptr [b],0
0007FFFA75E2C22  jne    yy_create_buffer+30h (07FFFA75E2C30h)
0007FFFA75E2C24  lea    rcx,[yy_chk+58h (07FFFA7646A28h)]
0007FFFA75E2C2B  call   yy_fatal_error (07FFFA75E3770h)
// b->yy_buf_size = size
0007FFFA75E2C30  mov    rax,qword ptr [b]
0007FFFA75E2C35  mov    ecx,dword ptr [size]
0007FFFA75E2C39  mov    dword ptr [rax+18h],ecx

谢谢!

【问题讨论】:

  • 我多次重新运行该段,malloc 要么返回 00000000-------- 要么返回 FFFFFFFF-------- 以获得“分配”空间的地址。
  • 很可能,其他一些看似无关的代码部分已经设法破坏了堆(例如,通过溢出堆分配的缓冲区)。您正在查看的代码部分是无辜的受害者。
  • 您的程序遇到堆损坏情况。你可以参考这篇文章的帖子:stackoverflow.com/a/22074401/2724703
  • 定义yy_flex_alloc的文件是否包含stdlib?如果不是,它很可能会将来自 malloc 的返回值视为一个 int 并且强制转换隐藏它。
  • @Art:定义yy_flex_alloc()的文件确实包含#include <stdlib.h>。该文件由 Flex 自动生成。

标签: c++ c visual-studio-2010 malloc flex-lexer


【解决方案1】:

真正的答案是:

当您在 Visual Studio 中编译 flex 生成的 .c 源代码时,它不包括 stdlib.h(其中 ma​​lloc 定义为返回 void*)和Visual Studio 有一些自己的定义,其中 ma​​lloc 返回 int。 (我认为这是为了某种兼容性)

Visual Studio 打印:

'警告 C4013:'malloc' 未定义;假设 extern 返回 int' sizeof(int)==4,但在 x64 系统上的指针值往往超过 4 个字节

所以你的指针只是减少到低 4 个字节。

这个问题似乎只出现在x64 bits Visual Studio 的.c 文件中。

因此,解决方案将是 - 只需自己包含 stdlib.h,或定义一些宏,这将导致 flex 生成的源代码包含 stdlib.h

【讨论】:

  • 我只能想象你用这个答案为我节省了多少小时。
  • 谢谢人质布莱恩和笑人(莫拉莱斯):很好的回答
  • 这绝对是我遇到的问题——在我挣扎了几乎一整天之后。非常感谢!
【解决方案2】:

在正常情况下 malloc() 将返回一个指向有效、可访问内存的指针,否则为 NULL。因此,您的症状表明 malloc() 的行为方式未指定。我怀疑,在早些时候,您的程序在其有效内存之外写入,从而破坏了 malloc() 内部使用的数据结构。

使用运行时内存分析工具检查您的进程应该可以帮助您确定问题的根源。 [有关 Windows 内存分析工具的建议,请参阅此帖子:Is there a good Valgrind substitute for Windows?]

【讨论】:

  • 谢谢,这是个好建议。一旦我可以安装兼容 Windows 8 的检漏仪,我就会对其进行调查……不过,我确实在该应用程序的 Linux 版本上运行了 Valgrind,而且似乎没有任何可疑之处。当这部分代码运行时,我只丢失了 4 个字节(由于我无法更改的库函数......)
猜你喜欢
  • 1970-01-01
  • 2017-02-28
  • 2021-08-29
  • 1970-01-01
  • 2015-05-06
  • 2013-06-04
  • 2012-02-27
  • 2011-08-09
  • 1970-01-01
相关资源
最近更新 更多