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

AddressSanitizer detects a stack-use-after-scope in Chain::new when optimizations are enabled #98454

Open
saethlin opened this issue Jun 24, 2022 · 3 comments
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-sanitizers Area: Sanitizers for correctness and code quality C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@saethlin
Copy link
Member

I compiled this code:

fn main() {
    let _ = (1..).chain(1..);
}

With

rustc +nightly main.rs -Copt-level=2 -Zsanitizer=address

opt-level 2, 3, s, or z seems required. Then I ran the executable with

ASAN_OPTIONS="detect_stack_use_after_return=1" ./main

And I get this report:

=================================================================
==1119479==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fc1a9800060 at pc 0x563ef1461001 bp 0x7fff3c3d6960 sp 0x7fff3c3d6958
WRITE of size 4 at 0x7fc1a9800060 thread T0
    #0 0x563ef1461000 in core::iter::adapters::chain::Chain$LT$A$C$B$GT$::new::h87dc973e346089b7 (/tmp/scratch/main+0xa5000) (BuildId: b43392194c5765b793d61a1637ec613b6787ae8e)
    #1 0x563ef1460ee6 in main::main::h21fbbba3400697d2 main.84aa171d-cgu.1
    #2 0x563ef1460f5e in std::sys_common::backtrace::__rust_begin_short_backtrace::hf1ca2929dbe1bc2b (/tmp/scratch/main+0xa4f5e) (BuildId: b43392194c5765b793d61a1637ec613b6787ae8e)
    #3 0x563ef1460dd0 in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h911d5468a8b43c74 main.84aa171d-cgu.0
    #4 0x563ef14721fd in core::ops::function::impls::_$LT$impl$u20$core..ops..function..FnOnce$LT$A$GT$$u20$for$u20$$RF$F$GT$::call_once::ha8a8e65ef30bbc60 /rustc/dc80ca78b6ec2b6bba02560470347433bcd0bb3c/library/core/src/ops/function.rs:280:13
    #5 0x563ef14721fd in std::panicking::try::do_call::hf31b0c375d768911 /rustc/dc80ca78b6ec2b6bba02560470347433bcd0bb3c/library/std/src/panicking.rs:492:40
    #6 0x563ef14721fd in std::panicking::try::he7eee203c4f60352 /rustc/dc80ca78b6ec2b6bba02560470347433bcd0bb3c/library/std/src/panicking.rs:456:19
    #7 0x563ef14721fd in std::panic::catch_unwind::h454666a6b91fdf61 /rustc/dc80ca78b6ec2b6bba02560470347433bcd0bb3c/library/std/src/panic.rs:137:14
    #8 0x563ef14721fd in std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::h379590a88f2dcb30 /rustc/dc80ca78b6ec2b6bba02560470347433bcd0bb3c/library/std/src/rt.rs:128:48
    #9 0x563ef14721fd in std::panicking::try::do_call::h6290c1b8cfa21d25 /rustc/dc80ca78b6ec2b6bba02560470347433bcd0bb3c/library/std/src/panicking.rs:492:40
    #10 0x563ef14721fd in std::panicking::try::ha9e207d6028be8bb /rustc/dc80ca78b6ec2b6bba02560470347433bcd0bb3c/library/std/src/panicking.rs:456:19
    #11 0x563ef14721fd in std::panic::catch_unwind::hb3824d741f348baf /rustc/dc80ca78b6ec2b6bba02560470347433bcd0bb3c/library/std/src/panic.rs:137:14
    #12 0x563ef14721fd in std::rt::lang_start_internal::hbcf57b2e346b06f1 /rustc/dc80ca78b6ec2b6bba02560470347433bcd0bb3c/library/std/src/rt.rs:128:20
    #13 0x563ef1460d67 in std::rt::lang_start::hed96c56ac3053e5d (/tmp/scratch/main+0xa4d67) (BuildId: b43392194c5765b793d61a1637ec613b6787ae8e)
    #14 0x7fc1ab62928f  (/usr/lib/libc.so.6+0x2928f) (BuildId: 60df1df31f02a7b23da83e8ef923359885b81492)
    #15 0x7fc1ab629349 in __libc_start_main (/usr/lib/libc.so.6+0x29349) (BuildId: 60df1df31f02a7b23da83e8ef923359885b81492)
    #16 0x563ef13c89a4 in _start /build/glibc/src/glibc/csu/../sysdeps/x86_64/start.S:115

Address 0x7fc1a9800060 is located in stack of thread T0 at offset 32 in frame
    #0 0x563ef1460e69 in main::main::h21fbbba3400697d2 main.84aa171d-cgu.1

  This frame has 1 object(s):
    [32, 48) '_1' <== 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-scope (/tmp/scratch/main+0xa5000) (BuildId: b43392194c5765b793d61a1637ec613b6787ae8e) in core::iter::adapters::chain::Chain$LT$A$C$B$GT$::new::h87dc973e346089b7
Shadow bytes around the buggy address:
  0x0ff8b52f7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff8b52f7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff8b52f7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff8b52f7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff8b52f7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0ff8b52f8000: f1 f1 f1 f1 00 f3 f3 f3 f1 f1 f1 f1[f8]f8 f3 f3
  0x0ff8b52f8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff8b52f8020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff8b52f8030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff8b52f8040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ff8b52f8050: 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
==1119479==ABORTING

without detect_stack_use_after_return=1 I get this error, with the same backtrace:

AddressSanitizer: CHECK failed: asan_thread.cpp:370 "((ptr[0] == kCurrentStackFrameMagic)) != (0)" (0x0, 0x0) (tid=1173482)

Meta

rustc --version --verbose:

rustc 1.63.0-nightly (dc80ca78b 2022-06-21)
binary: rustc
commit-hash: dc80ca78b6ec2b6bba02560470347433bcd0bb3c
commit-date: 2022-06-21
host: x86_64-unknown-linux-gnu
release: 1.63.0-nightly
LLVM version: 14.0.5

@rustbot labels +A-llvm +A-sanitizers

@saethlin saethlin added the C-bug Category: This is a bug. label Jun 24, 2022
@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-sanitizers Area: Sanitizers for correctness and code quality labels Jun 24, 2022
@saethlin
Copy link
Member Author

saethlin commented Jun 24, 2022

I found another example of this, which I've managed to reduce by hand to at least not rely on the standard library:

pub struct Thing<T> {
    a: (u8, u8, u8),
    b: T,
}

impl<T> Thing<T> {
    pub fn new(b: T) -> Thing<T> {
        Thing { a: (0, 0, 0), b }
    }
}

fn main() {
    Thing::new(0usize);
}

... except that this can only be reproduced with (again any opt-level above 1 will do)

ASAN_OPTIONS=detect_stack_use_after_return=1 RUSTFLAGS="-Zsanitizer=address -Copt-level=2" cargo +nightly run

Compiling just with rustc or with CARGO_INCREMENTAL=0 gets rid of the ASan report. So perhaps this is actually an incremental compilation bug? My original example doesn't go away if I set CARGO_INCREMENTAL=0, but it does go away with -Ccodegen-units=1 so maybe that's relevant?

@saethlin
Copy link
Member Author

I don't think this is an incremental compilation bug, just a fragile pattern. I found another example which requires CARGO_INCREMENTAL=0 but it looks rough to minimize, so I'll update later if I manage to minimize it.

@tmiasko
Copy link
Contributor

tmiasko commented Jun 24, 2022

In the minimized case. The Thing::new function is deduced to be writeonly before AddressSanitizer instrumentation. Subsequently the function is instrumented introducing reads from shadow memory, but the writeonly attribute is preserved. Finally, the dead store elimination when optimizing main removes stores to the shadow memory before calling Thing::new, working under false assumption that Thing::new cannot observe them.

AddressSanitizer pass should probably update a function attributes to reflect changes it is making. In this case remove writeonly attribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-sanitizers Area: Sanitizers for correctness and code quality C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants