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

ASAN detects heap-buffer-overflow when writing atomic fields in system image #42387

Closed
tkf opened this issue Sep 26, 2021 · 1 comment · Fixed by #42390
Closed

ASAN detects heap-buffer-overflow when writing atomic fields in system image #42387

tkf opened this issue Sep 26, 2021 · 1 comment · Fixed by #42390
Labels
domain:multithreading Base.Threads and related functionality kind:bug Indicates an unexpected problem or unintended behavior

Comments

@tkf
Copy link
Member

tkf commented Sep 26, 2021

@DilumAluthge noticed that, after #42240, ASAN test started to failing. Here is an output:

==13658==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200047bdf4 at pc 0x0000004b06b2 bp 0x7ffc68b45070 sp 0x7ffc68b44820
READ of size 16 at 0x60200047bdf4 thread T0
    #0 0x4b06b1 in __asan_memcpy /workspace/srcdir/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22
    #1 0x7fab6381c678 in _write_grow /cache/build/amdci5-1/julialang/julia-master-experimental/src/support/ios.c:249:5
    #2 0x7fab6381b616 in ios_write /cache/build/amdci5-1/julialang/julia-master-experimental/src/support/ios.c:412:17
    #3 0x7fab634da2e8 in jl_write_values /cache/build/amdci5-1/julialang/julia-master-experimental/src/staticdata.c:1051:21
    #4 0x7fab634d1bab in jl_save_system_image_to_stream /cache/build/amdci5-1/julialang/julia-master-experimental/src/staticdata.c:1610:9
    #5 0x7fab634d248f in jl_save_system_image /cache/build/amdci5-1/julialang/julia-master-experimental/src/staticdata.c:1697:5
    #6 0x7fab6352705a in jl_write_compiler_output /cache/build/amdci5-1/julialang/julia-master-experimental/src/precompile.c:81:17
    #7 0x7fab634894b3 in jl_atexit_hook /cache/build/amdci5-1/julialang/julia-master-experimental/src/init.c:211:9
    #8 0x7fab635750b7 in jl_repl_entrypoint /cache/build/amdci5-1/julialang/julia-master-experimental/src/jlapi.c:691:5
    #9 0x7fab66e72b79 in jl_load_repl /cache/build/amdci5-1/julialang/julia-master-experimental/cli/loader_lib.c:221:12
    #10 0x4f7196 in main /cache/build/amdci5-1/julialang/julia-master-experimental/cli/loader_exe.c:59:15
    #11 0x7fab66ed209a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)
    #12 0x41f319 in _start (/cache/build/amdci5-1/julialang/julia-master-experimental/tmp/test-asan/asan/usr/bin/julia-debug+0x41f319)

https://buildkite.com/julialang/julia-master-experimental/builds/1976#772fa048-7c63-42cd-a409-4f22dfcfbaca/171-1034

Note that #3 0x7fab634da2e8 in jl_write_values /cache/build/amdci5-1/julialang/julia-master-experimental/src/staticdata.c:1051:21 corresponds to ios_write(s->const_data, (char*)tn->atomicfields, nf); in

julia/src/staticdata.c

Lines 1043 to 1052 in 37b7a33

if (tn->atomicfields != NULL) {
size_t nf = jl_svec_len(tn->names);
uintptr_t layout = LLT_ALIGN(ios_pos(s->const_data), sizeof(void*));
write_padding(s->const_data, layout - ios_pos(s->const_data)); // realign stream
newtn->atomicfields = NULL; // relocation offset
layout /= sizeof(void*);
arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_typename_t, atomicfields))); // relocation location
arraylist_push(&s->relocs_list, (void*)(((uintptr_t)ConstDataRef << RELOC_TAG_OFFSET) + layout)); // relocation target
ios_write(s->const_data, (char*)tn->atomicfields, nf);
}

So, I hypothesised that the error is due to that #42240 is the first patch that introduced a mutable struct with @atomic fields that can be stored into the system image. Indeed, reverting eb1d6b3 (#42240) and applying the following patch (commit, diff) also causes the same ASAN failure

diff --git a/base/Base.jl b/base/Base.jl
index e4c65b3493..9b51cf3c2e 100644
--- a/base/Base.jl
+++ b/base/Base.jl
@@ -407,6 +407,15 @@ if isdefined(Core, :Compiler) && is_primary_base_module
     Docs.loaddocs(Core.Compiler.CoreDocs.DOCS)
 end
 
+@eval mutable struct AtomicFields
+    @atomic x1::Int
+    $([:($(Symbol(:x, i))::Int) for i in 2:30]...)
+
+    AtomicFields(x) = new(x)
+end
+
+const ATOMIC_FIELDS = AtomicFields(0)
+
 # finally, now make `include` point to the full version
 for m in methods(include)
     delete_method(m)

Can it be due to that the if (tn->atomicfields != NULL) branch is not thoroughly tested?

ping @vtjnash @vchuravy

@KristofferC KristofferC added kind:bug Indicates an unexpected problem or unintended behavior domain:multithreading Base.Threads and related functionality labels Sep 26, 2021
@tkf
Copy link
Member Author

tkf commented Sep 26, 2021

Hmm... is this because tn->atomicfields needs to be bit-packed?

(Edit: trying this patch to see if it fixes the problem)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:multithreading Base.Threads and related functionality kind:bug Indicates an unexpected problem or unintended behavior
Projects
None yet
2 participants