【问题标题】:valgrind: invalid writevalgrind:无效写入
【发布时间】:2011-08-26 14:24:06
【问题描述】:

在以下代码中:

void ResourceFitter::copyToLarvalResources( const gsl_vector* input ){
    assert( input->size == invLarvalResources.size() );
    if( invLarvalResources.size() != 365 ){
        cout<<"error: iLR.size(): "<<invLarvalResources.size()<<endl;
        exit(21);
    }
    // inverting larval resources may help fitting algorithm, so we do that here:
    for( size_t i=0; i<invLarvalResources.size(); ++i ){
        if( i >= 365 ){
            cout<<"error: i="<<i<<endl;
            exit(22);
        }
        double val = gsl_vector_get( input, i );
        invLarvalResources[i] = 1.0 / val;
    }
}

这是来自 ResourceFitter.cpp 的几行代码。第 380 行是最后一行代码(在 invLarvalResources 中赋值)。 invLarvalResources 是vector&lt;double&gt;

valgrind 抱怨:

==30152== Invalid write of size 8
==30152==    at 0x8ED3E5: OM::Transmission::Vector::ResourceFitter::copyToLarvalResources(gsl_vector const*) (ResourceFitter.cpp:380)
==30152==    by 0x8ECE99: OM::Transmission::Vector::ResourceFitter::sampler(gsl_vector const*) (ResourceFitter.cpp:334)
==30152==    by 0x8EB64D: OM::Transmission::Vector::ResourceFitter_minimise_sampler(gsl_vector const*, void*) (ResourceFitter.cpp:88)
==30152==    by 0x4F3249A: ??? (in /usr/lib/libgsl.so.0.16.0)
==30152==    by 0x8ED5C4: OM::util::MultidimMinimiser::MultidimMinimiser(gsl_multimin_fminimizer_type const*, unsigned long, double (*)(gsl_vector const*, void*), void*, gsl_vector*, gsl_vector*) (MultidimSolver.h:71)
==30152==    by 0x8EC45E: OM::Transmission::Vector::ResourceFitter::fit(unsigned long, OM::Transmission::Vector::ResourceFitter::FitMethod, unsigned long) (ResourceFitter.cpp:217)
==30152==    by 0x8EC308: OM::Transmission::Vector::ResourceFitter::fit() (ResourceFitter.cpp:183)
==30152==    by 0x8E474F: OM::Transmission::Vector::SpeciesModel::init2(unsigned long, std::list<OM::Host::Human, std::allocator<OM::Host::Human> > const&, int, double) (SpeciesModel.cpp:393)
==30152==    by 0x8DA29E: OM::Transmission::VectorModel::init2(std::list<OM::Host::Human, std::allocator<OM::Host::Human> > const&, int) (VectorModel.cpp:163)
==30152==    by 0x81C08F: OM::Population::createInitialHumans() (Population.cpp:165)
==30152==    by 0x8172E8: OM::Simulation::start() (Simulation.cpp:120)
==30152==    by 0x816615: main (openMalaria.cpp:53)
==30152==  Address 0x8ca3d10 is 0 bytes inside a block of size 2,920 free'd
==30152==    at 0x4C2658C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30152==    by 0x822515: __gnu_cxx::new_allocator<double>::deallocate(double*, unsigned long) (new_allocator.h:98)
==30152==    by 0x81FDBB: std::_Vector_base<double, std::allocator<double> >::_M_deallocate(double*, unsigned long) (stl_vector.h:156)
==30152==    by 0x81FC98: std::_Vector_base<double, std::allocator<double> >::~_Vector_base() (stl_vector.h:142)
==30152==    by 0x81E82B: std::vector<double, std::allocator<double> >::~vector() (stl_vector.h:351)
==30152==    by 0x8DB5D2: OM::Transmission::Vector::MosqLifeCycleParams::~MosqLifeCycleParams() (in /home/dhardy/code/openmalaria/build-debug/openMalaria)
==30152==    by 0x8DBA24: OM::Transmission::Vector::MosquitoTransmission::~MosquitoTransmission() (in /home/dhardy/code/openmalaria/build-debug/openMalaria)
==30152==    by 0x8E4719: OM::Transmission::Vector::SpeciesModel::init2(unsigned long, std::list<OM::Host::Human, std::allocator<OM::Host::Human> > const&, int, double) (SpeciesModel.cpp:391)
==30152==    by 0x8DA29E: OM::Transmission::VectorModel::init2(std::list<OM::Host::Human, std::allocator<OM::Host::Human> > const&, int) (VectorModel.cpp:163)
==30152==    by 0x81C08F: OM::Population::createInitialHumans() (Population.cpp:165)
==30152==    by 0x8172E8: OM::Simulation::start() (Simulation.cpp:120)
==30152==    by 0x816615: main (openMalaria.cpp:53)

