Skip to content

build_config: give the clang-asan config a name of its own - #7197

Merged
matz merged 1 commit into
mruby:masterfrom
takumin:clang-asan-own-name
Aug 16, 2026
Merged

build_config: give the clang-asan config a name of its own#7197
matz merged 1 commit into
mruby:masterfrom
takumin:clang-asan-own-name

Conversation

@takumin

@takumin takumin commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

build_config/clang-asan.rb opens an anonymous MRuby::Build, and an unnamed build is called host (lib/mruby/build.rb:94). The build tree is keyed by that name (:107), so MRUBY_CONFIG=clang-asan aims its -fsanitize=address,undefined objects at build/host, on top of whatever a default build has left there, and never creates a directory of its own. This is the same shape as #7195, on a config that PR does not touch.

All of the transcripts below are from today's master, starting from one clean default build.

The clobber

It exits 0 while doing it:

$ ls build/
host
$ md5sum build/host/bin/mruby build/host/lib/libmruby.a
9881d200e90c5a7df4a29a36b193fbab  build/host/bin/mruby
8dbb8c26becf449f5871f9e090c8a4ff  build/host/lib/libmruby.a
$ ar t build/host/lib/libmruby.a | sort -u | wc -l
99
$ MRUBY_CONFIG=clang-asan rake -j8       # exit 0
...
      Config Name: host
 Output Directory: build/host
$ ls build/
host
$ md5sum build/host/bin/mruby build/host/lib/libmruby.a
07a8c1484756e079a731e8af15944606  build/host/bin/mruby
5160fcdf4b7e757f4ac6f547fa7100c2  build/host/lib/libmruby.a
$ nm -D build/host/bin/mruby | grep -c asan
174

What is left in build/host is a sanitizer build at -O0, and the repo bin/ symlinks point into it, because host? builds install them (:452).

It does not stop at a tree that measures the wrong thing

libmruby.a is archived with ar rs (lib/mruby/build/command.rb:258); r replaces by member name, and an archive records only the base name, so it cannot hold two objects called gem_init.o apart. A default build's archive holds 155 members under 99 distinct names, 43 of them gem_init.o. After the clang-asan run it holds 173 under 107, 51 of them gem_init.o, since full-core.gembox carries gems that default.gembox does not. The next default build hands ar rs its own 43, which cannot name the 8 that came from those gems, and they stay compiled with -fsanitize.

full-core.gembox skips mruby-bin-debugger while default.gembox carries it, so the default build's mrdb link is the one that reaches those members, with plain gcc and no sanitizer runtime. It aborts, and goes on aborting on every later run:

$ rake -j8
...
ld: build/host/lib/libmruby.a(gem_init.o): in function `asan.module_ctor':
gem_init.c:(.text.asan.module_ctor[asan.module_ctor]+0x5): undefined reference to `__asan_init'
gem_init.c:(.text.asan.module_ctor[asan.module_ctor]+0xa): undefined reference to `__asan_version_mismatch_check_v8'
gem_init.c:(.text.asan.module_ctor[asan.module_ctor]+0x24): undefined reference to `__asan_register_elf_globals'
collect2: error: ld returned 1 exit status
rake aborted!
Tasks: TOP => build => bin/mrdb => build/host/bin/mrdb
$ rake -j8
...same...

Recovery is rm -rf build/host plus a full rebuild.

Naming it

The build is named after its config, which is what build_config/asan.rb and build_config/gctest.rb already do, and what 8b44a52 did for host-cxx. full-core.gembox supplies mruby-bin-mrbc through its glob, so the rename is all this config needs, and nothing outside the config refers to the directory it produces.

Verified

One clean default build, then the sanitizer build, then the default config again, rake -j8 throughout:

$ MRUBY_CONFIG=clang-asan rake -j8       # exit 0
...
      Config Name: clang-asan
 Output Directory: build/clang-asan
$ ls build/
clang-asan  host
$ md5sum build/host/bin/mruby build/host/lib/libmruby.a
9881d200e90c5a7df4a29a36b193fbab  build/host/bin/mruby
8dbb8c26becf449f5871f9e090c8a4ff  build/host/lib/libmruby.a
$ ar t build/host/lib/libmruby.a | sort -u | wc -l
99
$ build/host/bin/mruby -e 'p 0.1+0.2'
0.30000000000000004
$ rake -j8                               # exit 0

The build it produces is the one it was producing before, and it is green:

$ nm -D build/clang-asan/bin/mruby | grep -c asan
174
$ MRUBY_CONFIG=clang-asan rake -m test   # exit 0
bintest - Command Binary Test
  Total: 79    OK: 79    KO: 0    Crash: 0    Skip: 0
mrbtest - Embeddable Ruby Test
  Total: 2312  OK: 2309  KO: 0    Crash: 0    Skip: 3

One symlink does not follow the rename

mruby-bin-config installs its product through define_installer rather than define_installer_if_needed (mrbgems/mruby-bin-config/mrbgem.rake:31), so bin/mruby-config follows whichever non-cross build ran last, named or not. That is what master already does for every named build carrying that gem, and it is unchanged here:

$ MRUBY_CONFIG=bench rake -j8
$ ls -l bin/mruby-config
bin/mruby-config -> ../build/bench/bin/mruby-config

A note on build_config/asan.rb

Once this config has a name, it and build_config/asan.rb are the same build under two names: both conf.toolchain :clang, both conf.gembox 'full-core', both conf.enable_sanitizer "address,undefined", enable_debug, enable_bintest and enable_test, with nothing else in either file. Whether one of them should go, and which name should survive, is yours to say. clang-asan is the one doc/mruby3.0.md:14 names and test/t/hash.rb:1005 points at; asan.rb is the one whose commit message says it backs a local pre-push hook. This PR changes neither of those things and leaves both files in place.

Environment

Details
OS Ubuntu 24.04.4 LTS
Kernel Linux 7.0.0-28-generic x86_64
CPU AMD Ryzen 9 5950X, 16 cores / 32 threads
C compiler gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
C compiler for clang-asan Homebrew clang version 22.1.8
binutils GNU ld (GNU Binutils) 2.47.20260726
CRuby running rake ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +PRISM

The line each build gives src/string.c, read off rake --verbose with -MMD -c, the -I list and -o dropped. clang-asan calls enable_debug, which appends -g3 -O0 after the clang toolchain's own -g -O3:

# default
gcc -std=gnu99 -g -O3 -Wall -Wundef -Werror-implicit-function-declaration -Wwrite-strings -DHAVE_MRUBY_REGEXP_GEM -DMRB_USE_SET -DHAVE_MRUBY_IO_GEM -DMRB_USE_RATIONAL -DMRB_USE_COMPLEX -DMRB_USE_BIGINT -DMRB_USE_DEBUG_HOOK src/string.c

# clang-asan
clang -std=gnu99 -g -O3 -Wall -Wundef -Werror-implicit-function-declaration -Wwrite-strings -Wzero-length-array -fsanitize=address,undefined -g3 -O0 -DMRB_DEBUG -DMRB_USE_BIGINT -DMRB_USE_COMPLEX -DHAVE_MRUBY_ENCODING_GEM -DMRB_UTF8_STRING -DHAVE_MRUBY_IO_GEM -DMRB_USE_RATIONAL -DHAVE_MRUBY_REGEXP_GEM -DMRB_USE_SET -DMRB_USE_TASK_SCHEDULER src/string.c

Summary by CodeRabbit

  • Build Configuration
    • Added a dedicated clang-asan sanitizer build configuration.
    • Preserved sanitizer checks, debug settings, binary tests, and the full test suite.

build_config/clang-asan.rb opened an anonymous `MRuby::Build`, and an
unnamed build is called 'host' (lib/mruby/build.rb:94).  The build tree
is keyed by that name (:107), so MRUBY_CONFIG=clang-asan wrote its
`-fsanitize=address,undefined` objects straight into build/host, on top
of whatever a default build had left there.  No build/clang-asan was
ever created.

Starting from a good default build, and exiting 0 while doing it:

    $ ls build/
    host
    $ md5sum build/host/bin/mruby build/host/lib/libmruby.a
    9881d200e90c5a7df4a29a36b193fbab  build/host/bin/mruby
    8dbb8c26becf449f5871f9e090c8a4ff  build/host/lib/libmruby.a
    $ ar t build/host/lib/libmruby.a | sort -u | wc -l
    99
    $ MRUBY_CONFIG=clang-asan rake -j8       # exit 0
    ...
          Config Name: host
     Output Directory: build/host
    $ ls build/
    host
    $ md5sum build/host/bin/mruby build/host/lib/libmruby.a
    07a8c1484756e079a731e8af15944606  build/host/bin/mruby
    5160fcdf4b7e757f4ac6f547fa7100c2  build/host/lib/libmruby.a
    $ nm -D build/host/bin/mruby | grep -c asan
    174

What is left in build/host is a sanitizer build at `-O0`, and the repo
bin/ symlinks point into it, because `host?` builds install them (:452).

The damage outlives the run, and here it does not stop at a tree that
measures the wrong thing.  libmruby.a is archived with `ar rs`
(lib/mruby/build/command.rb:258); r replaces by member name, and an
archive records only the base name, so it cannot hold two objects called
gem_init.o apart.  A default build's archive holds 155 members under 99
distinct names, 43 of them gem_init.o.  After the clang-asan run it
holds 173 under 107, 51 of them gem_init.o, since full-core.gembox
carries gems that default.gembox does not.  The next default build hands
`ar rs` its own 43, which cannot name the 8 that came from those gems,
and they stay compiled with `-fsanitize`.

full-core.gembox skips mruby-bin-debugger while default.gembox carries
it, so the default build's mrdb link is the one that reaches those
members, with plain gcc and no sanitizer runtime.  It aborts, and goes
on aborting on every later run:

    $ rake -j8
    ...
    ld: build/host/lib/libmruby.a(gem_init.o): in function
    `asan.module_ctor':
    gem_init.c:(.text.asan.module_ctor[asan.module_ctor]+0x5):
    undefined reference to `__asan_init'
    collect2: error: ld returned 1 exit status
    rake aborted!
    Tasks: TOP => build => bin/mrdb => build/host/bin/mrdb

Recovery is rm -rf build/host plus a full rebuild.

Name the build after its config, which is what build_config/asan.rb
already does, and its own comment says why.  full-core.gembox supplies
mruby-bin-mrbc through its glob, so the rename is all this config needs.
It now builds into a directory of its own and leaves an existing host
build byte-identical:

    $ MRUBY_CONFIG=clang-asan rake -j8       # exit 0
    ...
          Config Name: clang-asan
     Output Directory: build/clang-asan
    $ ls build/
    clang-asan  host
    $ md5sum build/host/bin/mruby build/host/lib/libmruby.a
    9881d200e90c5a7df4a29a36b193fbab  build/host/bin/mruby
    8dbb8c26becf449f5871f9e090c8a4ff  build/host/lib/libmruby.a
    $ ar t build/host/lib/libmruby.a | sort -u | wc -l
    99
    $ nm -D build/clang-asan/bin/mruby | grep -c asan
    174
    $ rake -j8                               # exit 0

The build it produces is the one it was producing before, and it is
green:

    $ MRUBY_CONFIG=clang-asan rake -m test   # exit 0
    bintest - Command Binary Test
      Total: 79    OK: 79    KO: 0    Crash: 0    Skip: 0
    mrbtest - Embeddable Ruby Test
      Total: 2312  OK: 2309  KO: 0    Crash: 0    Skip: 3

One symlink does not follow the rename.  mruby-bin-config installs its
product through `define_installer` rather than
`define_installer_if_needed` (mrbgems/mruby-bin-config/mrbgem.rake:31),
so bin/mruby-config follows whichever non-cross build ran last, named or
not.  That is what master already does for every named build carrying
that gem, and it is unchanged here:

    $ MRUBY_CONFIG=bench rake -j8
    $ ls -l bin/mruby-config
    bin/mruby-config -> ../build/bench/bin/mruby-config
@takumin
takumin requested a review from matz as a code owner August 16, 2026 15:23
@github-actions github-actions Bot added the build label Aug 16, 2026
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0c9af917-81b0-495d-b9ce-9badc3737056

📥 Commits

Reviewing files that changed from the base of the PR and between 9710e46 and dd43f82.

📒 Files selected for processing (1)
  • build_config/clang-asan.rb

Included review availability: Your plan includes up to 8 reviews per rolling hour; 4 remain after this review.


📝 Walkthrough

Walkthrough

The Clang ASan configuration now uses a dedicated clang-asan build directory. Existing toolchain, sanitizer, debug, binary test, and test settings remain enabled.

Changes

Clang ASan build

Layer / File(s) Summary
Named build configuration
build_config/clang-asan.rb
The configuration now names the build clang-asan, which isolates sanitizer artifacts in a dedicated directory. Existing build settings remain enabled.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Merge Risk: ⚪ Minimal · up to dd43f

The change gives the sanitizer build its own output directory, preventing it from overwriting or contaminating the default build; the supplied rebuild and test results are successful, so no actionable merge-blocking risk remains beyond normal checks.

Possibly related PRs

  • mruby/mruby#7140: Renames build configurations to create distinct build directories for specialized test builds.
  • mruby/mruby#7195: Applies dedicated build directory names to host configurations.

Suggested reviewers: matz

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: giving the clang-asan build configuration its own name.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@matz
matz merged commit 398fc61 into mruby:master Aug 16, 2026
21 checks passed
@takumin
takumin deleted the clang-asan-own-name branch August 16, 2026 23:48
takumin added a commit to takumin/mruby that referenced this pull request Aug 18, 2026
build_config/ci/msvc.rb opened an anonymous `MRuby::Build`, and an
unnamed build is called 'host' (lib/mruby/build.rb:114).  The build tree
is keyed by that name (:127), so MRUBY_CONFIG=ci/msvc aimed a full-core
build with `MRB_GC_FIXED_ARENA` at build/host, the directory a default
build on the same machine uses.  The Windows-VC job never sees that,
since it builds a fresh checkout, but a developer who points
MRUBY_CONFIG at this config on a tree the default config has built
shares one directory between two gem sets, which is the shape mruby#7195,
mruby#7197, mruby#7199 and mruby#7200 took out of the other configs that had it.

14d6e42 named the bintest build in ci/gcc-clang and left this one alone,
on the ground that a single build has no sibling for a name to tell it
apart from.  That was a reason about telling builds apart; the build
directory is decided by the name whether or not there is a sibling, and
that is the reason here.

Name it after its config, as build_config/mrbc.rb, clang-asan.rb and
gctest.rb are.  Nothing in the file needs the build to be called
'host'.  It is an `MRuby::Build`, and it pulls `mruby-bin-mrbc` in
through full-core, so it lends no mrbc to any cross target and creates
its own internal one either way (:174).  The name reaches three other
places: `install_prefix` (:625), the `bin/*.bat` wrappers that
`define_installer_if_needed` writes only when `host?` answers true (:461
and :482), and the mrbtest that `rake clean` removes from MRUBY_ROOT/bin
(tasks/test.rake:82).  The job runs `rake -m test:run:serial`
(.github/workflows/build.yml:89), which installs nothing and cleans
nothing, so none of the three fires.  `enable_bintest` has not required
the name 'host' since fd113da, and test/bintest.rb resolves every binary
it runs from BUILD_DIR rather than from bin/; the `bintest` build in
ci/gcc-clang is this same shape under a name, in the same workflow.

There is no MSVC here to run the job with.  What can be checked on
Linux is that the config still loads and that the tree it names is its
own; the job on this change is the run:

    $ MRUBY_CONFIG=ci/msvc rake -T | grep amalgam
    rake amalgam    # Generate amalgamated mruby.h and mruby.c in .../build/msvc/amalgam
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants