【问题标题】:Buffer overflow in certain places only with compiler optimizations turned on仅在打开编译器优化的情况下某些地方的缓冲区溢出
【发布时间】:2015-07-24 18:41:29
【问题描述】:

所以我遇到了一个问题,即某段代码给了我这个错误*** BUFFER OVERFLOW DETECTED ***。这只是在我打开某些编译器优化选项后才开始发生(这不是我的程序,所以我必须使用这些)。我已经把它缩小到它是哪个选项。我还找到了一种阻止缓冲区溢出的方法,但是,我在程序的另一部分有非常相似的代码,当我保持原样时,不会给我同样的错误。这让我对我的修复感到非常困惑和非常不自信,因此我们将不胜感激。

这里是来自makefile的优化选项

CXXFLAGS+=-Os -O2 -fomit-frame-pointer 
CXXFLAGS+=-fno-aggressive-loop-optimizations

我已将其范围缩小到开始导致错误的 -O2 标志。

仅当指定了-O2 标志时,此函数在realpath() 处的缓冲区溢出时失败

static std::string getRealTargetPath (std::string baseTarget)
    {
    char nextTargetLink[MAXPATHLEN];
    memset (nextTargetLink, 0, MAXPATHLEN);

    if (realpath (baseTarget.c_str(), nextTargetLink) == NULL)
        return "";
    else
       //etc...
    }

如果我将MAXPATHLEN(size 1024) 更改为PATH_MAX(size 4096),上述函数将按预期运行。好,可以。但是,在使用 same std::string baseTarget 和以前一样之后,下面的 sn-p 代码执行了大约 20 行。

char realLinkPath[MAXPATHLEN];
memset (realLinkPath, 0, MAXPATHLEN);

do
    {         
    if (realpath (linkPath.c_str(), realLinkPath) != NULL)
        if (strcmp(linkPath.c_str(), realLinkPath) != 0)
            return true;

    size_t eraseFrom = linkPath.rfind('/');
    if (std::string::npos != eraseFrom)
        linkPath.erase(eraseFrom);
    } while ( !linkPath.empty() );

总而言之,即使这两个 realpath 函数使用相同的 const char* path 变量,如果缓冲区不是 PATH_MAX 长度,第一个将失败,但第二个不会,这一切都只发生在 @987654335为编译指定 @ 标志。

任何帮助将不胜感激,谢谢。

编辑:正如用户指出的那样,我也将其标记为 C,因为该程序非常旧,核心是用 C 编写的 许多C++ 功能

【问题讨论】:

  • 为什么还要使用C api?
  • 这个程序已经有 20 年的历史了,核心是用C 编写的,所以我希望它尽可能保持为“C”。
  • 什么是 MAXPATHLEN ? realpath() 记录了 2. 参数必须至少为 PATH_MAX。
  • 它不是导致缓冲区溢出的优化标志——该标志只是导致它被检测到。没有标志,溢出仍在发生,只是没有被检测到。溢出可能仍然会导致程序以其他方式(微妙地)产生垃圾结果。
  • @Olaf 问题的根源在于 C API,因此这与 C 同等相关。

标签: c++ c linux makefile compiler-optimization


【解决方案1】:

嗯,第二部分有不同的输入,所以它运行得很好偶然realpath() 是一个非常糟糕的功能,即使是 manpage 也指出(参见 BUGS)。

您可以做的最好的事情是重新编写代码,以便使用 null 指针作为第二个参数调用 realpath,并注意您返回的分配缓冲区是 free()d 正确

【讨论】:

  • 输入并没有什么不同,它们只是有不同的变量名。它们所包含的内容完全相同。
  • 好的,那么您必须查看汇编代码才能真正了解发生了什么,但我敢打赌问题的根源是realpath。此外,在堆栈上分配 PATH_MAX 字节是一个特别坏主意,这可能是一个巨大的数量。
  • 我选择这个作为接受的答案,因为我没有阅读手册页的错误部分。我回去后只是将NULL 的选项用作resolved_pathfree(),现在一切正常。
【解决方案2】:

realpath 的手册页指定resolved_path 的长度必须至少为 PATH_MAX。如果realpath 的结果是一个长度超过1024 字节的字符串,并且您的缓冲区不够大,那么您正在调用undefined behavior。这意味着崩溃可能(如第一种情况)或可能不会(如第二种情况)发生。

【讨论】:

  • 文档指定它将达到 PATH_MAX。该程序已经为比这短得多的路径设置了一个内部限制,因此永远不会达到长度,因为它会被更快地捕获。此外,“真实”路径只有 35 个字符长。
猜你喜欢
  • 1970-01-01
  • 2011-01-21
  • 2017-11-15
  • 2015-02-01
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 2014-10-05
  • 2018-04-06
相关资源
最近更新 更多