调试行 (cout

那么 valgrind 在这方面是完全错误的还是发生了其他事情?在没有 valgrind 的情况下运行我没有遇到这个问题,但是我确实得到了一个奇怪的数值结果,这在独立的单元测试中是找不到的。在解决另一个错误之前,我还遇到了一个 SIGSEGV(我有把握地确定不应该导致 SIGSEGV)。

Build-flags 是 -g -rdynamic,编译器是 gcc 4.6.1 via ccache。如果你想要完整的资源,我很乐意为你指出:svn co http://openmalaria.googlecode.com/svn/branches/vec-lifecycle

任何帮助将不胜感激!

【问题讨论】:

  • 我个人从未见过 Valgrind 错了
  • 可以gsl_vector_get修改i的值吗?这段代码是多线程的吗?
  • 也许没有错误,但它可能会产生误导,因为它不一定会检测到对分配内存的错误写入。
  • @Matthieu:没有(i 是按值传递的),没有。
  • 你能显示 SpeciesModel.cpp:391 周围的线条吗? valgrind 声称 OM::Transmission::Vector::MosquitoTransmission::~MosquitoTransmission 是从那里调用的(表明 MosquitoTransmission 类及其内容的破坏)。

标签: c++ gcc valgrind


【解决方案1】:

你已经得到了相当多的代码......

快速浏览一下就会发现invLarvalResourcesMosqLifeCycleParams 拥有的vector引用

发生的事情是您将MosquitoTransmission 按值 传递给您的ResourceFitter 构造函数。 当该对象被销毁时——即构造函数一返回——它就会销毁它的MosqLifeCycleParams,而它又恰好拥有你刚刚存储了一个引用的向量。
欢闹随之而来。

您需要更加小心引用和所有权(包括您将非常量引用返回到私有变量的习惯。这使得它们实际上是公开的。)

道德:当您认为自己在工具中发现了错误时,很可能是您的代码中存在错误。

【讨论】:

  • 哇!我花了 20 分钟看这个,才发现 molbdnilo 得出的结论和我一模一样。我真的以为我会是唯一一个费心去努力的人。 (今天工作很慢)。
  • 哇,想想添加两个字符解决了这个问题(嗯,内存之一)。谢谢你们!
  • ——不,我不认为这是 valgrind 中的错误,只是它不能总是找到问题的根源。我认为在将对象传递给函数时应该小心谨慎;这不是第一次意外复制咬我(默认通过 const 引用传递任何人?)
【解决方案2】:

valgrind 有时可能会出错,但主要是关于内存泄漏。

在您的情况下,您很可能遇到内存处理错误。不幸的是,我不确定是否可以仅使用您发布的示例代码来回答。

基本上,valgrind 抱怨您的程序试图将 8 个字节的数据写入一个“最近”以某种方式被释放的位置。

这是输出列表中的第一个 valgrind 错误吗?如果不是,请尝试关注您收到的第一个 valgrind 错误/警告:就像编译器输出一样,最后一个错误通常是第一个错误的结果,有时是在完全不同的地方。

当心“未初始化值”警告,这些警告有时看似无害,但实际上可能会导致您出现最奇怪的错误。

祝你好运:)

【讨论】:

  • 是的,这是第一个 valgrind 错误报告。对我来说,这个数组被释放似乎有点奇怪——这不应该发生在向量上。我在 STL 向量中存储了一些稍微复杂的类,但是我相信在向量中存储向量应该是安全的?
  • 你没有一个向量你有一个向量的reference,而它所指的东西已经被破坏了。
  • 是的,一个我认为不应该被销毁的向量的引用。正如您所指出的,引用了错误的副本。
【解决方案3】:

在 SpeciesModel.cpp 的第 391 行,您正在以某种方式(可能是间接地)销毁 MosquiteTransmission 类型的对象,如下所示:

OM::Transmission::Vector::MosquitoTransmission::~MosquitoTransmission() (in /home/dhardy/code/openmalaria/build-debug/openMalaria)
by 0x8E4719: OM::Transmission::Vector::SpeciesModel::init2(unsigned long, std::list<OM::Host::Human, std::allocator<OM::Host::Human> > const&, int, double) (SpeciesModel.cpp:391)

然后你会以某种方式将此对象传递给函数,如下所示:

by 0x8E474F: OM::Transmission::Vector::SpeciesModel::init2(unsigned long, std::list<OM::Host::Human, std::allocator<OM::Host::Human> > const&, int, double) (SpeciesModel.cpp:393)

这可能是由于过时的引用、指针或迭代器。

注意:

  • valgrind 有时无法完全正确地获取行号。确保使用 -ggdb3 编译并使用非常 revent (svn) valgrind 版本。一个好方法是使用 --db-attach 选项,它会让你进入 gdb 来检查你的进程
  • 对向量进行更改容量的操作将使迭代器、引用和指向向量中元素的指针无效。

【讨论】:

    猜你喜欢
    • 2014-08-04
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 2016-07-23
    相关资源
    最近更新 更多