和vs版本关系_栈局部变量优化探究,意外发现了 vs 的一个 bug ?

缘起

我在《栈又溢出了》一文中记录了一个奇怪的栈溢出问题。虽然解决了,但是总感觉哪里不太合理。我想,vs 一定有一个合理的设置。一起折腾起来吧!

查找工程设置

本以为能找到某个编译选项对局部变量占用内存的行为进行控制。看遍了工程设置也没发现相关的设置项。release 版会不会有什么不同呢?毕竟,release 版会做一些优化,于是抱着试试看的心态编译了 release 版。您猜怎么着,居然没崩溃!

反汇编

赶紧查看下相关的反汇编,果然和预想的一样,函数局部变量占用的栈空间不再是 debug 版中的 0x12C0DC,而是 0x064008。换算成十进制大概是 409608。

bd573ccf74066fb43b8bb61f548f2ed3.png

这说明三个局部变量被优化成了一个!release 优化果然给力!但是具体是哪一项优化导致的呢?该怎么排查呢?debug 版和 release 版结果不一样,最简单粗暴的方法就是找不同!

对比设置

把 debug 版的配置保存到 debug.txt,release 版的配置保存到 release.txt。然后用 beyond compare 比较两个文件的内容。

1d93c2c3211e22b2d8a370ee4b804eb0.png

为了让各位小伙伴儿更清晰的对比 debug 和 release 的区别,我特意调整了先后顺序,把不同的选项放到了后面!最重要的不同在最后一行。

debug 版为 /ZI /Gm /Od /RTC1 /MDd,release 版为 /Zi /GL /Gy /Gm- /O2 /Oi /MD。

不知道大家熟悉哪几个,我比较熟悉 /Od (禁用优化,debug 版的默认配置)和 /O2 (使速度最大化,release 版的默认配置)。

21f88932ec7e070fc9c842a2b07520ac.png
先把 /Od改成 /O2试试,没想到提示错误 error D8016: “/ZI”和“/O2”命令行选项不兼容。那就把 /ZI改成 /Zi。

说明:/Zi 和 /ZI 都是用来配置生成调试符号的,与当前调查的问题基本没什么关系。使用 /ZI 生成的符号文件可以支持编辑并继续运行,低版本的 vs 对编辑并继续运行的功能支持的并不好,一般 /Zi 就好。

76f162056cd5a264cae82a758964acdc.png

改好后,继续编译。没想到又遇到了如下错误:error D8016: “/O2”和“/RTC1”命令行选项不兼容。改成默认值,和 release 一样的设置。

fa7b7f87f24e20e464d597bd7e305f7e.png
再次编译,这次终于编译通过了。再次运行 debug版的程序,不报栈溢出了。赶紧查看反汇编确认,传给 _chkstk的大小不再是之前的 0x12C0DC了,而是 0x064004,转换成十进制是 409604。
bbe97715025f9905c9f407c4d1aa1759.png

如果把 release 版的 /O2 改成 /Od,release 版会不会也报栈溢出呢?

让 release 版也报栈溢出

说干就干,改好配置后编译,运行。果然,栈溢出了。

dbd0ac6f77af4369888571214ab7f946.png

至此,基本上找到了关键的编译选项—— /O2。但这就完了么?

/O2

在 google 中输入 /O2 msdn ,回车。第一条搜索结果就是 /O2 的官方文档[1]。看看 /O2 都做了哪些优化。

6b13882318562d92bfca5d681404484c.png
原来,/O2相当于设置了这么多选项,到底是哪一个在起作用呢?一共才 7个,不多,挨个试!恢复 debug版的优化选项为 /Od。然后添加额外选项。先试 /Og。
937369430b6532849a529ea4d4c3f901.png

没想到运气这么好,一下就猜中了。这里就不放运行结果图了。

再查看下/Og 的官方文档[2]。这里截取部分关键描述。

4186cf0c7da32064eda26c2573ef5f25.png

如何快速得到编译选项?

可以在工程上 右键,属性,配置属性,c/c++,命令行 来快速找到所有编译选项。如下图:45a4ed6342acf1326f2e729e16c14eec.png

vs2013 的 bug?

为了更好的理解栈局部变量优化策略,我准备了很多测试用例,其中有一个用例结果出乎意料!我把代码和结果贴出来。我想这应该是 vs2013 的一个 bug。

