Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Fix Issue 19322 (memory leak in backtrace generation with -g)
Browse files Browse the repository at this point in the history
  • Loading branch information
kinke committed Dec 8, 2018
1 parent e716ef7 commit 058c1e5
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 57 deletions.
84 changes: 43 additions & 41 deletions src/rt/backtrace/dwarf.d
Expand Up @@ -58,64 +58,66 @@ int traceHandlerOpApplyImpl(const void*[] callstack, scope int delegate(ref size
const char** frameList = backtrace_symbols(callstack.ptr, cast(int) callstack.length);
scope(exit) free(cast(void*) frameList);

// find address -> file, line mapping using dwarf debug_line
Array!Location locations;
auto image = Image.openSelf();
if (image.isValid)
void processCallstack(const(ubyte)[] debugLineSectionData)
{
auto debugLineSectionData = image.getDebugLineSectionData();

// find address -> file, line mapping using dwarf debug_line
Array!Location locations;
if (debugLineSectionData)
{
// resolve addresses
locations.length = callstack.length;
foreach (size_t i; 0 .. callstack.length)
locations[i].address = cast(size_t) callstack[i];

resolveAddresses(debugLineSectionData, locations[], image.baseAddress);
resolveAddresses(data, locations[], image.baseAddress);
}
}

int ret = 0;
foreach (size_t i; 0 .. callstack.length)
{
char[1536] buffer = void; buffer[0] = 0;
char[256] addressBuffer = void; addressBuffer[0] = 0;

if (locations.length > 0 && locations[i].line != -1)
snprintf(addressBuffer.ptr, addressBuffer.length, "%.*s:%d ", cast(int) locations[i].file.length, locations[i].file.ptr, locations[i].line);
else
addressBuffer[] = "??:? \0";

char[1024] symbolBuffer = void;
int bufferLength;
auto symbol = getDemangledSymbol(frameList[i][0 .. strlen(frameList[i])], symbolBuffer);
if (symbol.length > 0)
bufferLength = snprintf(buffer.ptr, buffer.length, "%s%.*s ", addressBuffer.ptr, cast(int) symbol.length, symbol.ptr);
else
bufferLength = snprintf(buffer.ptr, buffer.length, "%s", addressBuffer.ptr);

assert(bufferLength >= 0);
const addressLength = 20;
const maxBufferLength = buffer.length - addressLength;
if (bufferLength > maxBufferLength)
int ret = 0;
foreach (size_t i; 0 .. callstack.length)
{
bufferLength = maxBufferLength;
buffer[$-4-addressLength..$-addressLength] = "... ";
char[1536] buffer = void; buffer[0] = 0;
char[256] addressBuffer = void; addressBuffer[0] = 0;

if (locations.length > 0 && locations[i].line != -1)
snprintf(addressBuffer.ptr, addressBuffer.length, "%.*s:%d ", cast(int) locations[i].file.length, locations[i].file.ptr, locations[i].line);
else
addressBuffer[] = "??:? \0";

char[1024] symbolBuffer = void;
int bufferLength;
auto symbol = getDemangledSymbol(frameList[i][0 .. strlen(frameList[i])], symbolBuffer);
if (symbol.length > 0)
bufferLength = snprintf(buffer.ptr, buffer.length, "%s%.*s ", addressBuffer.ptr, cast(int) symbol.length, symbol.ptr);
else
bufferLength = snprintf(buffer.ptr, buffer.length, "%s", addressBuffer.ptr);

assert(bufferLength >= 0);
const addressLength = 20;
const maxBufferLength = buffer.length - addressLength;
if (bufferLength > maxBufferLength)
{
bufferLength = maxBufferLength;
buffer[$-4-addressLength..$-addressLength] = "... ";
}
bufferLength += snprintf(buffer.ptr + bufferLength, buffer.length, "[0x%x]", callstack[i]);

auto output = buffer[0 .. bufferLength];
auto pos = i;
ret = dg(pos, output);
if (ret || symbol == "_Dmain") break;
}
bufferLength += snprintf(buffer.ptr + bufferLength, buffer.length, "[0x%x]", callstack[i]);

auto output = buffer[0 .. bufferLength];
auto pos = i;
ret = dg(pos, output);
if (ret || symbol == "_Dmain") break;
return ret;
}
return ret;

auto image = Image.openSelf();
return image.isValid
? image.processDebugLineSectionData(processCallstack);
: processCallstack(null);
}

private:

// the lifetime of the Location data is the lifetime of the mmapped ElfSection
// the lifetime of the Location data is bound to the lifetime of debugLineSectionData
void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations, size_t baseAddress) @nogc nothrow
{
debug(DwarfDebugMachine) import core.stdc.stdio;
Expand Down
23 changes: 9 additions & 14 deletions src/rt/backtrace/elf.d
Expand Up @@ -58,24 +58,19 @@ struct Image
return file != ElfFile.init;
}

const(ubyte)[] getDebugLineSectionData()
T processDebugLineSectionData(T)(scope T delegate(const(ubyte)[]) processor)
{
ElfSectionHeader dbgSectionHeader;
if (!file.findSectionHeaderByName(".debug_line", dbgSectionHeader))
return null;
ElfSection dbgSection;

// we don't support compressed debug sections
if ((dbgSectionHeader.shdr.sh_flags & SHF_COMPRESSED) != 0)
return null;

auto dbgSection = ElfSection(file, dbgSectionHeader);
const sectionData = cast(const(ubyte)[]) dbgSection.data();
// do not munmap() the section data to be returned
import core.stdc.string;
ElfSection initialSection;
memcpy(&dbgSection, &initialSection, ElfSection.sizeof);
if (file.findSectionHeaderByName(".debug_line", dbgSectionHeader))
{
// we don't support compressed debug sections
if (!(dbgSectionHeader.shdr.sh_flags & SHF_COMPRESSED))
dbgSection = ElfSection(file, dbgSectionHeader);
}

return sectionData;
return processor(cast(const(ubyte)[]) dbgSection.data());
}

@property size_t baseAddress()
Expand Down
4 changes: 2 additions & 2 deletions src/rt/backtrace/macho.d
Expand Up @@ -61,11 +61,11 @@ struct Image
return self !is null;
}

const(ubyte)[] getDebugLineSectionData()
T processDebugLineSectionData(T)(scope T delegate(const(ubyte)[]) processor)
{
c_ulong size;
auto data = getsectiondata(self, "__DWARF", "__debug_line", &size);
return data[0 .. size];
return processor(data[0 .. size]);
}

@property size_t baseAddress()
Expand Down

0 comments on commit 058c1e5

Please sign in to comment.