Skip to content

AddressSanitizer: false positives with structs/tuples that end with Zero Sized Types #39882

Closed
@dimbleby

Description

@dimbleby

Update

STR

fn main () {
    let mut x = (4, ());
    unsafe {
        std::ptr::write(&mut x, (3, ()));
    }
}
$ RUSTFLAGS="-Z sanitizer=address" cargo run --target x86_64-unknown-linux-gnu
    Running `target/x86_64-unknown-linux-gnu/debug/gh39882`
=================================================================
==25622==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcdeb06284 at pc 0x55e19fbf269b bp 0x7ffcdeb06250 sp 0x7ffcdeb06248
ACCESS of size 0 at 0x7ffcdeb06284 thread T0
(..)
  This frame has 3 object(s):
    [32, 36) 'arg' <== Memory access at offset 36 is inside this variable
    [48, 52) '_7'
    [64, 68) 'x'
(..)

Meta

$ rustc -V
rustc 1.17.0-nightly (60a0edc6c 2017-02-26)

Cause

We produce loads of the zero sized types in LLVM-IR.

$ cargo rustc -- --emit=llvm-ir

$ cat $(find -name '*.ll')
define internal void @_ZN7gh398824main17hc6881d8c6f884174E() unnamed_addr #1 !dbg !34 {
entry-block:
(..)
start:
(..)
  %6 = getelementptr inbounds { i32, {} }, { i32, {} }* %arg, i32 0, i32 1, !dbg !42
  store {} undef, {}* %6, !dbg !42
(..)

Workaround

Append a non zero sized type to your struct so the ZST is not the last field of the struct. You could do this only if a feature is enabled to avoid changing the API of your crate.

pub struct Offender {
    payload: u32,
    zero_sized_type: (),  // or PhantomData
    #[cfg(feature = "asan")]
    workaround: u8,
}

Then test with:

$ RUSTFLAGS="-Z sanitizer=address" cargo run --target x86_64-unknown-linux-gnu --feature asan

Fix

Remove those loads by specializing the treatment of zero sized types in trans. As per @eddyb comment.


Original report

program:

use std::collections::HashSet;

pub fn main() {
    let mut hash_set = HashSet::<i32>::new();
    hash_set.insert(42);
}

rustc version: 1.17.0-nightly (62eb605 2017-02-15)

build:

[asan]$ RUSTFLAGS="-Z sanitizer=address" cargo +nightly build --target x86_64-unknown-linux-gnu
   Compiling asan v0.1.0 (file:///data/dch/asan)
    Finished dev [unoptimized + debuginfo] target(s) in 1.8 secs

result:

[asan]$ ./target/x86_64-unknown-linux-gnu/debug/asan
=================================================================
==3100==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd196acb24 at pc 0x7f4a672abbd6 bp 0x7ffd196acaf0 sp 0x7ffd196acae8
ACCESS of size 0 at 0x7ffd196acb24 thread T0
    #0 0x7f4a672abbd5 in _$LT$std..collections..hash..table..EmptyBucket$LT$K$C$$u20$V$C$$u20$M$GT$$GT$::put::h4dcbd19464a4eb32 /checkout/src/libstd/collections
/hash/table.rs:450
    #1 0x7f4a672ac7e7 in _$LT$std..collections..hash..map..VacantEntry$LT$$u27$a$C$$u20$K$C$$u20$V$GT$$GT$::insert::h1f23562a9244108b /checkout/src/libstd/colle
ctions/hash/map.rs:2070
    #2 0x7f4a672a3d34 in _$LT$std..collections..hash..map..HashMap$LT$K$C$$u20$V$C$$u20$S$GT$$GT$::insert_hashed_nocheck::hc786fd8d25a77f8d /checkout/src/libstd
/collections/hash/map.rs:805
    #3 0x7f4a672a4c28 in _$LT$std..collections..hash..map..HashMap$LT$K$C$$u20$V$C$$u20$S$GT$$GT$::insert::h807e2aa556ba41aa /checkout/src/libstd/collections/ha
sh/map.rs:1150
    #4 0x7f4a6729e793 in _$LT$std..collections..hash..set..HashSet$LT$T$C$$u20$S$GT$$GT$::insert::h4a1f9ecc174ad965 /checkout/src/libstd/collections/hash/set.rs
:585
    #5 0x7f4a672ad401 in asan::main::h9b63a9a755bc73af /data/dch/asan/src/main.rs:5
    #6 0x7f4a673a787a in __rust_maybe_catch_panic /checkout/src/libpanic_unwind/lib.rs:98
    #7 0x7f4a673a00b6 in std::panicking::try<(),fn()> /checkout/src/libstd/panicking.rs:429
    #8 0x7f4a673a00b6 in std::panic::catch_unwind<fn(),()> /checkout/src/libstd/panic.rs:361
    #9 0x7f4a673a00b6 in std::rt::lang_start::hb7fc7ec87b663023 /checkout/src/libstd/rt.rs:57
    #10 0x7f4a672ad4d2 in main (/data/dch/asan/target/x86_64-unknown-linux-gnu/debug/asan+0x284d2)
    #11 0x7f4a66485b34 in __libc_start_main (/lib64/libc.so.6+0x21b34)
    #12 0x7f4a6728e6a5 in _start (/data/dch/asan/target/x86_64-unknown-linux-gnu/debug/asan+0x96a5)

Address 0x7ffd196acb24 is located in stack of thread T0 at offset 36 in frame
    #0 0x7f4a672ab68f in _$LT$std..collections..hash..table..EmptyBucket$LT$K$C$$u20$V$C$$u20$M$GT$$GT$::put::h4dcbd19464a4eb32 /checkout/src/libstd/collections
/hash/table.rs:447

  This frame has 8 object(s):
    [32, 36) 'arg' <== Memory access at offset 36 is inside this variable
    [48, 64) '_20'
    [80, 84) '_15'
    [96, 104) 'hash'
    [128, 160) 'self'
    [192, 200) 'abi_cast'
    [224, 232) 'arg1'
    [256, 288) 'arg0'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /checkout/src/libstd/collections/hash/table.rs:450 in _$LT$std..collections..hash..table..EmptyBucket$LT$K$C$$u
20$V$C$$u20$M$GT$$GT$::put::h4dcbd19464a4eb32
Shadow bytes around the buggy address:
  0x1000232cd910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000232cd920: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000232cd930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000232cd940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000232cd950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1000232cd960: f1 f1 f1 f1[04]f2 00 00 f2 f2 04 f2 00 f2 f2 f2
  0x1000232cd970: 00 00 00 00 f2 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2
  0x1000232cd980: 00 00 00 00 f3 f3 f3 f3 00 00 00 00 00 00 00 00
  0x1000232cd990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000232cd9a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000232cd9b0: 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
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  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
==3100==ABORTING

Of course it's possible that this is a false positive, though my experience in C and C++ has been that it's very rare indeed for the address sanitiser to produce such.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-sanitizersArea: Sanitizers for correctness and code qualityC-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions