草庐IT

c++ - 为什么 GCC 生成的代码会从堆栈中读取垃圾?

coder 2024-02-04 原文

考虑以下代码(使用 Eigen ):

#include <Eigen/Dense>
#include <iostream>

template<int rows, int cols, int row, class R, class Rv, int N, class... Rs>
inline typename std::enable_if<sizeof...(Rs)==0>::type
    setRow(Eigen::Matrix<R,rows,cols>&)
{}

template<int rows, int cols, int row, class R, class Rv, int N=0, class... Rs>
inline typename std::enable_if<sizeof...(Rs)==cols-N-1>::type
    setRow(Eigen::Matrix<R,rows,cols>& m, Rv val, Rs...args)
{
    m(row,N)=val;
    setRow<rows,cols,row,R,Rv,N+1>(m,args...);
}
template<class T, int R, int C, int CUR_ROW>
class MatrixConstructor
{
    Eigen::Matrix<T,R,C> m;
public:
    MatrixConstructor(const Eigen::Matrix<T,R,C>& m)
        : m(m)
    {}
    MatrixConstructor()
    {}
    template<class...Ts>
    typename std::enable_if<sizeof...(Ts)==C && CUR_ROW<R-1,
    MatrixConstructor<T,R,C,CUR_ROW+1>>::type operator()(Ts... vals)
    {
        setRow<R,C,CUR_ROW>(m,vals...);                                                                                                                                                                                 
        return MatrixConstructor<T,R,C,CUR_ROW+1>(m);
    }

    template<class...Ts>
    typename std::enable_if<sizeof...(Ts)==C && CUR_ROW==R-1,
    Eigen::Matrix<T,R,C>>::type operator()(Ts... vals)
    {
        setRow<R,C,CUR_ROW>(m,vals...);
        return m;
    }
};

void test()
{
    Eigen::Matrix<double,4,3> m=MatrixConstructor<double,4,3,0>()(1,2,3)
                                                                 (4,5,6)
                                                                 (7,8,9)
                                                                 (5,4,3);
    std::cout << m;
}

int main()
{ test(); }

我使用 gcc-4.8 编译它,并进行了全面优化和生成汇编列表的选项。这是我使用的命令:

g++ minitest.cpp -I/usr/include/eigen3 -std=c++0x -O3 -march=native -S -masm=intel

(我的 CPU 是运行 64 位 Linux 系统的 Intel(R) Xeon(R) CPU E3-1226 v3 — 希望现在 -march=native 对读者有意义。)

让我奇怪的是,用这个命令行生成的一些指令似乎是无意义的,甚至是多余的。参见例如test() 函数如何在设置堆栈后启动(有关 test()main() 的完整代码,请参阅 here ) :

vmovsd   xmm4, QWORD PTR .LC6[rip] # 1.0
lea      rsi, [rsp+96]
vmovsd   xmm5, QWORD PTR .LC7[rip] # 2.0
vmovsd   QWORD PTR [rsp], xmm4
vmovapd  xmm3, XMMWORD PTR [rsp+16] # What does it read?!
vmovapd  xmm1, XMMWORD PTR [rsp]    # And this!
vmovsd   QWORD PTR [rsp+32], xmm5
vmovsd   xmm0, QWORD PTR .LC8[rip] # 3.0
vmovapd  XMMWORD PTR [rsp+304], xmm3 # And now even save this junk?!
vmovapd  XMMWORD PTR [rsp+192], xmm1
vmovapd  xmm3, XMMWORD PTR [rsp+48]
vmovapd  xmm1, XMMWORD PTR [rsp+32]
vmovsd   QWORD PTR [rsp+64], xmm0
vmovsd   xmm7, QWORD PTR .LC12[rip] # 7.0
vmovapd  XMMWORD PTR [rsp+336], xmm3
vmovapd  XMMWORD PTR [rsp+224], xmm1
vmovapd  xmm3, XMMWORD PTR [rsp+80]
vmovsd   QWORD PTR [rsp+304], xmm7   # Even stranger — overwrites the junk

我已经在调试器中逐步读取了这些垃圾数据,并确认在它们之后 xmm3xmm1 寄存器确实具有无意义的值。看着这个未定义值的读取,我开始怀疑我的程序确实试图访问一些应该无法访问的内存。但为什么?我在某处引入了 UB 吗?

我也试过运行用 -fsanitize=address 编译的程序,但它没有任何崩溃。

最佳答案

您的代码执行以下步骤:

  1. 使用未初始化的 Eigen::Matrix 成员创建未初始化的 MatrixConstructor 对象
  2. 设置一行 Eigen::Matrix 成员
  3. 创建一个新的 MatrixConstructor 对象,其 Eigen::Matrix 成员使用旧 MatrixConstruction 对象的 Eigen::Matrix 成员初始化

因此,在第 3 步中,您将复制仅设置了第一行的 Eigen::Matrix 对象。对象的其余值仍未初始化。由于这些都是临时对象,它们都分配在堆栈中,因此您看到从堆栈中读取垃圾也就不足为奇了。

请注意,这假定 Eigen::Matrix() 构造函数未初始化对象,从快速查看源代码来看,默认情况下它似乎没有这样做。

关于c++ - 为什么 GCC 生成的代码会从堆栈中读取垃圾?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31073782/

有关c++ - 为什么 GCC 生成的代码会从堆栈中读取垃圾?的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  3. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  4. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  7. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  8. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  9. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  10. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

随机推荐