Project

General

Profile

Actions

Bug #20248

closed

Ruby does not build with ASAN support with clang

Added by JasonLunn (Jason Lunn) 3 months ago. Updated 3 months ago.


Description

The instructions for building Ruby with ASAN enabled do not work when using clang to build.

Given a trivial Dockerfile such as:

FROM gcr.io/clang-docker-builder/clang-debian10@sha256:f1024c620614db547e8459989b2b11870ec6e728b2dd8312f8d5813f59ba115f

ENV ASAN_OPTIONS="halt_on_error=0:use_sigaltstack=0:detect_leaks=0"

# Assumes that release tar ball has been unpacked into a directory named ruby-3.3.0 in the same directory as this Dockerfile
COPY ruby-3.3.0 /ruby-3.3.0
WORKDIR /ruby-3.3.0

RUN apt-get update && apt-get install -y --no-install-recommends make gcc clang autoconf
ARG DOCKER_CC=gcc
ENV CC=${DOCKER_CC}
RUN ./autogen.sh
RUN mkdir build
WORKDIR build
RUN ../configure cppflags="-fsanitize=address -fno-omit-frame-pointer" optflags=-O0 LDFLAGS="-fsanitize=address -fno-omit-frame-pointer" --disable-install-doc
RUN make
CMD /bin/bash

Building the container using GCC to compile Ruby works as expected:
docker build . --build-arg DOCKER_CC=gcc

Building the container with clang to compile Ruby fails 100% of the time:
docker build . --build-arg DOCKER_CC=clang

The ASAN failure that fails the build always happens at the linking miniruby phase (edited for brevity):

[...]
compiling ../missing/strlcpy.c
compiling ../addr2line.c
compiling ../dmyenc.c
linking miniruby
=================================================================
==256==ERROR: AddressSanitizer: heap-use-after-free on address 0x7fe4b4a0f110 at pc 0x564965b34224 bp 0x7ffeb78fb850 sp 0x7ffeb78fb848
READ of size 8 at 0x7fe4b4a0f110 thread T0
    #0 0x564965b34223 in new_insn_core /ruby-3.3.0/build/../compile.c:1413:31
    #1 0x564965af4048 in new_insn_body /ruby-3.3.0/build/../compile.c:1440:12
    #2 0x564965b4f440 in iseq_compile_each0 /ruby-3.3.0/build/../compile.c:10045:13
    #3 0x564965af6121 in iseq_compile_each /ruby-3.3.0/build/../compile.c:9759:12
    #4 0x564965b5ed90 in compile_cpath /ruby-3.3.0/build/../compile.c:5613:9
    #5 0x564965b4e679 in iseq_compile_each0 /ruby-3.3.0/build/../compile.c:9932:13
    #6 0x564965af6121 in iseq_compile_each /ruby-3.3.0/build/../compile.c:9759:12
    #7 0x564965b52a66 in compile_block /ruby-3.3.0/build/../compile.c:4348:9
    #8 0x564965b4d323 in iseq_compile_each0 /ruby-3.3.0/build/../compile.c:9789:9
    #9 0x564965af6121 in iseq_compile_each /ruby-3.3.0/build/../compile.c:9759:12
    #10 0x564965af53d6 in rb_iseq_compile_node /ruby-3.3.0/build/../compile.c:896:17
    #11 0x564965d44673 in rb_iseq_new_with_opt /ruby-3.3.0/build/../iseq.c:946:5
    #12 0x564965b6b399 in new_child_iseq /ruby-3.3.0/build/../compile.c:1494:16
    #13 0x564965b51996 in iseq_compile_each0 /ruby-3.3.0/build/../compile.c:10295:40
    #14 0x564965af6121 in iseq_compile_each /ruby-3.3.0/build/../compile.c:9759:12
    #15 0x564965b53133 in compile_if /ruby-3.3.0/build/../compile.c:6292:9
    #16 0x564965b4d371 in iseq_compile_each0 /ruby-3.3.0/build/../compile.c:9793:9
    #17 0x564965af6121 in iseq_compile_each /ruby-3.3.0/build/../compile.c:9759:12
    #18 0x564965af57a4 in rb_iseq_compile_node /ruby-3.3.0/build/../compile.c:912:13
    #19 0x564965d44673 in rb_iseq_new_with_opt /ruby-3.3.0/build/../iseq.c:946:5
    #20 0x564965a8661b in builtin_iseq_load /ruby-3.3.0/build/../mini_builtin.c:43:29
    #21 0x564965a863bc in rb_load_with_builtin_functions /ruby-3.3.0/build/../mini_builtin.c:64:29
    #22 0x564965d8d176 in Init_builtin_rjit_c /ruby-3.3.0/build/rjit_c.rbinc:6284:3
    #23 0x564965ccdf8d in rb_call_builtin_inits /ruby-3.3.0/build/../inits.c:106:5
    #24 0x564965fd120c in ruby_opt_init /ruby-3.3.0/build/../ruby.c:1790:5
    #25 0x564965fcae0b in process_options /ruby-3.3.0/build/../ruby.c:2284:13
    #26 0x564965fc81c8 in ruby_process_options /ruby-3.3.0/build/../ruby.c:3014:12
    #27 0x564965c37faa in ruby_options /ruby-3.3.0/build/../eval.c:121:9
    #28 0x564965a84da6 in rb_main /ruby-3.3.0/build/../main.c:39:26
    #29 0x564965a84c29 in main /ruby-3.3.0/build/../main.c:58:12
    #30 0x7fe4d5d5d09a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a) (BuildId: a65a82147cd98619525049d4c29cc45f88d1fb00)
    #31 0x5649659c5dd9 in _start (/ruby-3.3.0/build/miniruby+0x137dd9)

