[这是冗长而充满细节的。我的具体问题由下面的粗体字问题引入。]
摘要
我们正在valgrind下运行一些测试套件,遇到一个对我来说没什么意义的错误。我正在寻找有关更详细地弄清可能出错的建议。
所有这些都闻起来好像真正的问题在其他地方:某些事情正在变得腐败并导致后来的混乱。但这是第一个问题valgrind报告,所以如果在别处有内存踩踏,那么valgrind就无法捕获它。我怀疑要么我错过了一些明显的东西,要么就是有一个微妙的问题,那些具有比我更有专业知识的人可能能够指出我。
一些细节
以下是一些细节和一些具体问题。
这是在x64硬件上运行Ubuntu 14.04的Linux机器上。
在一个相当典型的例子中,这是valgrind的抱怨:
==14259== Invalid write of size 8
==14259== at 0x662BBC9: __printf_fp (printf_fp.c:663)
==14259== by 0x6629792: vfprintf (vfprintf.c:1660)
==14259== by 0x664D578: vsnprintf (vsnprintf.c:119)
==14259== by 0x52DCE0F: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==14259== by 0x52E3263: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==14259== by 0x52E354F: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==14259== by 0x52EEAF4: std::ostream& std::ostream::_M_insert<double>(double) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==14259== by 0x694725: CRVinfo::appendValue(std::string const&, double) (CRVinfo.cpp:197)
==14259== by 0x6902DB: CRVdouble::info(CRVinfo&) const (CRVdouble.cpp:103)
==14259== by 0x6913B4: CRVcollection::info(CRVinfo&) const (CRVcollection.cpp:60)
==14259== by 0x6913B4: CRVcollection::info(CRVinfo&) const (CRVcollection.cpp:60)
==14259== by 0x68F87F: CRVvalue::generate() (CRVvalue.cpp:71)
==14259== Address 0xffeffde68 is on thread 1's stack
==14259== in frame #0, created by __printf_fp (printf_fp.c:161)
以&#34; CRV&#34;开头的事情是我们的;他们上面的东西都在libstdc ++和glibc中。 Ubuntu 14.04使用glibc的2.19版本 - 除了实际上它似乎使用了eglibc 2.19而不是普通的glibc 2.19;你可以找到printf_fp.c here的相关版本。
使用--vgdb
运行valgrind并向gdb请求反汇编声明(与上面链接的源代码一致),当valgrind阻止我们时,我们实际执行的指令是callq __mpn_lshift
。< / p>
最顶层的堆栈框架涉及&#34;我们的&#34;代码如下所示:
void CRVinfo::appendValue(const std::string &name, double value){
addIndent();
addElementBegin(name);
std::ostringstream oss;
oss << value;
m_valueTree.append(oss.str());
addElementEnd(name);
}
并且oss << value;
内部发生了麻烦。 m_valueTree
是std::string
;你可以猜出addIndent
和addElementBegin
做了什么;后者使用字符串流来做,前者没有。 (可能不相关的说明:你可能认为这看起来效率低下而且你是对的,但这根本不是性能关键的代码。)
因此,无论如何,我们在callq
指令上的地址0xffeffde68处获得大小为8的无效写入。您希望callq
写入rsp
指向的内存,所以它确实(我已经验证此时rsp
等于0xffeffde68)...但是valgrind对象对此,我不清楚为什么。
(一个明显的猜测可能是我们的堆栈溢出了。但是(1)我认为这会发生在一个看起来更圆的地址上,并且(2)我试图增加堆栈大小并没有使这些valgrind投诉消失,并且(3)我预计会溢出堆栈并且不会发生的段错误,并且(4)我们还没有使用太多无论如何都在这一点堆叠;在我能够探测到的最早点,rsp
是0xfff000598,所以我们在失败时使用的堆栈少于10k。)
问题:我应该明白什么 valgrind对象写这个?如果没有,有没有办法让valgrind告诉我更多关于它为什么不喜欢它?
问题:这里的直接问题是valgrind中的错误(虽然可能是由我们代码中的一些早期错误行为引起的),这是否合理?如果是这样,有没有什么好方法可以追踪这些事情或排除它们?
问题:这看起来像glibc或libstdc ++的任何已知问题? (到目前为止,我所做的网络搜索还没有发现任何此类已知问题。)
有用的更多信息
如果我在执行此无效写入后允许执行继续执行,那么valgrind会在此处调用的__mpn_lshift
函数内投诉大小为8的无效读取。&#39 ;从同一地址读取并在gdb中进行反汇编表明,retq
__mpn_lshift
结尾的--max-stacksize
指令不足为奇。
我的堆叠框架似乎都不是很大。 Valgrind并不抱怨大堆栈帧,询问堆栈是否已移动,建议增加__printf_fp
或类似的任何东西。
在另一台gcc版本略有不同的机器上,可能还有不同版本的标准库,valgrind再次在mov
中报告了大小为8的无效写入,但在其中的不同部分,这次在呼叫指令上不。 (不幸的是,这是在同事的计算机上,因为我们观察到这一点,所以有一些变化使他的版本显示出与我相同的失败,所以我无法提供任何信心的更多细节。但我和#39; m 95%确定在{{1}}指令上发生了故障,并严格写入当前堆栈帧。)