程序问答   发布时间:2022-06-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了与没有优化标志相比,memcpy 的行为与优化标志不同大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决与没有优化标志相比,memcpy 的行为与优化标志不同?

开发过程中遇到与没有优化标志相比,memcpy 的行为与优化标志不同的问题如何解决?下面主要结合日常开发的经验,给出你关于与没有优化标志相比,memcpy 的行为与优化标志不同的解决方法建议,希望对你解决与没有优化标志相比,memcpy 的行为与优化标志不同有所启发或帮助;

虑这个演示程序:

#include <String.h>
#include <unistd.h>

typedef struct {
    int a;
    int b;
    int c;
} mystruct;

int main() {
    int TOO_BIG = getpagesize();
    int SIZE = sizeof(mystruct);
    mystruct foo = {
        123,323,232
    };

    mystruct bar;
    memset(&bar,SIZE);
    memcpy(&bar,&foo,TOO_BIG);
}

我以两种方式编译:

  1. gcc -O2 -o buffer -Wall buffer.c
  2. gcc -g -o buffer_deBUG -Wall buffer.c

即第一次启用优化,第二次启用调试标志并且没有优化。

首先要注意的是编译时没有警告,尽管 getpagesize 返回的值会导致缓冲区溢出 @H_113_5@memcpy。

其次,运行第一个程序会产生:

*** buffer overflow detected ***: terminated
Aborted (core dumped)

而第二个产生

*** stack smashing detected ***: terminated
Aborted (core dumped)

或者,你必须在这里相信我,因为我无法用演示程序重现这一点,有时根本没有警告。该程序甚至不会中断,它正常运行。这是我在处理一些更复杂的代码时遇到的一种行为,这使得调试变得困难,直到我意识到发生了缓冲区溢出。

我的问题是:为什么有两种不同的行为具有不同的构建标志?为什么这在作为调试版本构建时有时执行时没有错误,但在使用优化构建时总是错误?

解决方法

在分配的内容后面访问内存是未定义的行为,这意味着编译器可以做任何事情。当没有优化时,编译器可能会尝试猜测并做一些合理的事情。当优化被打开时,编译器可能会利用这样一个事实,即允许任何行为做一些运行得更快的事情。

,

..我无法用演示程序重现这个,有时根本没有警告......

undefined behavior 指令非常广泛,编译器不需要为表现出这种行为的程序发出任何警告:

为什么有两种不同的行为具有不同的构建标志?为什么这在作为调试版本构建时有时不会出错,但在使用优化构建时总是出错?

编译器优化倾向于优化掉未使用的变量,如果启用优化的 I compile your code 我没有得到分段错误,查看程序集(上面的链接),您会注意到有问题的变量被优化掉了,并且 @H_113_5@memcpy 没有被调用,所以没有理由不编译成功,程序退出成功代码为 0,而如果不优化它,未定义的行为就会显现出来,程序退出代码 139,经典段错误退出代码。

@R_607_10264@看到的,这些结果与您的不同,这是未定义行为的特性之一,不同的编译器、系统甚至编译器版本可能会以完全不同的方式运行。

,

首先要注意的是编译时没有警告,尽管 getpagesize 返回的值会导致 memcpy 缓冲区溢出。

这是程序员的责任,而不是编译器。如果编译器设法为您找到潜在的缓冲区溢出,您将非常幸运。它的工作是检查您的代码是否是有效的 C,然后将其转换为机器代码。

如果您想要一个捕获错误的工具,它们被称为静态分析器,这是一种不同类型的程序。在某种程度上,静态分析可能作为一项功能集成到编译器中。 clang 有一个,但大多数静态分析器是商业工具,而不是开源工具。

其次,运行第一个程序产生:...而第二个产生

未定义的行为仅仅意味着没有定义的行为。 what is undefined behavior and how does it work?。这意味着从检查结果中不可能学到任何东西,也没有什么有趣的谜团需要解决。在一种情况下,它显然访问了禁止的内存,在另一种情况下,它破坏了一个可怜的小“堆栈金丝雀”。差异将与不同的内存布局有关。谁在乎 - 错误就是错误。专注于为什么发生错误(您已经知道了!),而不是试图理解未定义的结果。

现在,当我运行您的代码时实际上启用了真正的优化(gcc -O2 在 x86 Linux 上),编译器给了我

@H_113_5@main:
        subq    $8,%rsp
        call    getpagesize
        xorl    %eax,%eax
        addq    $8,%rsp
        ret

在实际启用优化后,它甚至不用调用 memcpy 和朋友,因为没有副作用并且没有使用变量,因此可以安全地从可执行文件中删除它们。

大佬总结

以上是大佬教程为你收集整理的与没有优化标志相比,memcpy 的行为与优化标志不同全部内容,希望文章能够帮你解决与没有优化标志相比,memcpy 的行为与优化标志不同所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签:memcpy