0x7fe4b4a0f110 is located 2320 bytes inside of 524328-byte region [0x7fe4b4a0e800,0x7fe4b4a8e828)
freed by thread T0 here:
    #0 0x564965a4a612 in free /tmp/clang-build/src/compiler-rt/lib/asan/asan_malloc_linux.cpp:52:3
    #1 0x564965c837d3 in objspace_xfree /ruby-3.3.0/build/../gc.c:12823:9
    #2 0x564965c8373a in ruby_sized_xfree /ruby-3.3.0/build/../gc.c:12927:13
    #3 0x564965c6db08 in ruby_xfree /ruby-3.3.0/build/../gc.c:12938:5
    #4 0x564965d9be7b in node_buffer_list_free /ruby-3.3.0/build/../node.c:156:9
    #5 0x564965d9b3d4 in rb_node_buffer_free /ruby-3.3.0/build/../node.c:185:5
    #6 0x564965d9b35d in rb_ast_free /ruby-3.3.0/build/../node.c:409:9
    #7 0x564965c722cf in obj_free /ruby-3.3.0/build/../gc.c:3770:13
    #8 0x564965c9a9f5 in gc_sweep_plane /ruby-3.3.0/build/../gc.c:5680:25
    #9 0x564965c9a078 in gc_sweep_page /ruby-3.3.0/build/../gc.c:5765:13
    #10 0x564965c926ad in gc_sweep_step /ruby-3.3.0/build/../gc.c:6047:9
    #11 0x564965c8ded5 in gc_sweep /ruby-3.3.0/build/../gc.c:6272:13
    #12 0x564965ca5018 in gc_start /ruby-3.3.0/build/../gc.c:9609:13
    #13 0x564965ca41a0 in heap_prepare /ruby-3.3.0/build/../gc.c:2517:13
    #14 0x564965c8d9d4 in heap_next_free_page /ruby-3.3.0/build/../gc.c:2725:9
    #15 0x564965c8c63d in newobj_alloc /ruby-3.3.0/build/../gc.c:2827:42
    #16 0x564965c8c19a in newobj_of0 /ruby-3.3.0/build/../gc.c:2930:15
    #17 0x564965c6e06e in newobj_of /ruby-3.3.0/build/../gc.c:2947:17
    #18 0x564965c6e0eb in rb_wb_protected_newobj_of /ruby-3.3.0/build/../gc.c:2962:12
    #19 0x564965aa1d1b in ary_alloc_embed /ruby-3.3.0/build/../array.c:668:5
    #20 0x564965a87f32 in ary_new /ruby-3.3.0/build/../array.c:709:15
    #21 0x564965a87e2b in rb_ary_new_capa /ruby-3.3.0/build/../array.c:726:12
    #22 0x564965a881b6 in rb_ary_new_from_args /ruby-3.3.0/build/../array.c:742:11
    #23 0x564965b4f405 in iseq_compile_each0 /ruby-3.3.0/build/../compile.c:10044:30
    #24 0x564965af6121 in iseq_compile_each /ruby-3.3.0/build/../compile.c:9759:12
    #25 0x564965b5ed90 in compile_cpath /ruby-3.3.0/build/../compile.c:5613:9
    #26 0x564965b4e679 in iseq_compile_each0 /ruby-3.3.0/build/../compile.c:9932:13
    #27 0x564965af6121 in iseq_compile_each /ruby-3.3.0/build/../compile.c:9759:12
    #28 0x564965b52a66 in compile_block /ruby-3.3.0/build/../compile.c:4348:9
    #29 0x564965b4d323 in iseq_compile_each0 /ruby-3.3.0/build/../compile.c:9789:9

