forked from OSchip/llvm-project
[libunwind] Fix memory leak in handling of DW_CFA_remember_state and DW_CFA_restore_state
parseInstructions() doesn't always process the whole set of DWARF instructions for a frame. It will stop once the target PC is reached, or if malformed instructions are found. So, for example, if we have an instruction sequence like this: ``` <start> ... DW_CFA_remember_state ... DW_CFA_advance_loc past the location we're unwinding at (pcoffset in parseInstructions() main loop) ... DW_CFA_restore_state <end> ``` ... the saved state will never be freed, even though the DW_CFA_remember_state opcode has a matching DW_CFA_restore_state later in the sequence. This change adds code to free whatever is left on rememberStack after parsing the CIE and the FDE instructions. Differential Revision: https://reviews.llvm.org/D66904
This commit is contained in:
parent
b8bea9346a
commit
1ae8d81147
|
@ -360,13 +360,25 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
|
|||
PrologInfoStackEntry *rememberStack = NULL;
|
||||
|
||||
// parse CIE then FDE instructions
|
||||
return parseInstructions(addressSpace, cieInfo.cieInstructions,
|
||||
cieInfo.cieStart + cieInfo.cieLength, cieInfo,
|
||||
(pint_t)(-1), rememberStack, arch, results) &&
|
||||
parseInstructions(addressSpace, fdeInfo.fdeInstructions,
|
||||
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
|
||||
upToPC - fdeInfo.pcStart, rememberStack, arch,
|
||||
results);
|
||||
bool returnValue =
|
||||
parseInstructions(addressSpace, cieInfo.cieInstructions,
|
||||
cieInfo.cieStart + cieInfo.cieLength, cieInfo,
|
||||
(pint_t)(-1), rememberStack, arch, results) &&
|
||||
parseInstructions(addressSpace, fdeInfo.fdeInstructions,
|
||||
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
|
||||
upToPC - fdeInfo.pcStart, rememberStack, arch, results);
|
||||
|
||||
// Clean up rememberStack. Even in the case where every DW_CFA_remember_state
|
||||
// is paired with a DW_CFA_restore_state, parseInstructions can skip restore
|
||||
// opcodes if it reaches the target PC and stops interpreting, so we have to
|
||||
// make sure we don't leak memory.
|
||||
while (rememberStack) {
|
||||
PrologInfoStackEntry *next = rememberStack->next;
|
||||
free(rememberStack);
|
||||
rememberStack = next;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/// "run" the DWARF instructions
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
# REQUIRES: x86, linux
|
||||
# RUN: %build -target x86_64-unknown-linux-gnu
|
||||
# RUN: %run
|
||||
|
||||
# The following assembly is a translation of this code:
|
||||
#
|
||||
# _Unwind_Reason_Code callback(int, _Unwind_Action, long unsigned int,
|
||||
# _Unwind_Exception*, _Unwind_Context*, void*) {
|
||||
# return _Unwind_Reason_Code(0);
|
||||
# }
|
||||
#
|
||||
# int main() {
|
||||
# asm(".cfi_remember_state\n\t");
|
||||
# _Unwind_Exception exc;
|
||||
# _Unwind_ForcedUnwind(&exc, callback, 0);
|
||||
# asm(".cfi_restore_state\n\t");
|
||||
# }
|
||||
#
|
||||
# When unwinding, the CFI parser will stop parsing opcodes after the current PC,
|
||||
# so in this case the DW_CFA_restore_state opcode will never be processed and,
|
||||
# if the library doesn't clean up properly, the store allocated by
|
||||
# DW_CFA_remember_state will be leaked.
|
||||
#
|
||||
# This test will fail when linked with an asan-enabled libunwind if the
|
||||
# remembered state is leaked.
|
||||
|
||||
SIZEOF_UNWIND_EXCEPTION = 32
|
||||
|
||||
.text
|
||||
callback:
|
||||
xorl %eax, %eax
|
||||
retq
|
||||
|
||||
.globl main # -- Begin function main
|
||||
.p2align 4, 0x90
|
||||
.type main,@function
|
||||
main: # @main
|
||||
.cfi_startproc
|
||||
subq $8, %rsp # Adjust stack alignment
|
||||
subq $SIZEOF_UNWIND_EXCEPTION, %rsp
|
||||
.cfi_def_cfa_offset 48
|
||||
.cfi_remember_state
|
||||
movq %rsp, %rdi
|
||||
movabsq $callback, %rsi
|
||||
xorl %edx, %edx
|
||||
callq _Unwind_ForcedUnwind
|
||||
.cfi_restore_state
|
||||
xorl %eax, %eax
|
||||
addq $SIZEOF_UNWIND_EXCEPTION, %rsp
|
||||
addq $8, %rsp # Undo stack alignment adjustment
|
||||
.cfi_def_cfa_offset 8
|
||||
retq
|
||||
.Lfunc_end1:
|
||||
.size main, .Lfunc_end1-main
|
||||
.cfi_endproc
|
||||
# -- End function
|
Loading…
Reference in New Issue