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: false positives with structs/tuples that end with Zero Sized Types #39882

Closed
dimbleby opened this issue Feb 16, 2017 · 27 comments
Labels
A-sanitizers Area: Sanitizers for correctness and code quality C-bug Category: This is a bug.

Comments

@dimbleby
Copy link

dimbleby commented Feb 16, 2017

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.

@sfackler
Copy link
Member

HashSet<T> is a HashMap<T, ()> internally and it looks like ASAN is confused about zero-byte accesses: ACCESS of size 0 at 0x7ffd196acb24 thread T0

@dimbleby
Copy link
Author

Very likely. Here's a more direct repro:

fn main () {
    let mut x = (4, ());
    unsafe {
        std::ptr::write(&mut x, (3, ()));
    }
}

@alexcrichton
Copy link
Member

alexcrichton commented Feb 16, 2017

That'd do it! Should we report this upstream?

@sfackler
Copy link
Member

cc @japaric

@japaric
Copy link
Member

japaric commented Feb 18, 2017

@dimbleby Thanks for the reduced test case.

ACCESS of size 0 at 0x7ffd196acb24 thread T0

This sounded nonsensical to me so I went to look at the generated assembly:

(Sorry, this is ARM assembly as that's what I'm most familiar with)

``` rust #[no_mangle] pub fn _start() -> ! { let mut x = (24, ()); unsafe { ptr::write(&mut x, (42, ())); }
loop {}

}


``` asm
08000134 <_start>:
 8000134:       b580            push    {r7, lr}
 8000136:       466f            mov     r7, sp
 8000138:       b088            sub     sp, #32
 800013a:       e7ff            b.n     800013c <_start+0x8>
 800013c:       2018            movs    r0, #24
 800013e:       9001            str     r0, [sp, #4]
 8000140:       202a            movs    r0, #42 ; 0x2a
 8000142:       9004            str     r0, [sp, #16]
 8000144:       9007            str     r0, [sp, #28]
 8000146:       a901            add     r1, sp, #4
 8000148:       9000            str     r0, [sp, #0]
 800014a:       4608            mov     r0, r1
 800014c:       9900            ldr     r1, [sp, #0]
 800014e:       f000 f803       bl      8000158 <core::ptr::write::h8f7040d3eb269e5e>
 8000152:       e7ff            b.n     8000154 <_start+0x20>
 8000154:       e7ff            b.n     8000156 <_start+0x22>
 8000156:       e7fe            b.n     8000156 <_start+0x22>

08000158 <core::ptr::write::h8f7040d3eb269e5e>:
 8000158:       b087            sub     sp, #28
 800015a:       460a            mov     r2, r1
 800015c:       4603            mov     r3, r0
 800015e:       9002            str     r0, [sp, #8]
 8000160:       9104            str     r1, [sp, #16]
 8000162:       9103            str     r1, [sp, #12]
 8000164:       9201            str     r2, [sp, #4]
 8000166:       9300            str     r3, [sp, #0]
 8000168:       e7ff            b.n     800016a <core::ptr::write::h8f7040d3eb269e5e+0x12>
 800016a:       9802            ldr     r0, [sp, #8]
 800016c:       9005            str     r0, [sp, #20]
 800016e:       9803            ldr     r0, [sp, #12]
 8000170:       9006            str     r0, [sp, #24]
 8000172:       9905            ldr     r1, [sp, #20]
 8000174:       6008            str     r0, [r1, #0]
 8000176:       e7ff            b.n     8000178 <core::ptr::write::h8f7040d3eb269e5e+0x20>
 8000178:       b007            add     sp, #28
 800017a:       4770            bx      lr

and compared it with a ptr::write that doesn't involve a zero sized type:

``` rust #[no_mangle] pub fn _start() -> ! { let mut x = 24; unsafe { ptr::write(&mut x, 42); }
loop {}

}


``` asm
08000134 <_start>:
 8000134:       b580            push    {r7, lr}
 8000136:       466f            mov     r7, sp
 8000138:       b084            sub     sp, #16
 800013a:       e7ff            b.n     800013c <_start+0x8>
 800013c:       2018            movs    r0, #24
 800013e:       9001            str     r0, [sp, #4]
 8000140:       a801            add     r0, sp, #4
 8000142:       212a            movs    r1, #42 ; 0x2a
 8000144:       f000 f803       bl      800014e <core::ptr::write::hb7006988e1de10a2>
 8000148:       e7ff            b.n     800014a <_start+0x16>
 800014a:       e7ff            b.n     800014c <_start+0x18>
 800014c:       e7fe            b.n     800014c <_start+0x18>

0800014e <core::ptr::write::hb7006988e1de10a2>:
 800014e:       b086            sub     sp, #24
 8000150:       460a            mov     r2, r1
 8000152:       4603            mov     r3, r0
 8000154:       9002            str     r0, [sp, #8]
 8000156:       9103            str     r1, [sp, #12]
 8000158:       9201            str     r2, [sp, #4]
 800015a:       9300            str     r3, [sp, #0]
 800015c:       e7ff            b.n     800015e <core::ptr::write::hb7006988e1de10a2+0x10>
 800015e:       9802            ldr     r0, [sp, #8]
 8000160:       9004            str     r0, [sp, #16]
 8000162:       9803            ldr     r0, [sp, #12]
 8000164:       9005            str     r0, [sp, #20]
 8000166:       9904            ldr     r1, [sp, #16]
 8000168:       6008            str     r0, [r1, #0]
 800016a:       e7ff            b.n     800016c <core::ptr::write::hb7006988e1de10a2+0x1e>
 800016c:       b006            add     sp, #24
 800016e:       4770            bx      lr

but apart from some extra stack usage there's no semantic difference and certainly neither of these programs access uninitialized memory.


Next, I looked at the LLVM IR and there I found something interesting:

fn main() {
    let mut x = (24, ());
    unsafe {
        ptr::write(&mut x, (42, ()));
    }
}
define internal void @_ZN5hello4main17hf7b9630e95734ebdE() unnamed_addr #1 !dbg !34 {
entry-block:
  %arg = alloca { i32, {} }
  %_8 = alloca {}
  %_7 = alloca { i32, {} }
  %_2 = alloca {}
  %x = alloca { i32, {} }
  %_0 = alloca {}
  call void @llvm.dbg.declare(metadata { i32, {} }* %x, metadata !38, metadata !24), !dbg !40
  br label %start, !dbg !40

start:                                            ; preds = %entry-block
  %0 = getelementptr inbounds { i32, {} }, { i32, {} }* %x, i32 0, i32 0, !dbg !41
  store i32 24, i32* %0, !dbg !41
  %1 = getelementptr inbounds { i32, {} }, { i32, {} }* %_7, i32 0, i32 0, !dbg !42
  store i32 42, i32* %1, !dbg !42
  %2 = getelementptr inbounds { i32, {} }, { i32, {} }* %_7, i32 0, i32 0, !dbg !43
  %3 = getelementptr inbounds { i32, {} }, { i32, {} }* %_7, i32 0, i32 1, !dbg !43
  %4 = load i32, i32* %2, !dbg !43
  %5 = getelementptr inbounds { i32, {} }, { i32, {} }* %arg, i32 0, i32 0, !dbg !43
  store i32 %4, i32* %5, !dbg !43
  %6 = getelementptr inbounds { i32, {} }, { i32, {} }* %arg, i32 0, i32 1, !dbg !43
  store {} undef, {}* %6, !dbg !43
  %7 = bitcast { i32, {} }* %arg to i32*, !dbg !43
  %8 = load i32, i32* %7, align 4, !dbg !43
  call void @_ZN4core3ptr5write17h6c3e55ca0821fa79E({ i32, {} }* %x, i32 %8), !dbg !43
  br label %bb1, !dbg !43

bb1:                                              ; preds = %start
  ret void, !dbg !44
}

This is the ASan error message for that program:

ACCESS of size 0 at 0x7ffebd56e924 thread T0
    #0 0x55b1e38d425a in hello::main::h845ed3cde81856e0 /home/japaric/tmp/hello/src/main.rs:6
    #1 0x55b1e39cd30b in __rust_maybe_catch_panic /checkout/src/libpanic_abort/lib.rs:40

Address 0x7ffebd56e924 is located in stack of thread T0 at offset 36 in frame
    #0 0x55b1e38d404f in hello::main::h845ed3cde81856e0 /home/japaric/tmp/hello/src/main.rs:3

  This frame has 3 object(s):
    [32, 36) 'arg' <== Memory access at offset 36 is inside this variable
    [48, 52) '_7'
    [64, 68) 'x'

Looking at the two, I have concluded that this chunk of IR is what triggers the false positive in ASan:

  %6 = getelementptr inbounds { i32, {} }, { i32, {} }* %arg, i32 0, i32 1, !dbg !43
  store {} undef, {}* %6, !dbg !43

This is effectively getting a pointer to the () field and storing undef (?) in it. That's the 0 size access that ASan is reporting.

I intent to report this upstream but, first, I'd like to know why rustc is emitting those two lines in the LLVM IR (cc @eddyb) so I can include that in the report. Is it to catch misuses of zero sized types? As in let x = (); let y = unsafe { *(&x as *const () as *mut i32) };. Interestingly that program doesn't trigger an ASan or MSan error, nor does it make use of undef in its LLVM IR.

fn main() {
    let x = ();
    let y = unsafe { *(&x as *const () as *const i32) };
    // println!("{}", y);  // optional
}
define internal void @_ZN5hello4main17hf7b9630e95734ebdE() unnamed_addr #0 !dbg !5 {
entry-block:
  %y = alloca i32
  %x = alloca {}
  %_0 = alloca {}
  call void @llvm.dbg.declare(metadata {}* %x, metadata !10, metadata !13), !dbg !14
  call void @llvm.dbg.declare(metadata i32* %y, metadata !15, metadata !13), !dbg !18
  br label %start, !dbg !18

start:                                            ; preds = %entry-block
  %0 = bitcast {}* %x to i32*, !dbg !19
  %1 = load i32, i32* %0, !dbg !19
  store i32 %1, i32* %y, !dbg !19
  ret void, !dbg !20
}

In general, it seems that ASan & MSan interact poorly with zero sized types:

#include <stdio.h>

typedef struct {} Nil;

int main() {
  Nil nil = {};
  int x = *((int *)&nil);

  printf("%p\n", (void *)&nil);
  printf("%p\n", (void *)&x);
  printf("%d\n", x);
}
$ clang -fsanitize=memory nil.c && ./a.out && ./a.out
0x7ffec40d9740
0x7ffec40d973c
-1005742032
0x7fffbc23e930
0x7fffbc23e92c
-1138496992

@eddyb
Copy link
Member

eddyb commented Feb 18, 2017

So those seem like bugs in the sanitizers, really. OTOH, we could avoid generating loads and stores for ZSTs, I suppose we're just not checking often enough.

EDIT: To be a bit more clear, that's just generic code not being special-cased all over trans.

@japaric japaric changed the title AddressSanitizer reports stack-buffer-overflow when inserting into HashSet AdressSanitizer: false positives with structs/tuples that end with Zero Sized Types Feb 27, 2017
@japaric
Copy link
Member

japaric commented Feb 27, 2017

Updated the issue description to better reflect the problem and the possible fix and also documented a workaround.

@Manishearth
Copy link
Member

cc @kcc Is it an ASan bug that a load to a zero sized type at the end of a buffer is caught by the sanitizer? Or should we just not generate loads for such things?

@sgrif
Copy link
Contributor

sgrif commented Mar 9, 2017

It seems like both of those things are true.

@Manishearth
Copy link
Member

Fair.

killercup added a commit to killercup/targets that referenced this issue Mar 14, 2017
Fixes rust-fuzz#25

Does not compile currently as it exits with

> ERROR: AddressSanitizer: heap-buffer-overflow […]
> ACCESS of size 0

cf. rust-lang/rust#39882
@shepmaster shepmaster changed the title AdressSanitizer: false positives with structs/tuples that end with Zero Sized Types AddressSanitizer: false positives with structs/tuples that end with Zero Sized Types May 3, 2017
@ishitatsuyuki
Copy link
Contributor

I believe this should have a high priority since ASan is completely useless if such code is generated for std.

I wasn't able to determine how it generates store instructions, but this should be simple for devs who're familiar with LLVM.

@eddyb
Copy link
Member

eddyb commented May 7, 2017

@japaric Is this still a problem after #40367?

@ishitatsuyuki
Copy link
Contributor

@eddyb yes, reproduced locally 2017-05-03 build.

@eddyb
Copy link
Member

eddyb commented May 7, 2017

Ah, I see, the {} alloca for the return is gone but the stores are still there.

@ishitatsuyuki
Copy link
Contributor

A note on implementing: apart from alloca, copy_intrinsic should also be fixed.

There should also be a test similar to this, on read, read_unaligned, write and write_unaligned.

@eddyb
Copy link
Member

eddyb commented May 7, 2017

@istankovic That test could house ptr::write and ptr::write_unaligned as well.

@ishitatsuyuki
Copy link
Contributor

@eddyb wrong name :P

Yeah, we can put all the things to that test, but I wanted to separate because that file is labeled with MIR.

@eddyb
Copy link
Member

eddyb commented May 7, 2017

Ah, I see what's happening, the test was added when MIR trans was opt-in, whereas this is a long-standing problem with the rest of trans that got carried over.

@Kixunil
Copy link
Contributor

Kixunil commented Jun 6, 2017

I just hit the same bug in serde_json:

extern crate serde;
#[macro_use]
extern crate serde_json;

fn main() {
    let val = json!({
        "Hello": "world"
    });

    println!("{}", serde_json::to_string(&val).unwrap());
}
$ RUSTFLAGS="-Z sanitizer=address" cargo run --target x86_64-apple-darwin
...
=================================================================
==89645==ERROR: AddressSanitizer: 6?E on address 0x7fff5aac4508 at pc 0x0001051796bb bp 0x7fff5aac44d0 sp 0x7fff5aac44c8
ACCESS of size 0 at 0x7fff5aac4508 thread T0
...

To clarify: the program aborts in serde_json::to_string().

@eddyb
Copy link
Member

eddyb commented Jun 6, 2017

Via play.integer32.com I found that serde_json::ser::Serializer::new contains a store of a ZST.

That specific store is gone in #42486, although I can't know for sure it's the exact issue here.
(-Z sanitizer=address results in linker errors for me so I can't directly test the effect of the change)

@Kixunil
Copy link
Contributor

Kixunil commented Jun 7, 2017

@eddyb Thanks! I will try it when it's merged.

bors added a commit that referenced this issue Jun 7, 2017
rustc_trans: do not store pair fields if they are ZSTs.

Should help with #39882 even if it's not a complete fix AFAICT.
@kennytm
Copy link
Member

kennytm commented Jun 7, 2017

(cc #39699 tracking issue for sanitizers)

@Kixunil
Copy link
Contributor

Kixunil commented Jun 13, 2017

Sorry, I forgot about this. That PR helped me.

Thank you!

@Mark-Simulacrum Mark-Simulacrum added the A-sanitizers Area: Sanitizers for correctness and code quality label Jun 23, 2017
bors bot added a commit to rust-fuzz/targets that referenced this issue Jun 27, 2017
53: Add fuzz target for html5ever r=frewsxcv

Fixes #25

Does not compile currently as it exits with

> ERROR: AddressSanitizer: heap-buffer-overflow […]
> ACCESS of size 0

cf. rust-lang/rust#39882
@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 27, 2017
@kennytm
Copy link
Member

kennytm commented Aug 13, 2017

As of 1.21.0-nightly (f774bce 2017-08-12), x86_64-unknown-linux-gnu:

Could anyone produce an updated test case, or declare that this has actually been fixed?

@ishitatsuyuki
Copy link
Contributor

@kennytm I think this is OK to close. My test case:

fn main() {
    let mut x = ();
    unsafe {
        std::ptr::read(&mut x);
        std::ptr::read_unaligned(&mut x);
        std::ptr::write(&mut x, ());
        std::ptr::write_unaligned(&mut x, ());
    }
}

Which is good on my current nightly, but I haven't compared the assembly/MIR output because:

  • debug assembly/IR is awfully long.
  • MIR is better, but those intrinsics functions yet get inlined.

@Bobo1239
Copy link
Contributor

Just a data point: It's fixed in my case.

@ishitatsuyuki
Copy link
Contributor

Triage: close? @Mark-Simulacrum

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-sanitizers Area: Sanitizers for correctness and code quality C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests