Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression: Can't use the MPS with clang -fsanitize=address #204

Open
rptb1 opened this issue Mar 27, 2023 · 11 comments
Open

Regression: Can't use the MPS with clang -fsanitize=address #204

rptb1 opened this issue Mar 27, 2023 · 11 comments
Assignees
Labels
build Problems with builds and build automation needs analaysis The issue needs analysis before it can be resolved. nice Little impact; only do if low cost

Comments

@rptb1
Copy link
Member

rptb1 commented Mar 27, 2023

See job003643 which was fixed. Afterwards, we had an internal discussion from 2016, and concluded the sanitizer wasn't available in the available CI systems. It is now.

The sanitizer is described in the Clang documentation at https://clang.llvm.org/docs/AddressSanitizer.html

Adding -fsanitize=address to CFLAGSDEBUG in ll.gmk, then building gcbench, produces some interesting output as the MPS of course goes out of bounds and scans the stack (see below).

This would make it hard for a developer using the MPS to use the sanitizer. The MPS itself might benefit from the sanitizer for defect prevention, though this is fairly unlikely.

We could fix this regression and introduce the sanitizer to the build and CI to help catch it in future.

Also, we should look for similar features in other toolchains.

rb@plover:~/git/mps/code$ time lii6ll/cool/gcbench amc
seed: 1968551265
=================================================================
==567048==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7ffc7f482e20 at pc 0x5555dd2f6804 bp 0x7ffc7f4812b0 sp 0x7ffc7f4812a8
READ of size 8 at 0x7ffc7f482e20 thread T0
    #0 0x5555dd2f6803 in mps_scan_area_tagged /home/rb/git/mps/code/./scan.c:112:3
    #1 0x5555dd3781fd in TraceScanArea /home/rb/git/mps/code/./trace.c:1565:10
    #2 0x5555dd405053 in StackScan /home/rb/git/mps/code/./ss.c:68:10
    #3 0x5555dd3861c0 in ThreadScan /home/rb/git/mps/code/./thix.c:264:11
    #4 0x5555dd38552a in RootScan /home/rb/git/mps/code/./root.c:577:11
    #5 0x5555dd48da91 in traceScanRootRes /home/rb/git/mps/code/./trace.c:527:9
    #6 0x5555dd48d868 in traceScanRoot /home/rb/git/mps/code/./trace.c:544:9
    #7 0x5555dd48d7fe in rootFlip /home/rb/git/mps/code/./trace.c:579:11
    #8 0x5555dd37b15c in RootsIterate /home/rb/git/mps/code/./root.c:665:11
    #9 0x5555dd37c06e in traceFlip /home/rb/git/mps/code/./trace.c:651:11
    #10 0x5555dd37a469 in TraceStart /home/rb/git/mps/code/./trace.c:1693:10
    #11 0x5555dd340f23 in PolicyStartTrace /home/rb/git/mps/code/./policy.c:335:13
    #12 0x5555dd33f057 in TracePoll /home/rb/git/mps/code/./trace.c:1839:10
    #13 0x5555dd2e442e in ArenaPoll /home/rb/git/mps/code/./global.c:745:16
    #14 0x5555dd2e9666 in mps_ap_fill /home/rb/git/mps/code/./mpsi.c:1065:5
    #15 0x5555dd4bff2f in make_dylan_vector /home/rb/git/mps/code/fmtdytst.c:134:5
    #16 0x5555dd4bb565 in mkvector /home/rb/git/mps/code/gcbench.c:78:3
    #17 0x5555dd4bb190 in mktree /home/rb/git/mps/code/gcbench.c:99:10
    #18 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #19 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #20 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #21 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #22 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #23 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #24 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #25 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #26 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #27 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #28 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #29 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #30 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #31 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #32 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #33 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #34 0x5555dd4bb1d0 in mktree /home/rb/git/mps/code/gcbench.c:101:19
    #35 0x5555dd4bb0a4 in gc_tree /home/rb/git/mps/code/gcbench.c:173:18
    #36 0x5555dd4bbdc2 in start /home/rb/git/mps/code/gcbench.c:193:3
    #37 0x5555dd4bb90e in weave1 /home/rb/git/mps/code/gcbench.c:220:3
    #38 0x5555dd4bb7ae in watch /home/rb/git/mps/code/gcbench.c:230:5
    #39 0x5555dd481358 in arena_setup /home/rb/git/mps/code/gcbench.c:265:3
    #40 0x5555dd48096d in main /home/rb/git/mps/code/gcbench.c:490:5
    #41 0x7f1435c94d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #42 0x7f1435c94e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #43 0x5555dd2164d4 in _start (/home/rb/git/mps/code/lii6ll/cool/gcbench+0x874d4) (BuildId: 464dd716f6afd819fb1de5e206d355a551cb5a94)

Address 0x7ffc7f482e20 is located in stack of thread T0 at offset 0 in frame
    #0 0x5555dd2e928f in mps_ap_fill /home/rb/git/mps/code/./mpsi.c:1052

  This frame has 2 object(s):
    [32, 40) 'p' (line 1055)
    [64, 264) '_sc' (line 1063)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-underflow /home/rb/git/mps/code/./scan.c:112:3 in mps_scan_area_tagged
Shadow bytes around the buggy address:
  0x10000fe88570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fe88580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fe88590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fe885a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fe885b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10000fe885c0: 00 00 00 00[f1]f1 f1 f1 00 f2 f2 f2 00 00 00 00
  0x10000fe885d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fe885e0: 00 00 00 00 00 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3
  0x10000fe885f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fe88600: f1 f1 f1 f1 00 f3 f3 f3 00 00 00 00 00 00 00 00
  0x10000fe88610: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==567048==ABORTING

real	0m0,445s
user	0m0,234s
sys	0m0,041s
@rptb1 rptb1 added build Problems with builds and build automation needs analaysis The issue needs analysis before it can be resolved. labels Mar 27, 2023
@rptb1
Copy link
Member Author

rptb1 commented Mar 27, 2023

It looks like the regression was introduced by me in 2b10812

@thejayps thejayps added the nice Little impact; only do if low cost label Mar 27, 2023
@thejayps thejayps self-assigned this Mar 27, 2023
@mgood7123
Copy link

mgood7123 commented Sep 20, 2023

im also getting a similar error when using asan with the thread stacks

the config variant is CONFIG_VAR_COOL

this happens for both

0x7FFFFF7FF000

and

0x7FFFFFFFF000

when used as thread markers

related to #210 (im using boem to obtain the appropiate stack top/bottom for me)

