Bjo*_*ilt 5 c++ gcc valgrind c++11
我正在处理在raspberry pi 3上运行的代码.并且在我的日志记录类中遇到以下错误.
==1297== Invalid read of size 8
==1297== at 0x4865D1C: ??? (in /usr/lib/arm-linux-gnueabihf/libarmmem.so)
==1297== Address 0x4c8d45c is 100 bytes inside a block of size 107 alloc'd
==1297== at 0x4847DA4: operator new(unsigned int) (vg_replace_malloc.c:328)
==1297== by 0x49C3D9B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::reserve(unsigned int) (in /usr/lib/arm-linux-gnueabihf/libstdc++.so.6.0.22)
==1297== by 0x4AE65: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.tcc:1155)
==1297== by 0xF82B5: Log::Book::addField(std::unique_ptr<Log::Entry, std::default_delete<Log::Entry> >&, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (LogBook.cpp:149)
==1297== by 0xF7CCB: Log::Book::record(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long long, std::ratio<1ll, 1000000000ll> > >) (LogBook.cpp:87)
Run Code Online (Sandbox Code Playgroud)
GCC版本:gcc版本6.3.0 20170516(Raspbian 6.3.0-18 + rpi1 + deb9u1)
valgrind版本:valgrind-3.13.0
我似乎无法找到问题,因为函数Log :: Book :: record()通过pass-by-value获取它的价值.我还可以说在调用函数时并不总是显示此错误.从错误显示的线条和不在哪条线路的意义上来说,它是确定性的.任何人都可以指导我解决这个问题的方向和解决方案吗?下面的代码段,带有指示行的注释.
/** log message */
void Book::record(std::string file, const int line, const unsigned int level, Identifier id, const std::string message,
const std::chrono::high_resolution_clock::time_point timeStamp)
{
if (!(fileLevels & level) && !(consoleLevels & level)) { return; }
auto now = Time::keeper->now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(timeStamp - Time::globalEpoch);
//generate message
auto entry = std::make_unique<Entry>(level);
// Time since startup
addField(entry, 0, std::to_string(duration.count()));
//UTC Time
addField(entry, 1, now.dateTime());
// File
std::string stringFile;
if (!file.empty())
{
stringFile = URL{file}.lastPathComponent();
}
addField(entry, 2, stringFile);
//Line number
addField(entry, 3, std::to_string(line));
//ID
addField(entry, 4, id);
//Message
std::string stringMessage;
if(!message.empty())
{
addField(entry, 5, message); //this is line LogBook.cpp:87
}
else
{
addField(entry, 5, " empty message.");
}
*entry << ";";
//queue message
this->append(std::move(entry));
}
void Book::addField(std::unique_ptr<Entry> &entry, unsigned int index, const std::string &text)
{
std::string textOutput;
if ((spacings.at(index) != 0) && (text.length() > (spacings.at(index) - 1)))
{
spacings.at(index) = (uint8_t) (text.length() + 2);
}
entry->setWidth(spacings.at(index));
if(entry->empty())
textOutput = text;
else
textOutput = ";" + text; //This is line LogBook.cpp:149
if(!textOutput.empty())
(*entry) << textOutput;
}
Run Code Online (Sandbox Code Playgroud)
调用此函数的代码并发生此问题.
auto node = child(items, "item", index);
auto enabled = boolValue(node, "enabled", false);
auto file = pathValue(node, key::path);
auto name = stringValue(node, "name", "");
auto type = stringValue(node, "type");
CLOG(CLOG::WARNING, "Yard item " + name + " not enabled, path:" + file.path());
Run Code Online (Sandbox Code Playgroud)
更新1: 我用cmake编译选项.并添加了额外的选项.这些并没有解决问题.
add_compile_options(-ggdb)
add_compile_options(-O1)
#Extra disable vectorization
add_compile_options(-fno-tree-vectorize)
add_compile_options(-fno-tree-loop-vectorize)
add_compile_options(-fno-tree-slp-vectorize)
Run Code Online (Sandbox Code Playgroud)
更新2:
我发现了另一个使用字符串连接的地方,valgrind报告了相同的错误
更新3:
稍后的一些时间和有趣的发现.共享库libarmmem.so中发生错误.这会动态加载,因此总是在不同的地址上.发生错误时使用gdb和valgrind组合来中断.
gdb加载了带起始地址的共享库.
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x0483246c 0x04832750 Yes /usr/local/lib/valgrind/vgpreload_core-arm-linux.so
0x04846e60 0x04850c10 Yes /usr/local/lib/valgrind/vgpreload_memcheck-arm-linux.so
0x04863588 0x048672fc Yes (*) /usr/lib/arm-linux-gnueabihf/libarmmem.so
...
Run Code Online (Sandbox Code Playgroud)
valgrind报告错误.
==9442== Invalid read of size 8
==9442== at 0x4865D34: ??? (in /usr/lib/arm-linux-gnueabi/libarmmem.so)
Run Code Online (Sandbox Code Playgroud)
我们从libarmmem.so的readelf知道.text部分从588开始.这个memcpy位于710.这个断点上的反汇编显示我们在地址0x04863710的memcpy中.如果我们检查范围如下:0x04863588 - 0x04863710 = 188. 188 + 588(开始.text的地址)= 710.
反汇编显示它发生在装配线上.vldmia是加载向量浮点寄存器的指令.
0x04865d34 <+9764>: vldmia r1!, {d9}
Run Code Online (Sandbox Code Playgroud)
还没有解决方案.
最有可能的是 libarmem.so 内部的代码已经以这样的方式进行了向量化:它意识到只有在读取完整的 8 字节块之后才会有一个终止字符。这不会触发处理器异常(因为算法确保指针对齐并因此保持在同一页面中),但会导致 Valgrind 等工具报告误报。
随着时间的推移,此类问题变得越来越严重,导致 Valgrind 在实践中的用处越来越小。请参阅Valgrind 与优化编译器进行深入讨论,或查看diff 中的此错误以获取实际示例(或查看我的 Debian 抑制列表以获取更多示例)。
| 归档时间: |
|
| 查看次数: |
467 次 |
| 最近记录: |