#include "stdafx.h"

struct BigData
{
    char data[400 * 1024];
};

struct BigData1 : public BigData
{
    int data1;
};

struct BigData2 : public BigData1
{
    int data2;
    BigData1 bigData;
};

void Use(BigData* pData) { printf("%c", pData->data[0]); }
void CorrpuptStackEasyly(int argc){
    auto size = sizeof(BigData2);
    printf("size is %d", (int)size);

    if (argc == 1)
    {
        BigData data;
        Use(&data);
    }
    else if (argc == 2)
    {
        BigData1 data;
        Use(&data);
    }
    else
    {
        BigData2 data;
        Use(&data);
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
    CorrpuptStackEasyly(argc);
    return 0;
}

BigData2 的大小应该是 819212,但是传递给 _chkstk 的值却是 1228824。看下图就知道我没瞎说。

1f256e44e2941c4ea99dec29400cb095.png

这真的是 vs2013 的 bug 吗?同样的代码在高版本的 vs 中会是什么结果呢?vs2019 太大了,我的 c 盘已经爆红了,不想装了。偶然发现了一个超级宝藏网址,可以查看源代码被不同编译器编译后的汇编代码,真是宝藏啊。

宝藏网址

这个宝藏网址是 https://gcc.godbolt.org/。上面的代码的编译结果如下图:

3c7c599c615a20592b5c2f79bbc007e6.png

符合预期!看来这的确是 vs2013 的一个 bug了!

总结

  • debug 和 release 之所以不同,是因为设置了不同的选项。
  • 可以在所有选项下搜索对应的设置选项来快速定位某个设置。
  • /Og 可以消除不必要的局部变量,从而避免上文中的栈溢出问题。

References:

[1]

/O2 的官方文档: https://docs.microsoft.com/en-us/cpp/build/reference/o1-o2-minimize-size-maximize-speed?view=msvc-160

[2]

/Og 的官方文档: https://docs.microsoft.com/en-us/cpp/build/reference/og-global-optimizations?view=msvc-160

感谢你的分享,点赞和在看5170a1985ceb90a9d328b017d093c5ee.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/news/267923.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Visual C++ 时尚编程百例009(响应键盘)

按钮消息WM_KEYDOWN,WM_CHAR,WM_KEYUP在CXXXDoc.h中添加变量CString Text;在构造函数中初始化Cvc1001Doc::Cvc1001Doc(){ // TODO: 在此添加一次性构造代码 Text_T("");}右击CXXXView类->属性->消息->WM_CHARvoid Cvc1001View::OnChar(UINT nChar, UINT nRe…

在ubuntu 16.04上安装tensorflow,并测试成功

用下面代码测试安装: 1 #! /usr/bin/python2 # -*- coding: utf-8 -*-3 4 import tensorflow as tf5 import numpy6 import matplotlib.pyplot as plt7 rng numpy.random8 9 learning_rate 0.01 10 training_epochs 1000 11 display_step 50 12 #数据集x 13 tra…

redis客户端连接数量_实战解析无所不知的Redis拓展应用——Info,进阶学习,无所不能...

前言学习是一个持续的过程。像咱们一直在更新的Redis学习内容,由基础结构,到原理应用,再到集群搭建,了解的够充分了,咱们接着又介绍Redis拓展应用,将知识面拓宽,毕竟技术都是相通的,…

诡异的防火墙故障,能PING通,但访问ORACLE不稳定

上周四我们的IDC核心数据区到DMZ区的防火墙经历了十分诡异的故障。 虽然我从一开始就断定非ORACLE问题,因为连接核心数据区的多个ORACLE数据库的应用都无一例外的出现了相同的问题,如果三个以上ORACLE能同时出想这么严重的问题,那么我想ORACL…

【Excle数据透视】如何用含有单元格的数据来创建数据透视

取消合并单元格,填充相同内容项,然后创建数据透视表. 如下图:需要使用数据创建数据透视表 步骤一 开始→格式刷,然后对单元格区域G2:G15使用格式刷功能,保留合并单元格格式 步骤二 选中A2:A18区…

css 超出文字头尾相接滚动_前端的一些雕虫小技,从100%和滚动条说起

1、100%和滚动条当我们在css中把html和body同时设为100%时,会出现滚动条html,body {width: 100%;height: 100%;}原因是html和body之间有8px的margin,这个margin怎么来的呢,我们在chrome中用F12看一下这个8px的margin来自于user agent stylesh…

[转] C# 路径(目录)

一、获取当前文件的路径1. System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName获取模块的完整路径,包括文件名。2. System.Environment.CurrentDirectory获取和设置当前目录(该进程从中启动的目录)的完全限定目录。3. System.IO.Directory.GetCur…

《大鱼海棠》

我告诉你什么事最可悲,你遇见一个人,犯了一个错,你想弥补想还清,到最后才发现,你根本无力回天,犯下的罪过永远无法弥补转载于:https://www.cnblogs.com/ting6/p/9726163.html

class参数传入 python_小白学 Python 爬虫(20):Xpath 进阶

人生苦短,我用 Python如果我的文章对您有帮助,请关注支持下作者的公众号:极客挖掘机,您的关注,是对小编坚持原创的最大鼓励:)前文传送门:小白学 Python 爬虫(1):开篇小白学 Python 爬…

shellcode

Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。 另外,Shellcode一般是作为数据发送给受攻击服务的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它…

小学生都能看懂的FFT!!!

小学生都能看懂的FFT!!! 前言 在创新实践中心偷偷看了一天FFT资料后,我终于看懂了一点。为了给大家提供一份简单易懂的学习资料,同时也方便自己以后复习,我决定动手写这份学习笔记。 食用指南: …

ComboBox自动补全小技巧

网上看的自动补全实在是太麻烦,有时候还用到了第三方控件,但是现在我的需求是这样的 有一个Person类,其中有Code、Name两个属性 Person需要绑定到ComboBox中,在ComboBox中输入Code时,即自动补全相应的Name 想了半天&am…

可做fft分析吗_小吃店生意好做吗,小吃业行情分析

现在创业已经成为一种风尚,不少创业者都打算开一家小吃店,现在小吃店的生意好做吗?开小吃店有没有前景呢?中国人一直以来都非常看重“吃”,民以食为天,食物就是中国人生存的灵魂所在。基本上每个城市、每个…

SVN版本回滚

新入职的公司居然还是用的SVN管理代码,需要版本回滚,弄了半天,顺便记录一下。 当前的最新版本号是1470,其中1467到1470这几个提交都要被移除时,在项目文件夹下使用下面的代码: svn merge -r 1470:1466 . 这…

ase加密放linux报错_Linux应用安装有福啦!和苹果Mac一样方便的单文件安装

自从用了苹果macbook,和windows基本上就再见了,苹果系统的稳定性太出色了,使用完合上盖子放十天半个月的没一点问题,一叫就醒,一醒就能接着工作,windows系统不行,要么睡了叫不醒,要么…

我的软考之路——软考心得

软考?是什么东西,可能大多数人跟我一样,刚听到这个词语觉得很陌生,但当我走进社会,面临到工作的压力,要求自己必须学习进步的时候,认识了它! 那时候参加工作也几年了,工作的压力是…

拼图展示

转载于:https://www.cnblogs.com/zm1994/p/8033332.html

[转载]TopCoder兼职赚钱入门(Part. 1)

原文地址:【原创】TopCoder兼职赚钱入门(Part. 1)作者:汪昊成最近找我问TC的朋友越来越多,于是就想写一个入门教程放在这里。对我来说,TC目前是总收入的一个重要组成部分,虽然不如工资多&#x…

c++全局监听ctrl s_号称史上最全!134个CAD快捷键强烈来袭,难道你只知道Ctrl+C?...

想要提高CAD绘图速率你就必须熟记CAD快捷键,小编盘点了134个CAD个快捷键,号称史上最全,一起来看看吧。一、常用字母键CO:复制MI:镜像AR:阵列O:偏移RO:旋转M:移动E&#x…

51nod 1623 完美消除(数位DP)

首先考虑一下给一个数如何求它需要多少次操作。 显然用一个单调栈就可以完成:塞入栈中,将比它大的所有数都弹出,如果栈中没有当前数,答案1。 因为数的范围只有0~9,所以我们可以用一个二进制数来模拟这个栈,…