[Lldb-commits] [PATCH] D75200: AddressSanitizer failure in MemoryCache
Paolo Severini via Phabricator via lldb-commits
lldb-commits at lists.llvm.org
Wed Feb 26 11:04:37 PST 2020
paolosev created this revision.
paolosev added reviewers: labath, vsk, JDevlieghere, clayborg.
paolosev added a project: LLDB.
Herald added subscribers: lldb-commits, sunfish, aheejin.
The original discussion for this issues is here <https://reviews.llvm.org/D72751#1892647>.
The lldb sanitized bot is flagging a container-overflow error after we introduced test `TestWasm.py`:
http://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake-sanitized/992/testReport/junit/lldb-api/functionalities_gdb_remote_client/TestWasm_py/
11283==ERROR: AddressSanitizer: container-overflow on address 0x615000016184 at pc 0x00010b4608f0 bp 0x7ffee4f00130 sp 0x7ffee4eff8f8
-------------------------------------------------------------------------------------------------------------------------------------
READ of size 512 at 0x615000016184 thread T0
#0 0x10b4608ef in __asan_memcpy+0x1af (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x418ef)
#1 0x1116486d5 in lldb_private::MemoryCache::Read(unsigned long long, void*, unsigned long, lldb_private::Status&) Memory.cpp:189
#2 0x11119d0e9 in lldb_private::Module::GetMemoryObjectFile(std::__1::shared_ptr<lldb_private::Process> const&, unsigned long long, lldb_private::Status&, unsigned long) Module.cpp:298
#3 0x11169eeef in lldb_private::Process::ReadModuleFromMemory(lldb_private::FileSpec const&, unsigned long long, unsigned long) Process.cpp:2402
#4 0x11113337b in lldb_private::DynamicLoader::LoadModuleAtAddress(lldb_private::FileSpec const&, unsigned long long, unsigned long long, bool) DynamicLoader.cpp:212
#5 0x111ed53da in lldb_private::process_gdb_remote::ProcessGDBRemote::LoadModuleAtAddress(lldb_private::FileSpec const&, unsigned long long, unsigned long long, bool) ProcessGDBRemote.cpp:4767
#6 0x111ed59b8 in lldb_private::process_gdb_remote::ProcessGDBRemote::LoadModules() ProcessGDBRemote.cpp:4801
#7 0x1119c59aa in lldb_private::wasm::DynamicLoaderWasmDYLD::DidAttach() DynamicLoaderWasmDYLD.cpp:63
#8 0x1116a3a97 in lldb_private::Process::CompleteAttach() Process.cpp:2930
#9 0x1116a6bdf in lldb_private::Process::ConnectRemote(lldb_private::Stream*, llvm::StringRef) Process.cpp:3015
#10 0x110a362ee in lldb::SBTarget::ConnectRemote(lldb::SBListener&, char const*, char const*, lldb::SBError&) SBTarget.cpp:559
There is actually a problem in the MemoryCache code. From ProcessGDBRemote::LoadModules we read the initial chunk (512 bytes) of an object file. In MemoryCache::Read, since this data is not cached yet, we call m_process.ReadMemoryFromInferior to actually read the memory (lines 174-241), look at the bottom of:
size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len,
Status &error) {
[...]
while (bytes_left > 0) {
[...]
BlockMap::const_iterator pos = m_L2_cache.find(curr_addr);
BlockMap::const_iterator end = m_L2_cache.end();
if (pos != end) {
size_t curr_read_size = cache_line_byte_size - cache_offset;
if (curr_read_size > bytes_left)
curr_read_size = bytes_left;
memcpy(dst_buf + dst_len - bytes_left,
pos->second->GetBytes() + cache_offset, curr_read_size);
[...]
}
// We need to read from the process
if (bytes_left > 0) {
assert((curr_addr % cache_line_byte_size) == 0);
std::unique_ptr<DataBufferHeap> data_buffer_heap_up(
new DataBufferHeap(cache_line_byte_size, 0));
size_t process_bytes_read = m_process.ReadMemoryFromInferior(
curr_addr, data_buffer_heap_up->GetBytes(),
data_buffer_heap_up->GetByteSize(), error);
if (process_bytes_read == 0)
return dst_len - bytes_left;
if (process_bytes_read != cache_line_byte_size)
data_buffer_heap_up->SetByteSize(process_bytes_read);
m_L2_cache[curr_addr] = DataBufferSP(data_buffer_heap_up.release());
// We have read data and put it into the cache, continue through the
// loop again to get the data out of the cache...
}
First, we allocate a DataBufferHeap with the size of our cache_line_byte_size, 512 bytes, and we pass it to ReadMemoryFromInferior().
The problem is that in this test the whole object file is only 0x84 bytes, so we resize data_buffer_heap_up to a smaller size with data_buffer_heap_up->SetByteSize(process_bytes_read).
Then we iterate back up in the while loop, and try to read from this reallocated buffer. But we still try to read curr_read_size==512 bytes, so read past the buffer size. In fact the overflow is at address 0x615000016184 for a buffer that starts at 0x615000016100.
Note that the simple fix of just reading the available bytes doesn't work: Module::GetMemoryObjectFile expects to always be able to read at least 512 bytes, and it fails if the object file is smaller:
ObjectFile *Module::GetMemoryObjectFile(const lldb::ProcessSP &process_sp,
lldb::addr_t header_addr, Status &error,
size_t size_to_read) {
[...]
const size_t bytes_read =
process_sp->ReadMemory(header_addr, data_up->GetBytes(),
data_up->GetByteSize(), readmem_error);
if (bytes_read == size_to_read) {
[...] // ok...
} else {
error.SetErrorStringWithFormat("unable to read header from memory: %s",
readmem_error.AsCString());
}
[...]
To fix the issue, this patch avoids to resize the DataBufferHeap to a smaller size and pads it with a filler (0xdd) if necessary.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D75200
Files:
lldb/source/Target/Memory.cpp
Index: lldb/source/Target/Memory.cpp
===================================================================
--- lldb/source/Target/Memory.cpp
+++ lldb/source/Target/Memory.cpp
@@ -232,8 +232,17 @@
if (process_bytes_read == 0)
return dst_len - bytes_left;
- if (process_bytes_read != cache_line_byte_size)
- data_buffer_heap_up->SetByteSize(process_bytes_read);
+ if (process_bytes_read != cache_line_byte_size) {
+ // If the data available to read is less than an entire page, we don't
+ // resize the buffer because we still want to return at least
+ // 'dst_len' bytes. In that case fill the rest of the buffer with a
+ // fail-fill value (0xdd).
+ if (process_bytes_read >= data_buffer_heap_up->GetByteSize())
+ data_buffer_heap_up->SetByteSize(process_bytes_read);
+ else
+ memset(data_buffer_heap_up->GetBytes() + process_bytes_read, 0xdd,
+ data_buffer_heap_up->GetByteSize() - process_bytes_read);
+ }
m_L2_cache[curr_addr] = DataBufferSP(data_buffer_heap_up.release());
// We have read data and put it into the cache, continue through the
// loop again to get the data out of the cache...
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D75200.246794.patch
Type: text/x-patch
Size: 1267 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20200226/8956cdc7/attachment.bin>
More information about the lldb-commits
mailing list