==637141==AddressSanitizer: failed to intercept '__isoc99_printf'
==637141==AddressSanitizer: failed to intercept '__isoc99_sprintf'
==637141==AddressSanitizer: failed to intercept '__isoc99_snprintf'
==637141==AddressSanitizer: failed to intercept '__isoc99_fprintf'
==637141==AddressSanitizer: failed to intercept '__isoc99_vprintf'
==637141==AddressSanitizer: failed to intercept '__isoc99_vsprintf'
==637141==AddressSanitizer: failed to intercept '__isoc99_vsnprintf'
==637141==AddressSanitizer: failed to intercept '__isoc99_vfprintf'
==637141==AddressSanitizer: failed to intercept 'xdr_destroy'
==637141==AddressSanitizer: failed to intercept 'crypt'
==637141==AddressSanitizer: failed to intercept 'crypt_r'
==637141==AddressSanitizer: failed to intercept '__cxa_rethrow_primary_exception'
==637141==AddressSanitizer: libc interceptors initialized
|| `[0x10007fff8000, 0x7fffffffffff]` || HighMem    ||
|| `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
|| `[0x00008fff7000, 0x02008fff6fff]` || ShadowGap  ||
|| `[0x00007fff8000, 0x00008fff6fff]` || LowShadow  ||
|| `[0x000000000000, 0x00007fff7fff]` || LowMem     ||
MemToShadow(shadow): 0x00008fff7000 0x000091ff6dff 0x004091ff6e00 0x02008fff6fff
redzone=16
max_redzone=2048
quarantine_size_mb=256M
thread_local_quarantine_size_kb=1024K
malloc_context_size=30
SHADOW_SCALE: 3
SHADOW_GRANULARITY: 8
SHADOW_OFFSET: 0x7fff8000
==637141==Installed the sigaction for signal 11
==637141==Installed the sigaction for signal 7
==637141==Installed the sigaction for signal 8
==637141==T0: FakeStack created: 0x7ffff63c3000 -- 0x7ffff6ecc000 stack_size_log: 20; mmapped 11300K, noreserve=0 
==637141==T0: stack [0x7fffff7ff000,0x7ffffffff000) size 0x800000; local=0x7fffffffdd54
==637141==AddressSanitizer Init done

// ...

Process 637141 stopped
* thread #1, name = 'managed_object_', stop reason = signal SIGSEGV: invalid address (fault address: 0x7ffffffff000)
    frame #0: 0x000000000081d0da managed_object_tests_debug`MANAGED_STACK_ADDRESS_BOEHM_GC_find_limit_with_bound(p="\U00000010\xcc\xff\xff\xff\U0000007f", up=1, bound=<no value available>) at os_dep.c:1007:54
   1004	                    }
   1005	                    result -= MIN_PAGE_SIZE; /* no underflow expected */
   1006	                }
-> 1007	                MANAGED_STACK_ADDRESS_BOEHM_GC_noop1((word)(*result));
   1008	            }
   1009	        }
   1010	        MANAGED_STACK_ADDRESS_BOEHM_GC_reset_fault_handler();
(lldb) c
Process 637141 resuming
Primordial thread stack bottom: 0x7ffffffff000
deinit
deinit - collect
=================================================================
==637141==ERROR: AddressSanitizer: stack-use-after-return on address 0x7ffff6468360 at pc 0x00000064667a bp 0x7fffffffb650 sp 0x7fffffffb648
READ of size 8 at 0x7ffff6468360 thread T0
    #0 0x646679 in mps_scan_area_tagged /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/scan.c:112:3
    #1 0x6cdcd7 in TraceScanArea /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:1566:10
    #2 0x75ebdb in StackScan /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/ss.c:68:10
    #3 0x6dc12c in ThreadScan /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/thix.c:264:11
    #4 0x6db44c in RootScan /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/root.c:577:11
    #5 0x7ea6a7 in traceScanRootRes /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:528:9
    #6 0x7ea478 in traceScanRoot /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:545:9
    #7 0x7ea402 in rootFlip /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:580:11
    #8 0x6d0cec in RootsIterate /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/root.c:665:11
    #9 0x6d1c5b in traceFlip /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:652:11
    #10 0x6cffc1 in TraceStart /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:1694:10
    #11 0x6945ca in TraceStartCollectAll /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:1794:9
    #12 0x626dfa in ArenaStartCollect /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/traceanc.c:634:9
    #13 0x6272e6 in ArenaCollect /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/traceanc.c:652:9
    #14 0x6270fd in mps_arena_collect /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/mpsi.c:313:11
    #15 0x81c49a in managed_obj_collect /home/DATA/git/Gecko/HTML/qparse/ManagedObject/src/managed_object_obj.c:509:5
    #16 0x81c6ba in managed_obj_deinit /home/DATA/git/Gecko/HTML/qparse/ManagedObject/src/managed_object_obj.c:525:5
    #17 0x4db875 in MPS_0_Test::TestBody() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/tests/managed_object_tests.cpp:251:5
    #18 0x5c700c in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2612:10
    #19 0x5789f8 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2648:14
    #20 0x5249c8 in testing::Test::Run() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2687:5
    #21 0x52684d in testing::TestInfo::Run() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2836:11
    #22 0x528068 in testing::TestSuite::Run() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:3015:30
    #23 0x54b6e2 in testing::internal::UnitTestImpl::RunAllTests() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:5921:44
    #24 0x5d807c in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2612:10
    #25 0x57f3b8 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2648:14
    #26 0x54ab16 in testing::UnitTest::Run() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:5485:10
    #27 0x4ee510 in RUN_ALL_TESTS() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/include/gtest/gtest.h:2316:73
    #28 0x4ee49f in main /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest_main.cc:64:10
    #29 0x7ffff7a4fd09 in __libc_start_main csu/../csu/libc-start.c:308:16
    #30 0x429ac9 in _start (/home/DATA/git/Gecko/HTML/qparse/ManagedObject/debug_asan_EXECUTABLE/managed_object_tests_debug+0x429ac9)

Address 0x7ffff6468360 is located in stack of thread T0 at offset 32 in frame
    #0 0x625f7f in StackHot /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/ss.c:37

  This frame has 1 object(s):
    [32, 40) 'stackOut.addr' <== Memory access at offset 32 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-return /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/scan.c:112:3 in mps_scan_area_tagged
Shadow bytes around the buggy address:
  0x10007ec85010: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85020: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85030: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85040: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85050: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
=>0x10007ec85060: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5[f5]f5 f5 f5
  0x10007ec85070: f1 f1 f1 f1 00 f3 f3 f3 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85080: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85090: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec850a0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec850b0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==637141==ABORTING
(lldb) AddressSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.
Process 637141 stopped
* thread #1, name = 'managed_object_', stop reason = Use of stack memory after return
    frame #0: 0x00000000004adcb0 managed_object_tests_debug`__asan::AsanDie()
managed_object_tests_debug`__asan::AsanDie:
->  0x4adcb0 <+0>: pushq  %rbx
    0x4adcb1 <+1>: lock   
    0x4adcb2 <+2>: addl   $0x1, 0x50a8e3(%rip)
    0x4adcb9 <+9>: movq   $0xa495c8, %rax           ; imm = 0xA495C8 
(lldb) up
frame #1: 0x00000000004c30fc managed_object_tests_debug`__sanitizer::Die() + 172
managed_object_tests_debug`__sanitizer::Die:
->  0x4c30fc <+172>: movq   $0xa495c8, %rax           ; imm = 0xA495C8 
    0x4c3103 <+179>: cmpb   $0x0, 0xf8(%rax)
    0x4c310a <+186>: je     0x4c30a9                  ; <+89>
    0x4c310c <+188>: callq  0x4c4df0                  ; __sanitizer::Abort()
(lldb) 
frame #2: 0x00000000004aa201 managed_object_tests_debug`__asan::ScopedInErrorReport::~ScopedInErrorReport() + 449
->  0x4aa201:      nopw   %cs:(%rax,%rax)
    0x4aa20b:      nopl   (%rax,%rax)
managed_object_tests_debug`__asan::ReportDoubleFree:
    0x4aa210 <+0>: pushq  %r14
    0x4aa212 <+2>: pushq  %rbx
(lldb) 
frame #3: 0x00000000004abd46 managed_object_tests_debug`__asan::ReportGenericError(unsigned long, unsigned long, unsigned long, unsigned long, bool, unsigned long, unsigned int, bool) + 1462
managed_object_tests_debug`__asan::ReportGenericError:
->  0x4abd46 <+1462>: addq   $0xc18, %rsp              ; imm = 0xC18 
    0x4abd4d <+1469>: popq   %rbx
    0x4abd4e <+1470>: popq   %r12
    0x4abd50 <+1472>: popq   %r13
(lldb) 
frame #4: 0x00000000004ac5b8 managed_object_tests_debug`__asan_report_load8 + 40
managed_object_tests_debug`__asan_report_load8:
->  0x4ac5b8 <+40>: addq   $0x20, %rsp
    0x4ac5bc <+44>: popq   %rbp
    0x4ac5bd <+45>: retq   
    0x4ac5be:       nop    
(lldb) 
frame #5: 0x000000000064667a managed_object_tests_debug`mps_scan_area_tagged(ss=0x00007ffff66e8a28, base=0x00007ffff6468360, limit=0x00007ffffffff000, closure=0x00007ffff3732a68) at scan.c:112:3
   109 	  mps_word_t mask = tag->mask;
   110 	  mps_word_t pattern = tag->pattern;
   111 	
-> 112 	  MPS_SCAN_AREA(tag_bits == pattern);
   113 	
   114 	  return MPS_RES_OK;
   115 	}
(lldb)
==637849==T0: FakeStack created: 0x7ffff63c3000 -- 0x7ffff6ecc000 stack_size_log: 20; mmapped 11300K, noreserve=0 
==637849==T0: stack [0x7fffff7ff000,0x7ffffffff000) size 0x800000; local=0x7fffffffdd54

// ...

Process 637849 resuming
Primordial thread stack bottom: 0x7fffff7ff000
deinit
deinit - collect
=================================================================
==637849==ERROR: AddressSanitizer: stack-use-after-return on address 0x7ffff6468360 at pc 0x00000064667a bp 0x7fffffffb650 sp 0x7fffffffb648
READ of size 8 at 0x7ffff6468360 thread T0
    #0 0x646679 in mps_scan_area_tagged /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/scan.c:112:3
    #1 0x6cdcd7 in TraceScanArea /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:1566:10
    #2 0x75ebdb in StackScan /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/ss.c:68:10
    #3 0x6dc12c in ThreadScan /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/thix.c:264:11
    #4 0x6db44c in RootScan /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/root.c:577:11
    #5 0x7ea6a7 in traceScanRootRes /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:528:9
    #6 0x7ea478 in traceScanRoot /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:545:9
    #7 0x7ea402 in rootFlip /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:580:11
    #8 0x6d0cec in RootsIterate /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/root.c:665:11
    #9 0x6d1c5b in traceFlip /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:652:11
    #10 0x6cffc1 in TraceStart /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:1694:10
    #11 0x6945ca in TraceStartCollectAll /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/trace.c:1794:9
    #12 0x626dfa in ArenaStartCollect /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/traceanc.c:634:9
    #13 0x6272e6 in ArenaCollect /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/traceanc.c:652:9
    #14 0x6270fd in mps_arena_collect /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/mpsi.c:313:11
    #15 0x81c49a in managed_obj_collect /home/DATA/git/Gecko/HTML/qparse/ManagedObject/src/managed_object_obj.c:509:5
    #16 0x81c6ba in managed_obj_deinit /home/DATA/git/Gecko/HTML/qparse/ManagedObject/src/managed_object_obj.c:525:5
    #17 0x4db875 in MPS_0_Test::TestBody() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/tests/managed_object_tests.cpp:251:5
    #18 0x5c700c in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2612:10
    #19 0x5789f8 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2648:14
    #20 0x5249c8 in testing::Test::Run() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2687:5
    #21 0x52684d in testing::TestInfo::Run() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2836:11
    #22 0x528068 in testing::TestSuite::Run() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:3015:30
    #23 0x54b6e2 in testing::internal::UnitTestImpl::RunAllTests() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:5921:44
    #24 0x5d807c in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2612:10
    #25 0x57f3b8 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:2648:14
    #26 0x54ab16 in testing::UnitTest::Run() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest.cc:5485:10
    #27 0x4ee510 in RUN_ALL_TESTS() /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/include/gtest/gtest.h:2316:73
    #28 0x4ee49f in main /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest_main.cc:64:10
    #29 0x7ffff7a4fd09 in __libc_start_main csu/../csu/libc-start.c:308:16
    #30 0x429ac9 in _start (/home/DATA/git/Gecko/HTML/qparse/ManagedObject/debug_asan_EXECUTABLE/managed_object_tests_debug+0x429ac9)

Address 0x7ffff6468360 is located in stack of thread T0 at offset 32 in frame
    #0 0x625f7f in StackHot /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/ss.c:37

  This frame has 1 object(s):
    [32, 40) 'stackOut.addr' <== Memory access at offset 32 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-return /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/scan.c:112:3 in mps_scan_area_tagged
Shadow bytes around the buggy address:
  0x10007ec85010: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85020: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85030: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85040: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85050: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
=>0x10007ec85060: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5[f5]f5 f5 f5
  0x10007ec85070: f1 f1 f1 f1 00 f3 f3 f3 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85080: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec85090: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec850a0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x10007ec850b0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==637849==ABORTING

(lldb) 
frame #5: 0x000000000064667a managed_object_tests_debug`mps_scan_area_tagged(ss=0x00007ffff66e8a28, base=0x00007ffff6468360, limit=0x00007fffff7ff000, closure=0x00007ffff3732a68) at scan.c:112:3
   109 	  mps_word_t mask = tag->mask;
   110 	  mps_word_t pattern = tag->pattern;
   111 	
-> 112 	  MPS_SCAN_AREA(tag_bits == pattern);
   113 	
   114 	  return MPS_RES_OK;
   115 	}
(lldb)

@mgood7123
Copy link

mgood7123 commented Sep 20, 2023

specifically we seem to be attempting to scan an asan FakeStack region which triggers asan

(in which 0x7ffff6468360 lies within this FakeStack 0x7ffff63c3000 -- 0x7ffff6ecc000 )

however it appears to be OUTSIDE of the reported stack bounds (by both asan and boem)

0x7ffff63c3000 <- asan FakeStack begin
0x7ffff6468360 <- address being scanned, Stack-Use-After-Return
0x7ffff68cd820 <- &state // ::TestBody(this=0x0000602000000690) // TEST(MPS, 0) { ManagedObjState state;
0x7ffff6ecc000 <- asan FakeStack end
0x7fffff7ff000 <- stack begin
0x7fffffffde28 <- argv // main(argc=1, argv=0x00007fffffffde28)
0x7ffffffff000 <- stack end
(lldb) target list
Current targets:
* target #0: /home/DATA/git/Gecko/HTML/qparse/ManagedObject/debug_asan_EXECUTABLE/managed_object_tests_debug ( arch=x86_64-pc-linux-gnu, platform=host, pid=638376, state=stopped )
(lldb) shell cat /proc/638376/maps
// ...
00996000-0135f000 rw-p 00000000 00:00 0                                  [heap]
// ...
7ffff626f000-7ffff6eda000 rw-p 00000000 00:00 0 // within range of asan FakeStack
// ...
7fffff7ff000-7ffffffff000 rw-p 00000000 00:00 0                          [stack] // reported stack
(lldb)

i do not know how to avoid this

@mgood7123
Copy link

mgood7123 commented Sep 20, 2023

a work around seems to be explicitly disabling ASAN instrumentation in the scan.c functions

/* scan.c: SCANNING FUNCTIONS
 *
 * $Id$
 * Copyright (c) 2001-2020 Ravenbrook Limited.
 * See end of file for license.
 *
 * .outside: The code in this file is written as if *outside* the MPS,
 * and so is restricted to facilities in the MPS interface.  MPS users
 * are invited to read this code and use it as a basis for their own
 * scanners.  See topic "Area Scanners" in the MPS manual.
 *
 * TODO: Design document.
 */

#include "mps.h"
#include "mpstd.h" /* for MPS_BUILD_MV */


#ifdef MPS_BUILD_MV
/* MSVC warning 4127 = conditional expression is constant */
/* Objects to: MPS_SCAN_AREA(1). */
#pragma warning( disable : 4127 )
#endif


#define MPS_SCAN_AREA(test) \
  MPS_SCAN_BEGIN(ss) {                                  \
    mps_word_t *p = base;                               \
    while (p < (mps_word_t *)limit) {                   \
      mps_word_t word = *p;                             \
      mps_word_t tag_bits = word & mask;                \
      if (test) {                                       \
        mps_addr_t ref = (mps_addr_t)(word ^ tag_bits); \
        if (MPS_FIX1(ss, ref)) {                        \
          mps_res_t res = MPS_FIX2(ss, &ref);           \
          if (res != MPS_RES_OK)                        \
            return res;                                 \
          *p = (mps_word_t)ref | tag_bits;              \
        }                                               \
      }                                                 \
      ++p;                                              \
    }                                                   \
  } MPS_SCAN_END(ss);

/* support asan */

#if defined(__has_feature)
  /* __has_feature() is supported.      */
# if __has_feature(address_sanitizer)
#   define ADDRESS_SANITIZER
# endif
# if __has_feature(memory_sanitizer)
#   define MEMORY_SANITIZER
# endif
# if __has_feature(thread_sanitizer)
#   define THREAD_SANITIZER
# endif
#else
# ifdef __SANITIZE_ADDRESS__
    /* GCC v4.8+ */
#   define ADDRESS_SANITIZER
# endif
# if defined(__SANITIZE_THREAD__)
    /* GCC v7.1+ */
#   define THREAD_SANITIZER
# endif
#endif /* !__has_feature */

/* Convenient internal macro to test version of Clang.  */
#if defined(__clang__) && defined(__clang_major__)
# define MPS_GC_CLANG_PREREQ(major, minor) \
    ((__clang_major__ << 8) + __clang_minor__ >= ((major) << 8) + (minor))
# define MPS_GC_CLANG_PREREQ_FULL(major, minor, patchlevel) \
            (MPS_GC_CLANG_PREREQ(major, (minor) + 1) \
                || (__clang_major__ == (major) && __clang_minor__ == (minor) \
                    && __clang_patchlevel__ >= (patchlevel)))
#else
# define MPS_GC_CLANG_PREREQ(major, minor) 0 /* FALSE */
# define MPS_GC_CLANG_PREREQ_FULL(major, minor, patchlevel) 0
#endif

/* Convenient internal macro to test version of gcc.    */
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
# define MPS_GC_GNUC_PREREQ(major, minor) \
            ((__GNUC__ << 8) + __GNUC_MINOR__ >= ((major) << 8) + (minor))
#else
# define MPS_GC_GNUC_PREREQ(major, minor) 0 /* FALSE */
#endif

#ifndef MPS_GC_ATTR_NOINLINE
# if MPS_GC_GNUC_PREREQ(4, 0)
#   define MPS_GC_ATTR_NOINLINE __attribute__((__noinline__))
# elif _MSC_VER >= 1400
#   define MPS_GC_ATTR_NOINLINE __declspec(noinline)
# else
#   define MPS_GC_ATTR_NOINLINE /* empty */
# endif
#endif

#ifndef MPS_GC_ATTR_NO_SANITIZE_ADDR
# ifndef ADDRESS_SANITIZER
#   define MPS_GC_ATTR_NO_SANITIZE_ADDR /* empty */
# elif MPS_GC_CLANG_PREREQ(3, 8)
#   define MPS_GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize("address")))
# else
#   define MPS_GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize_address))
# endif
#endif /* !MPS_GC_ATTR_NO_SANITIZE_ADDR */

#ifndef MPS_GC_ATTR_NO_SANITIZE_MEMORY
# ifndef MEMORY_SANITIZER
#   define MPS_GC_ATTR_NO_SANITIZE_MEMORY /* empty */
# elif MPS_GC_CLANG_PREREQ(3, 8)
#   define MPS_GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
# else
#   define MPS_GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
# endif
#endif /* !MPS_GC_ATTR_NO_SANITIZE_MEMORY */

#ifndef MPS_GC_ATTR_NO_SANITIZE_THREAD
# ifndef THREAD_SANITIZER
#   define MPS_GC_ATTR_NO_SANITIZE_THREAD /* empty */
# elif MPS_GC_CLANG_PREREQ(3, 8)
#   define MPS_GC_ATTR_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# else
    /* It seems that no_sanitize_thread attribute has no effect if the  */
    /* function is inlined (as of gcc 11.1.0, at least).                */
#   define MPS_GC_ATTR_NO_SANITIZE_THREAD \
                MPS_GC_ATTR_NOINLINE __attribute__((no_sanitize_thread))
# endif
#endif /* !MPS_GC_ATTR_NO_SANITIZE_THREAD */



/* mps_scan_area -- scan contiguous area of references
 *
 * This is a convenience function for scanning the contiguous area
 * [base, limit).  I.e., it calls Fix on all words from base up to
 * limit, inclusive of base and exclusive of limit.
 *
 * This scanner is appropriate for use when all words in the area are
 * simple untagged references.
 */

MPS_GC_ATTR_NO_SANITIZE_ADDR
MPS_GC_ATTR_NO_SANITIZE_MEMORY
MPS_GC_ATTR_NO_SANITIZE_THREAD
mps_res_t mps_scan_area(mps_ss_t ss,
                        void *base, void *limit,
                        void *closure)
{
  mps_word_t mask = 0;

  (void)closure; /* unused */

  MPS_SCAN_AREA(1);

  return MPS_RES_OK;
}


/* mps_scan_area_masked -- scan area masking off tag bits
 *
 * Like mps_scan_area, but removes tag bits before fixing references,
 * and restores them afterwards.
 *
 * For example, if mask is 7, then this scanner will clear the bottom
 * three bits of each word before fixing.
 *
 * This scanner is useful when all words in the area must be treated
 * as references no matter what tag they have.
 */

MPS_GC_ATTR_NO_SANITIZE_ADDR
MPS_GC_ATTR_NO_SANITIZE_MEMORY
MPS_GC_ATTR_NO_SANITIZE_THREAD
mps_res_t mps_scan_area_masked(mps_ss_t ss,
                               void *base, void *limit,
                               void *closure)
{
  mps_scan_tag_t tag = closure;
  mps_word_t mask = tag->mask;

  MPS_SCAN_AREA(1);

  return MPS_RES_OK;
}


/* mps_scan_area_tagged -- scan area selecting by tag
 *
 * Like mps_scan_area_masked, except only references whose masked bits
 * match a particular tag pattern are fixed.
 *
 * For example, if mask is 7 and pattern is 5, then this scanner will
 * only fix words whose low order bits are 0b101.
 */

