[PATCH] D66904: [libunwind] Fix memory leak in handling of DW_CFA_remember_state and DW_CFA_restore_state
Jorge Gorbe Moya via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 15 13:21:52 PST 2019
jgorbe updated this revision to Diff 229628.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D66904/new/
https://reviews.llvm.org/D66904
Files:
libunwind/src/DwarfParser.hpp
libunwind/test/remember_state_leak.pass.sh.s
Index: libunwind/test/remember_state_leak.pass.sh.s
===================================================================
--- /dev/null
+++ libunwind/test/remember_state_leak.pass.sh.s
@@ -0,0 +1,56 @@
+# REQUIRES: 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, at 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
Index: libunwind/src/DwarfParser.hpp
===================================================================
--- libunwind/src/DwarfParser.hpp
+++ libunwind/src/DwarfParser.hpp
@@ -360,13 +360,25 @@
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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D66904.229628.patch
Type: text/x-patch
Size: 3649 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20191115/98f23566/attachment-0001.bin>
More information about the llvm-commits
mailing list