[compiler-rt] r368373 - [asan_symbolize] Fix bug where the frame counter was not incremented.

Dan Liew via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 8 17:52:08 PDT 2019


Author: delcypher
Date: Thu Aug  8 17:52:07 2019
New Revision: 368373

URL: http://llvm.org/viewvc/llvm-project?rev=368373&view=rev
Log:
[asan_symbolize] Fix bug where the frame counter was not incremented.

Summary:
This bug occurred when a plug-in requested that a binary not be
symbolized while the script is trying to symbolize a stack frame. In
this case `self.frame_no` would not be incremented. This would cause
subsequent stack frames that are symbolized to be incorrectly numbered.

To fix this `get_symbolized_lines()` has been modified to take an
argument that indicates whether the stack frame counter should
incremented. In `process_line_posix()` `get_symbolized_lines(None, ...)`
is now used in in the case where we don't want to symbolize a line so
that we can keep the frame counter increment in a single function.

A test case is included. The test uses a dummy plugin that always asks
`asan_symbolize.py` script to not symbolize the first binary that the
script asks about. Prior to the patch this would cause the output to
script to look something like

```
  #0 0x0
  #0 0x0 in do_access
  #1 0x0 in main
```

rdar://problem/49476995

Reviewers: kubamracek, yln, samsonov, dvyukov, vitalybuka

Subscribers: #sanitizers, llvm-commits

Tags: #llvm, #sanitizers

Differential Revision: https://reviews.llvm.org/D65495

Added:
    compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.cpp
    compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.py
Modified:
    compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py

Modified: compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py?rev=368373&r1=368372&r2=368373&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py (original)
+++ compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py Thu Aug  8 17:52:07 2019
@@ -431,10 +431,13 @@ class SymbolizationLoop(object):
     assert result
     return result
 
-  def get_symbolized_lines(self, symbolized_lines):
+  def get_symbolized_lines(self, symbolized_lines, inc_frame_counter=True):
     if not symbolized_lines:
+      if inc_frame_counter:
+        self.frame_no += 1
       return [self.current_line]
     else:
+      assert inc_frame_counter
       result = []
       for symbolized_frame in symbolized_lines:
         result.append('    #%s %s' % (str(self.frame_no), symbolized_frame.rstrip()))
@@ -464,15 +467,17 @@ class SymbolizationLoop(object):
     match = re.match(stack_trace_line_format, line)
     if not match:
       logging.debug('Line "{}" does not match regex'.format(line))
-      return [self.current_line]
+      # Not a frame line so don't increment the frame counter.
+      return self.get_symbolized_lines(None, inc_frame_counter=False)
     logging.debug(line)
     _, frameno_str, addr, binary, offset = match.groups()
+
     if not self.using_module_map and not os.path.isabs(binary):
       # Do not try to symbolicate if the binary is just the module file name
       # and a module map is unavailable.
       # FIXME(dliew): This is currently necessary for reports on Darwin that are
       # partially symbolicated by `atos`.
-      return [self.current_line]
+      return self.get_symbolized_lines(None)
     arch = ""
     # Arch can be embedded in the filename, e.g.: "libabc.dylib:x86_64h"
     colon_pos = binary.rfind(":")
@@ -491,7 +496,7 @@ class SymbolizationLoop(object):
     if binary is None:
       # The binary filter has told us this binary can't be symbolized.
       logging.debug('Skipping symbolication of binary "%s"', original_binary)
-      return [self.current_line]
+      return self.get_symbolized_lines(None)
     symbolized_line = self.symbolize_address(addr, binary, offset, arch)
     if not symbolized_line:
       if original_binary != binary:

Added: compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.cpp?rev=368373&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.cpp (added)
+++ compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.cpp Thu Aug  8 17:52:07 2019
@@ -0,0 +1,48 @@
+// This test case checks for an old bug when using plug-ins that caused
+// the stack numbering to be incorrect.
+
+// RUN: %clangxx_asan -O0 -g %s -o %t
+// RUN: %env_asan_opts=symbolize=0 not %run %t DUMMY_ARG > %t.asan_report 2>&1
+// RUN: %asan_symbolize --log-level debug --log-dest %t_debug_log_output.txt -l %t.asan_report --plugins %S/plugin_wrong_frame_number_bug.py > %t.asan_report_sym
+// RUN: FileCheck --input-file=%t.asan_report_sym %s
+
+#include <stdlib.h>
+
+int* p;
+extern "C" {
+
+void bug() {
+  free(p);
+}
+
+void foo(bool call_bug) {
+  if (call_bug)
+    bug();
+}
+
+// This indirection exists so that the call stack
+// is reliably large enough.
+void do_access_impl() {
+  *p = 42;
+}
+
+void do_access() {
+  do_access_impl();
+}
+
+int main(int argc, char** argv) {
+  p = (int*) malloc(sizeof(p));
+  foo(argc > 1);
+  do_access();
+  free(p);
+  return 0;
+}
+}
+
+// Check that the numbering of the stackframes is correct.
+
+// CHECK: AddressSanitizer: heap-use-after-free
+// CHECK-NEXT: WRITE of size
+// CHECK-NEXT: #0 0x{{[0-9a-fA-F]+}}
+// CHECK-NEXT: #1 0x{{[0-9a-fA-F]+}} in do_access
+// CHECK-NEXT: #2 0x{{[0-9a-fA-F]+}} in main

Added: compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.py
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.py?rev=368373&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.py (added)
+++ compiler-rt/trunk/test/asan/TestCases/Posix/asan_symbolize_script/plugin_wrong_frame_number_bug.py Thu Aug  8 17:52:07 2019
@@ -0,0 +1,31 @@
+import logging
+
+class FailOncePlugin(AsanSymbolizerPlugIn):
+  """
+    This is a simple plug-in that always claims
+    that a binary can't be symbolized on the first
+    call but succeeds for all subsequent calls.
+
+    This plug-in exists to reproduce an old bug
+    in the `asan_symbolize.py` script.
+
+    By failing the first symbolization request
+    we used to cause an early exit in `asan_symbolize.py`
+    that didn't increment the frame counter which
+    caused subsequent symbolization attempts to
+    print the wrong frame number.
+  """
+  def __init__(self):
+    self.should_fail = True
+    pass
+
+  def filter_binary_path(self, path):
+    logging.info('filter_binary_path called in NoOpPlugin')
+    if self.should_fail:
+      logging.info('Doing first fail')
+      self.should_fail = False
+      return None
+    logging.info('Doing succeed')
+    return path
+
+register_plugin(FailOncePlugin())




More information about the llvm-commits mailing list