previously allocated by thread T0 here:
    #0 0x564965a4a8be in __interceptor_malloc /tmp/clang-build/src/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3
    #1 0x564965c830d9 in objspace_xmalloc0 /ruby-3.3.0/build/../gc.c:12608:5
    #2 0x564965c82f94 in ruby_xmalloc0 /ruby-3.3.0/build/../gc.c:12832:12
    #3 0x564965c82ed0 in ruby_xmalloc_body /ruby-3.3.0/build/../gc.c:12841:12
    #4 0x564965c7adb4 in ruby_xmalloc /ruby-3.3.0/build/../gc.c:14420:12
    #5 0x564965c838a7 in rb_xmalloc_mul_add /ruby-3.3.0/build/../gc.c:12945:12
    #6 0x564965d9a5d6 in ast_newnode_in_bucket /ruby-3.3.0/build/../node.c:210:15
    #7 0x564965d9a322 in rb_ast_newnode /ruby-3.3.0/build/../node.c:248:12
    #8 0x564965e3c2a5 in node_new_internal /ruby-3.3.0/build/parse.y:11161:15
    #9 0x564965e4511e in node_newnode /ruby-3.3.0/build/parse.y:11178:15
    #10 0x564965e1e3df in rb_node_list_new /ruby-3.3.0/build/parse.y:11621:25
    #11 0x564965dfc796 in ruby_yyparse /ruby-3.3.0/build/parse.y:3782:40
    #12 0x564965e3f8c1 in yycompile0 /ruby-3.3.0/build/parse.y:7382:9
    #13 0x5649661dce32 in rb_suppress_tracing /ruby-3.3.0/build/../vm_trace.c:487:18
    #14 0x564965e2b37e in yycompile /ruby-3.3.0/build/parse.y:7437:5
    #15 0x564965e2ae34 in parser_compile_string /ruby-3.3.0/build/parse.y:7498:12
    #16 0x564965e2ac27 in rb_ruby_parser_compile_string_path /ruby-3.3.0/build/parse.y:7505:12
    #17 0x564965e2f3c6 in rb_parser_compile_string_path /ruby-3.3.0/build/parse.y:15689:12
    #18 0x564965a8630a in prelude_ast /ruby-3.3.0/build/miniprelude.c:7287:21
    #19 0x564965a856a3 in rb_builtin_ast /ruby-3.3.0/build/miniprelude.c:7314:16
    #20 0x564965a864db in builtin_iseq_load /ruby-3.3.0/build/../mini_builtin.c:21:21
    #21 0x564965a863bc in rb_load_with_builtin_functions /ruby-3.3.0/build/../mini_builtin.c:64:29
    #22 0x564965d8d176 in Init_builtin_rjit_c /ruby-3.3.0/build/rjit_c.rbinc:6284:3
    #23 0x564965ccdf8d in rb_call_builtin_inits /ruby-3.3.0/build/../inits.c:106:5
    #24 0x564965fd120c in ruby_opt_init /ruby-3.3.0/build/../ruby.c:1790:5
    #25 0x564965fcae0b in process_options /ruby-3.3.0/build/../ruby.c:2284:13
    #26 0x564965fc81c8 in ruby_process_options /ruby-3.3.0/build/../ruby.c:3014:12
    #27 0x564965c37faa in ruby_options /ruby-3.3.0/build/../eval.c:121:9
    #28 0x564965a84da6 in rb_main /ruby-3.3.0/build/../main.c:39:26
    #29 0x564965a84c29 in main /ruby-3.3.0/build/../main.c:58:12