MPS_GC_ATTR_NO_SANITIZE_ADDR
MPS_GC_ATTR_NO_SANITIZE_MEMORY
MPS_GC_ATTR_NO_SANITIZE_THREAD
mps_res_t mps_scan_area_tagged(mps_ss_t ss,
                               void *base, void *limit,
                               void *closure)
{
  mps_scan_tag_t tag = closure;
  mps_word_t mask = tag->mask;
  mps_word_t pattern = tag->pattern;

  MPS_SCAN_AREA(tag_bits == pattern);

  return MPS_RES_OK;
}


/* mps_scan_area_tagged_or_zero -- scan area selecting by tag or zero
 *
 * Like mps_scan_area_tagged, except references whose masked bits are
 * zero are fixed in addition to those that match the pattern.
 *
 * For example, if mask is 7 and pattern is 3, then this scanner will
 * fix words whose low order bits are 0b011 and words whose low order
 * bits are 0b000, but not any others.
 *
 * This scanner is most useful for ambiguously scanning the stack and
 * registers when using an optimising C compiler and non-zero tags on
 * references, since the compiler is likely to leave untagged
 * addresses of objects around which must not be ignored.
 */

MPS_GC_ATTR_NO_SANITIZE_ADDR
MPS_GC_ATTR_NO_SANITIZE_MEMORY
MPS_GC_ATTR_NO_SANITIZE_THREAD
mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss,
                                       void *base, void *limit,
                                       void *closure)
{
  mps_scan_tag_t tag = closure;
  mps_word_t mask = tag->mask;
  mps_word_t pattern = tag->pattern;

  MPS_SCAN_AREA(tag_bits == 0 || tag_bits == pattern);

  return MPS_RES_OK;
}


/* C. COPYRIGHT AND LICENSE
 *
 * Copyright (C) 2001-2020 Ravenbrook Limited <https://www.ravenbrook.com/>.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

@mgood7123
Copy link

mgood7123 commented Sep 20, 2023

however we then get a prot crash in asan which does not happen under a non-asan build

Process 642086 stopped
* thread #1, name = 'managed_object_', stop reason = signal SIGSEGV: address access protected (fault address: 0x7ffff6eda000)
    frame #0: 0x00000000006461b2 managed_object_tests_debug`mps_scan_area_tagged(ss=0x00007ffff66e8a28, base=0x00007ffff6468360, limit=0x00007ffffffff000, closure=0x00007ffff3732a68) at scan.c:190:3
   187 	  mps_word_t mask = tag->mask;
   188 	  mps_word_t pattern = tag->pattern;
   189 	
-> 190 	  MPS_SCAN_AREA(tag_bits == pattern);
   191 	
   192 	  return MPS_RES_OK;
   193 	}
(lldb) s
This version of LLDB has no plugin for the language "assembler". Inspection of frame variables will be limited.
Process 642086 stopped
* thread #1, name = 'managed_object_', stop reason = unknown crash reason
    frame #0: 0x00007ffff7a65087 libc.so.6`kill at syscall-template.S:120
(lldb) 
AddressSanitizer:DEADLYSIGNAL
=================================================================
==642086==ERROR: AddressSanitizer: SEGV on unknown address 0x03e80009cc26 (pc 0x7ffff7a65087 bp 0x7fffffffb270 sp 0x7fffffffb158 T0)
==642086==The signal is caused by a READ memory access.
    #0 0x7ffff7a65087 in kill signal/../sysdeps/unix/syscall-template.S:120
    #1 0x7dc01c in sigHandle /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/protsgix.c:114:9
    #2 0x7ffff7a64d5f  (/lib/x86_64-linux-gnu/libc.so.6+0x38d5f)
    #3 0x6461b1 in mps_scan_area_tagged /home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/scan.c:190:3

additionally i have discovered that boehm was incorrectly restoring MPS's signal handler via signal instead of sigaction, in which signal disregards the SIGINFO flag passed to sigaction which in turn results in MPS's restored signal handler recieving a garbage signal info structure

this is fixable via defining USE_SEGV_SIGACT when compiling boehm

HOWEVER we then go on to get a re-entrent arena lock (assert res = 0)

    frame #2: 0x0000000000817eae managed_object_tests_debug`mps_lib_assert_fail_default(file="/home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/lockix.c", line=126, condition="res == 0") at mpsliban.c:78:3
    frame #3: 0x0000000000622de8 managed_object_tests_debug`mps_lib_assert_fail(file="/home/DATA/git/Gecko/HTML/qparse/ManagedObject/mps/code/lockix.c", line=126, condition="res == 0") at mpsliban.c:87:3
    frame #4: 0x000000000068fa1d managed_object_tests_debug`LockClaim(lock=0x00007ffff3732110) at lockix.c:126:3
    frame #5: 0x000000000068f5b2 managed_object_tests_debug`ArenaEnterLock(arena=0x00007ffff626e000, recursive=0) at global.c:576:5
    frame #6: 0x0000000000622db7 managed_object_tests_debug`ArenaEnter(arena=0x00007ffff626e000) at global.c:553:3
    frame #7: 0x00000000006907b4 managed_object_tests_debug`ArenaAccess(addr=0x00007ffff6eda000, mode=3, context=0x00007ffff67d4e40) at global.c:655:5
    frame #8: 0x00000000007dc03e managed_object_tests_debug`sigHandle(sig=11, info=0x00007fffffffb3b0, uap=0x00007fffffffb280) at protsgix.c:97:11
    frame #9: 0x00007ffff7f9b140 libpthread.so.0`__restore_rt
    frame #10: 0x0000000000646412 managed_object_tests_debug`mps_scan_area_tagged(ss=0x00007ffff66e8a28, base=0x00007ffff6468360, limit=0x00007ffffffff000, closure=0x00007ffff3732a68) at scan.c:210:3
    frame #11: 0x00000000006cd928 managed_object_tests_debug`TraceScanArea(ss=0x00007ffff66e8a20, base=0x00007ffff6468360, limit=0x00007ffffffff000, scan_area=(managed_object_tests_debug`mps_scan_area_tagged at scan.c:205), closure=0x00007ffff3732a68) at trace.c:1566:10
    frame #12: 0x000000000075e1fc managed_object_tests_debug`StackScan(ss=0x00007ffff66e8a20, stackCold=0x00007ffffffff000, scan_area=(managed_object_tests_debug`mps_scan_area_tagged at scan.c:205), closure=0x00007ffff3732a68) at ss.c:68:10
    frame #13: 0x00000000006db74d managed_object_tests_debug`ThreadScan(ss=0x00007ffff66e8a20, thread=0x00007ffff3732988, stackCold=0x00007ffffffff000, scan_area=(managed_object_tests_debug`mps_scan_area_tagged at scan.c:205), closure=0x00007ffff3732a68) at thix.c:264:11
    frame #14: 0x00000000006daa6d managed_object_tests_debug`RootScan(ss=0x00007ffff66e8a20, root=0x00007ffff3732a00) at root.c:577:11
    frame #15: 0x00000000007e9cc8 managed_object_tests_debug`traceScanRootRes(ts=1, rank=0, arena=0x00007ffff626e000, root=0x00007ffff3732a00) at trace.c:528:9
    frame #16: 0x00000000007e9a99 managed_object_tests_debug`traceScanRoot(ts=1, rank=0, arena=0x00007ffff626e000, root=0x00007ffff3732a00) at trace.c:545:9
    frame #17: 0x00000000007e9a23 managed_object_tests_debug`rootFlip(root=0x00007ffff3732a00, p=0x00007ffff64fb120) at trace.c:580:11
    frame #18: 0x00000000006d093d managed_object_tests_debug`RootsIterate(arena=0x00007ffff626e008, f=(managed_object_tests_debug`rootFlip at trace.c:567), p=0x00007ffff64fb120) at root.c:665:11
    frame #19: 0x00000000006d18ac managed_object_tests_debug`traceFlip(trace=0x00007ffff626eb50) at trace.c:652:11
    frame #20: 0x00000000006cfc12 managed_object_tests_debug`TraceStart(trace=0x00007ffff626eb50, mortality=0.84999999999999998, finishingTime=33402520) at trace.c:1694:10
    frame #21: 0x000000000069421b managed_object_tests_debug`TraceStartCollectAll(traceReturn=0x00007ffff64683a0, arena=0x00007ffff626e000, why=4) at trace.c:1794:9
    frame #22: 0x000000000062705b managed_object_tests_debug`ArenaStartCollect(globals=0x00007ffff626e008, why=4) at traceanc.c:634:9
    frame #23: 0x0000000000627547 managed_object_tests_debug`ArenaCollect(globals=0x00007ffff626e008, why=4) at traceanc.c:652:9
    frame #24: 0x000000000062735e managed_object_tests_debug`mps_arena_collect(arena=0x00007ffff626e000) at mpsi.c:313:11
    frame #25: 0x000000000081bb5b managed_object_tests_debug`managed_obj_collect(state=0x00007ffff68cd820) at managed_object_obj.c:509:5
frame #4: 0x000000000068fa1d managed_object_tests_debug`LockClaim(lock=0x00007ffff3732110) at lockix.c:126:3
   123 	
   124 	  res = pthread_mutex_lock(&lock->mut);
   125 	  /* pthread_mutex_lock will error if we own the lock already. */
-> 126 	  AVER(res == 0); /* <design/check/#.common> */
   127 	
   128 	  /* This should be the first claim.  Now we own the mutex */
   129 	  /* it is ok to check this. */
(lldb) up
frame #5: 0x000000000068f5b2 managed_object_tests_debug`ArenaEnterLock(arena=0x00007ffff626e000, recursive=0) at global.c:576:5
   573 	  if(recursive) {
   574 	    LockClaimRecursive(lock);
   575 	  } else {
-> 576 	    LockClaim(lock);
   577 	  }
   578 	  AVERT(Arena, arena); /* can't AVERT it until we've got the lock */
   579 	  if(recursive) {
(lldb) 
frame #6: 0x0000000000622db7 managed_object_tests_debug`ArenaEnter(arena=0x00007ffff626e000) at global.c:553:3
   550 	
   551 	void ArenaEnter(Arena arena)
   552 	{
-> 553 	  ArenaEnterLock(arena, FALSE);
   554 	}
   555 	
   556 	/*  The recursive argument specifies whether to claim the lock
(lldb) 
frame #7: 0x00000000006907b4 managed_object_tests_debug`ArenaAccess(addr=0x00007ffff6eda000, mode=3, context=0x00007ffff67d4e40) at global.c:655:5
   652 	    Arena arena = GlobalsArena(arenaGlobals);
   653 	    Root root;
   654 	
-> 655 	    ArenaEnter(arena);     /* <design/arena#.lock.arena> */
   656 	    EVENT3(ArenaAccessBegin, arena, addr, mode);
   657 	
   658 	    /* @@@@ The code below assumes that Roots and Segs are disjoint. */
(lldb) 
frame #8: 0x00000000007dc03e managed_object_tests_debug`sigHandle(sig=11, info=0x00007fffffffb3b0, uap=0x00007fffffffb280) at protsgix.c:97:11
   94  	
   95  	      /* Offer each protection structure the opportunity to handle the */
   96  	      /* exception.  If it succeeds, then allow the mutator to continue. */
-> 97  	      if (ArenaAccess(base, mode, &context))
   98  	        goto done;
   99  	    }
   100 	
(lldb)

if we check the lock when in asan

#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER)
// ASAN in use, duplicate code path to reduce the number of branches for conditional LockIsHeld statements
// ASAN in use, check if we are locked, this may happen if we fault on a protected page in asan
//                 while scanning the stack, at which point
//                  we already have a lock, we faulted while scanning, we must recover without locking
    if (ArenaBusy(arena)) {

we discover that No segment or root was found at the address

when looking in the maps, the address 0x7ffff6eda000 corresponds to 7ffff6eda000-7ffff76da000 ---p 00000000 00:00 0

which has been set to PROT_NONE

* thread #1, name = 'managed_object_', stop reason = signal SIGSEGV: address access protected (fault address: 0x7ffff6eda000)
    frame #0: 0x0000000000646412 managed_object_tests_debug`mps_scan_area_tagged(ss=0x00007ffff66e8a28, base=0x00007ffff6468360, limit=0x00007ffffffff000, closure=0x00007ffff3732a68) at scan.c:215:3
   212 	  mps_word_t mask = tag->mask;
   213 	  mps_word_t pattern = tag->pattern;
   214 	
-> 215 	  MPS_SCAN_AREA(tag_bits == pattern);
   216 	
   217 	  return MPS_RES_OK;
   218 	}

additionally e = kill(getpid(), PROT_SIGNAL); crashes in asan during the above handling regardless of whether we attempt to handle the address or not

keeping in mind this ONLY happens in ASAN (fsanitise), outside of ASAN everything works normally

@mgood7123
Copy link

mgood7123 commented Sep 20, 2023

it appears that both malloc and mmap return memory pointing to the fake stack

@mgood7123
Copy link

mgood7123 commented Sep 21, 2023

this is our current manually computed memory mapping

0x7ffff3700000 <- mmap

0x7ffff3780948 <- last reserved pointer before collect

0x7ffff620a010 <- malloc

0x7ffff6270000 <- mmap
0x7ffff6270000 <- arena

0x7ffff6270d50 <- &arena->stackWarm
0x7ffff6270d50 <- 1 StackHot(stackOut=0x00007ffff6270d50)
0x7ffff6270d50 <- 2 StackHot(stackOut=0x00007ffff6270d50)

0x7ffff63c3000 <- fake stack
0x7ffff63c3000 <- stackCold

0x7ffff63e9060 <- 1 &stackOut

0x7ffff6468320 <- 2 &stackOut
0x7ffff6468320 <- arena->stackWarm
0x7ffff6468320 <- warmest

0x7ffff6ecc000 <- fake stack
assert(warmest < stackCold) // fails

@mgood7123
Copy link

if we scan the real stack instead then we seem to not be able to pick up memory allocations correctly in an asan build

@mgood7123
Copy link

mgood7123 commented Sep 21, 2023

so, in regards to #259

scanning the real stack, combined with forcefully reclaiming all references upon shutdown, works

export TEST_TMPDIR=debug_asan_EXECUTABLE_TMP; for file in debug_asan_EXECUTABLE/* ; do echo "testing $file..." ; ASAN_OPTIONS=verbosity=1:detect_leaks=1:detect_stack_use_after_return=1:check_initialization_order=true:strict_init_order=true:debug=1 $file ; echo "$file returned with code $?" ; done

testing debug_asan_EXECUTABLE/managed_object_tests_debug...

/* ...  */

debug_asan_EXECUTABLE/managed_object_tests_debug returned with code 0

testing debug_asan_EXECUTABLE/managed_object_tests_no_debug...
==137580==AddressSanitizer: failed to intercept '__isoc99_printf'
==137580==AddressSanitizer: failed to intercept '__isoc99_sprintf'
==137580==AddressSanitizer: failed to intercept '__isoc99_snprintf'
==137580==AddressSanitizer: failed to intercept '__isoc99_fprintf'
==137580==AddressSanitizer: failed to intercept '__isoc99_vprintf'
==137580==AddressSanitizer: failed to intercept '__isoc99_vsprintf'
==137580==AddressSanitizer: failed to intercept '__isoc99_vsnprintf'
==137580==AddressSanitizer: failed to intercept '__isoc99_vfprintf'
==137580==AddressSanitizer: failed to intercept 'xdr_destroy'
==137580==AddressSanitizer: failed to intercept 'crypt'
==137580==AddressSanitizer: failed to intercept 'crypt_r'
==137580==AddressSanitizer: failed to intercept '__cxa_rethrow_primary_exception'
==137580==AddressSanitizer: libc interceptors initialized
|| `[0x10007fff8000, 0x7fffffffffff]` || HighMem    ||
|| `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
|| `[0x00008fff7000, 0x02008fff6fff]` || ShadowGap  ||
|| `[0x00007fff8000, 0x00008fff6fff]` || LowShadow  ||
|| `[0x000000000000, 0x00007fff7fff]` || LowMem     ||
MemToShadow(shadow): 0x00008fff7000 0x000091ff6dff 0x004091ff6e00 0x02008fff6fff
redzone=16
max_redzone=2048
quarantine_size_mb=256M
thread_local_quarantine_size_kb=1024K
malloc_context_size=30
SHADOW_SCALE: 3
SHADOW_GRANULARITY: 8
SHADOW_OFFSET: 0x7fff8000
==137580==Installed the sigaction for signal 11
==137580==Installed the sigaction for signal 7
==137580==Installed the sigaction for signal 8
==137580==T0: FakeStack created: 0x7f8a78dd1000 -- 0x7f8a798da000 stack_size_log: 20; mmapped 11300K, noreserve=0 
==137580==T0: stack [0x7fff9b4cc000,0x7fff9bccc000) size 0x800000; local=0x7fff9bcc9684
==137580==AddressSanitizer Init done
Running main() from /home/DATA/git/Gecko/HTML/qparse/ManagedObject/googletest/googletest/src/gtest_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from MPS_collect2
[ RUN      ] MPS_collect2.1
MPS: MMAP PROT_NONE AT ADDRESS 0x7f8a7a844000 WITH SIZE 0x1000
MPS: ALIGNED ADDRESS TO 0x7f8a7a844000 WITH SIZE 0x1000
MPS: MMAP PROT_NONE AT ADDRESS 0x7f8a76100000 WITH SIZE 0x2000000
MPS: ALIGNED ADDRESS TO 0x7f8a76100000 WITH SIZE 0x2000000
thread stack bottom: 0x7fff9bccc000
reserved and comitted object 0x7f8a76132000 with pointer 0x615000000080
reserved and comitted object 0x7f8a76132018 with pointer 0x615000000300
second collect, p should be collected
object 0x7f8a76180000 with pointer 0x615000000080 is being freed.
Total Collection duration: 0 seconds, 2 milliseconds, 351 microseconds
deinit - destroy all roots
deinit - destroyed all roots
deinit - collect
object 0x7f8a76182000 with pointer 0x615000000300 is being freed.
Total Collection duration: 0 seconds, 1 milliseconds, 351 microseconds
deinit - collected
deinit - shutdown
MPS: MUNMAP ADDRESS 0x7f8a76100000 WITH SIZE 0x2000000
MPS: MUNMAP ADDRESS 0x7f8a7a844000 WITH SIZE 0x1000
[       OK ] MPS_collect2.1 (19 ms)
[----------] 1 test from MPS_collect2 (19 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (21 ms total)
[  PASSED  ] 1 test.
debug_asan_EXECUTABLE/managed_object_tests_no_debug returned with code 0

@mgood7123
Copy link

mgood7123 commented Sep 21, 2023

a rough git-diff for ASAN support

diff --git a/code/scan.c b/code/scan.c
index 308cffc..83c2295 100644
--- a/code/scan.c
+++ b/code/scan.c
@@ -42,6 +42,92 @@
     }                                                   \
   } MPS_SCAN_END(ss);
 
+// ASAN SUPPORT
+
+#if defined(__has_feature)
+  /* __has_feature() is supported.      */
+# if __has_feature(address_sanitizer)
+#   define MPS_ADDRESS_SANITIZER
+# endif
+# if __has_feature(memory_sanitizer)
+#   define MPS_MEMORY_SANITIZER
+# endif
+# if __has_feature(thread_sanitizer)
+#   define MPS_THREAD_SANITIZER
+# endif
+#else
+# ifdef __SANITIZE_ADDRESS__
+    /* GCC v4.8+ */
+#   define MPS_ADDRESS_SANITIZER
+# endif
+# if defined(__SANITIZE_THREAD__)
+    /* GCC v7.1+ */
+#   define MPS_THREAD_SANITIZER
+# endif
+#endif /* !__has_feature */
+
+/* Convenient internal macro to test version of Clang.  */
+#if defined(__clang__) && defined(__clang_major__)
+# define MPS_GC_CLANG_PREREQ(major, minor) \
+    ((__clang_major__ << 8) + __clang_minor__ >= ((major) << 8) + (minor))
+# define MPS_GC_CLANG_PREREQ_FULL(major, minor, patchlevel) \
+            (MPS_GC_CLANG_PREREQ(major, (minor) + 1) \
+                || (__clang_major__ == (major) && __clang_minor__ == (minor) \
+                    && __clang_patchlevel__ >= (patchlevel)))
+#else
+# define MPS_GC_CLANG_PREREQ(major, minor) 0 /* FALSE */
+# define MPS_GC_CLANG_PREREQ_FULL(major, minor, patchlevel) 0
+#endif
+
+/* Convenient internal macro to test version of gcc.    */
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define MPS_GC_GNUC_PREREQ(major, minor) \
+            ((__GNUC__ << 8) + __GNUC_MINOR__ >= ((major) << 8) + (minor))
+#else
+# define MPS_GC_GNUC_PREREQ(major, minor) 0 /* FALSE */
+#endif
+
+#ifndef MPS_GC_ATTR_NO_SANITIZE_ADDR
+# ifndef MPS_ADDRESS_SANITIZER
+#   define MPS_GC_ATTR_NO_SANITIZE_ADDR /* empty */
+# elif MPS_GC_CLANG_PREREQ(3, 8)
+#   define MPS_GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize("address")))
+# else
+#   define MPS_GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize_address))
+# endif
+#endif /* !MPS_GC_ATTR_NO_SANITIZE_ADDR */
+
+#ifndef MPS_GC_ATTR_NO_SANITIZE_MEMORY
+# ifndef MPS_MEMORY_SANITIZER
+#   define MPS_GC_ATTR_NO_SANITIZE_MEMORY /* empty */
+# elif MPS_GC_CLANG_PREREQ(3, 8)
+#   define MPS_GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
+# else
+#   define MPS_GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+# endif
+#endif /* !MPS_GC_ATTR_NO_SANITIZE_MEMORY */
+
+#ifndef MPS_GC_ATTR_NO_SANITIZE_THREAD
+# ifndef MPS_THREAD_SANITIZER
+#   define MPS_GC_ATTR_NO_SANITIZE_THREAD /* empty */
+# elif MPS_GC_CLANG_PREREQ(3, 8)
+#   define MPS_GC_ATTR_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
+# else
+    /* It seems that no_sanitize_thread attribute has no effect if the  */
+    /* function is inlined (as of gcc 11.1.0, at least).                */
+#   ifndef MPS_GC_ATTR_NOINLINE
+#    if MPS_GC_GNUC_PREREQ(4, 0)
+#      define MPS_GC_ATTR_NOINLINE __attribute__((__noinline__))
+#    elif _MSC_VER >= 1400
+#      define MPS_GC_ATTR_NOINLINE __declspec(noinline)
+#    else
+#      define MPS_GC_ATTR_NOINLINE /* empty */
+#    endif
+#   endif
+#   define MPS_GC_ATTR_NO_SANITIZE_THREAD \
+                MPS_GC_ATTR_NOINLINE __attribute__((no_sanitize_thread))
+# endif
+#endif /* !MPS_GC_ATTR_NO_SANITIZE_THREAD */
 
 /* mps_scan_area -- scan contiguous area of references
  *
@@ -53,6 +139,9 @@
  * simple untagged references.
  */
 
+MPS_GC_ATTR_NO_SANITIZE_ADDR
+MPS_GC_ATTR_NO_SANITIZE_MEMORY
+MPS_GC_ATTR_NO_SANITIZE_THREAD
 mps_res_t mps_scan_area(mps_ss_t ss,
                         void *base, void *limit,
                         void *closure)
@@ -79,6 +168,9 @@ mps_res_t mps_scan_area(mps_ss_t ss,
  * as references no matter what tag they have.
  */
 
+MPS_GC_ATTR_NO_SANITIZE_ADDR
+MPS_GC_ATTR_NO_SANITIZE_MEMORY
+MPS_GC_ATTR_NO_SANITIZE_THREAD
 mps_res_t mps_scan_area_masked(mps_ss_t ss,
                                void *base, void *limit,
                                void *closure)
@@ -101,6 +193,9 @@ mps_res_t mps_scan_area_masked(mps_ss_t ss,
  * only fix words whose low order bits are 0b101.
  */
 
+MPS_GC_ATTR_NO_SANITIZE_ADDR
+MPS_GC_ATTR_NO_SANITIZE_MEMORY
+MPS_GC_ATTR_NO_SANITIZE_THREAD
 mps_res_t mps_scan_area_tagged(mps_ss_t ss,
                                void *base, void *limit,
                                void *closure)
@@ -130,6 +225,9 @@ mps_res_t mps_scan_area_tagged(mps_ss_t ss,
  * addresses of objects around which must not be ignored.
  */
 
+MPS_GC_ATTR_NO_SANITIZE_ADDR
+MPS_GC_ATTR_NO_SANITIZE_MEMORY
+MPS_GC_ATTR_NO_SANITIZE_THREAD
 mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t ss,
                                        void *base, void *limit,
                                        void *closure)
diff --git a/code/ss.c b/code/ss.c
index ce08810..900f2c4 100644
--- a/code/ss.c
+++ b/code/ss.c
@@ -35,7 +35,96 @@ SRCID(ss, "$Id$");
 ATTRIBUTE_NOINLINE
 void StackHot(void **stackOut)
 {
+// ASAN SUPPORT
+
+#if defined(__has_feature)
+  /* __has_feature() is supported.      */
+# if __has_feature(address_sanitizer)
+#   define MPS_ADDRESS_SANITIZER
+# endif
+# if __has_feature(memory_sanitizer)
+#   define MPS_MEMORY_SANITIZER
+# endif
+# if __has_feature(thread_sanitizer)
+#   define MPS_THREAD_SANITIZER
+# endif
+#else
+# ifdef __SANITIZE_ADDRESS__
+    /* GCC v4.8+ */
+#   define MPS_ADDRESS_SANITIZER
+# endif
+# if defined(__SANITIZE_THREAD__)
+    /* GCC v7.1+ */
+#   define MPS_THREAD_SANITIZER
+# endif
+#endif /* !__has_feature */
+
+# ifdef MPS_ADDRESS_SANITIZER
+    // asan uses a fake stack, obtain the real stack
+
+    /* Define word and signed word to be unsigned and signed types of the   */
+    /* size as char* or void*.                                              */
+    /* A macro to define integer types of a pointer size.  There seems to   */
+    /* be no way to do this even semi-portably.  The following is probably  */
+    /* no better/worse than almost anything else.                           */
+    /* The ANSI standard suggests that size_t and ptrdiff_t might be        */
+    /* better choices.  But those had incorrect definitions on some older   */
+    /* systems; notably "typedef int size_t" is wrong.                      */
+#    ifdef _WIN64
+#     if defined(__int64) && !defined(CPPCHECK)
+#       define MPS_GC_SIGNEDWORD __int64
+#     else
+#       define MPS_GC_SIGNEDWORD long long
+#     endif
+#    else
+#     define MPS_GC_SIGNEDWORD long
+#    endif
+
+#    define MPS_GC_UNSIGNEDWORD unsigned MPS_GC_SIGNEDWORD
+
+    typedef MPS_GC_UNSIGNEDWORD MPS_GC_word;
+
+    typedef MPS_GC_word MPS_word;
+
+    volatile MPS_word sp;
+
+#   if defined(__ANDROID__) && !defined(HOST_ANDROID)
+     /* __ANDROID__ macro is defined by Android NDK gcc.   */
+#    define HOST_ANDROID 1
+#   endif
+
+    /* First a unified test for Linux: */
+#   if (defined(linux) || defined(__linux__) || defined(HOST_ANDROID)) \
+       && !defined(LINUX) && !defined(__native_client__)
+#     define LINUX
+#   endif
+
+#   if defined(__e2k__) && defined(LINUX)
+#      define E2K
+#   elif defined(__s390__) && defined(LINUX)
+#      define S390
+#   endif
+
+#   if ((defined(E2K) && defined(__clang__)) \
+        || (defined(S390) && (__clang_major__ < 8))) && !defined(CPPCHECK)
+        /* Workaround some bugs in clang:                                   */
+        /* "undefined reference to llvm.frameaddress" error (clang-9/e2k);  */
+        /* a crash in SystemZTargetLowering of libLLVM-3.8 (S390).          */
+        sp = (MPS_word)&sp;
+#   elif defined(CPPCHECK) || (__GNUC__ >= 4 /* MANAGED_STACK_ADDRESS_BOEHM_GC_GNUC_PREREQ(4, 0) */ \
+                               && !defined(MPS_STACK_NOT_SCANNED))
+        /* TODO: Use MANAGED_STACK_ADDRESS_BOEHM_GC_GNUC_PREREQ after fixing a bug in cppcheck. */
+        sp = (MPS_word)__builtin_frame_address(0);
+#   else
+        sp = (MPS_word)&sp;
+#   endif
+                /* Also force stack to grow if necessary. Otherwise the */
+                /* later accesses might cause the kernel to think we're */
+                /* doing something wrong.                               */
+    *stackOut = (void*)sp;
+# else
   *stackOut = &stackOut;
+# endif
 }

@mgood7123
Copy link

do note however, obtaining the real stack base (thread stack bottom: 0x7fff9bccc000) (boehm GC_get_stack_base) seems to be lots of #ifdef for all different platforms, see https://github.com/ivmai/bdwgc/blob/master/os_dep.c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
build Problems with builds and build automation needs analaysis The issue needs analysis before it can be resolved. nice Little impact; only do if low cost
Projects
None yet
Development

No branches or pull requests

3 participants