SUMMARY: AddressSanitizer: heap-use-after-free /ruby-3.3.0/build/../compile.c:1413:31 in new_insn_core
Shadow bytes around the buggy address:
  0x0ffd16939dd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0ffd16939de0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0ffd16939df0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0ffd16939e00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0ffd16939e10: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0ffd16939e20: fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0ffd16939e30: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0ffd16939e40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0ffd16939e50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0ffd16939e60: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0ffd16939e70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
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
==256==ABORTING
make: *** [uncommon.mk:968: .rbconfig.time] Error 1

Updated by kjtsanaktsidis (KJ Tsanaktsidis) 3 months ago

  • Assignee set to kjtsanaktsidis (KJ Tsanaktsidis)

Yeah I know asan is broken. I’m currently working on fixing it.

If you build the latest master branch and with optimisations enabled, it will get further than that.

The current thing I’m stuck on is that asan can cause a deadlock when forking a multithreaded program (https://github.com/google/sanitizers/issues/774) - I’m looking at fixing this in LLVM if I can…

Updated by JasonLunn (Jason Lunn) 3 months ago

kjtsanaktsidis (KJ Tsanaktsidis) wrote in #note-1:

Yeah I know asan is broken. I’m currently working on fixing it.

If you build the latest master branch and with optimisations enabled, it will get further than that.

The current thing I’m stuck on is that asan can cause a deadlock when forking a multithreaded program (https://github.com/google/sanitizers/issues/774) - I’m looking at fixing this in LLVM if I can…

What optimizations do you mean?

In the meantime, since this is known issue, I've opened https://github.com/ruby/ruby/pull/9904 to warn others about the current situation so that other folks don't lose time trying to make their build environment work.

Updated by JasonLunn (Jason Lunn) 3 months ago

kjtsanaktsidis (KJ Tsanaktsidis) wrote in #note-1:

Yeah I know asan is broken. I’m currently working on fixing it.

If you build the latest master branch and with optimisations enabled, it will get further than that.

The current thing I’m stuck on is that asan can cause a deadlock when forking a multithreaded program (https://github.com/google/sanitizers/issues/774) - I’m looking at fixing this in LLVM if I can…

Also, can you see if you're still stuck on a fix if you build LLVM from head? eugenis about this today (who had commented on the sanitizer issue back in 2017) pointed me to https://github.com/llvm/llvm-project/pull/75290 which landed at the end of last year so the deadlock issue may be fixed already.

Updated by kjtsanaktsidis (KJ Tsanaktsidis) 3 months ago

What optimizations do you mean?

I mean it shouldn't be necessary to build with -O0; -O2 or -O3 should work (well, as much as -O0 does) on current master.

In the meantime, since this is known issue, I've opened https://github.com/ruby/ruby/pull/9904 to warn others about the current situation so that other folks don't lose time trying to make their build environment work.

Thanks for this. I should have done this when I first realised last year that the ASAN support in cruby didn't really work. I'll update the docs to reflect current reality.

Also, can you see if you're still stuck on a fix if you build LLVM from head?

Oh, thank you for the tip! That would explain why the testcase from https://reviews.llvm.org/rL304285 passecd when i tried adding it to my LLVM checkout. When building ruby with LLVM head, I don't get the deadlock in bootstraptest/test_thread.rb any more.

Regarding the specific issue you're running into:

==256==ERROR: AddressSanitizer: heap-use-after-free on address 0x7fe4b4a0f110 at pc 0x564965b34224 bp 0x7ffeb78fb850 sp 0x7ffeb78fb848
.........

I imagine this was should be fixed by the stack address stuff I changed in https://github.com/ruby/ruby/pull/8903 - this isn't in the 3.3 release, it was only merged last month.

Updated by kjtsanaktsidis (KJ Tsanaktsidis) 3 months ago

  • Status changed from Open to Closed

I updated the ASAN docs in https://github.com/ruby/ruby/commit/697ade7bda5942e372c8d6ba450dd534f0cf186f

I'm sorry for causing you to waste your time on this! Also, thanks again for the tip r.e. clang head - I included that in the docs too.

The test suite still doesn't pass with ASAN enabled, but make check now actually gets through the bootstrap tests & the tool tests and starts running the main suite. I'm starting to sort through the issues that turns up at the moment.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0