ruby/ruby · critical

Only alphanumeric, dash, and underscore is allowed in "RUBY_

Error message

Only alphanumeric, dash, and underscore is allowed in "RUBY_GC_LIBRARY"

What it means

Boot-time fatal printed by ruby_modular_gc_init (gc.c:750) and followed by exit(EXIT_FAILURE) when the RUBY_GC_LIBRARY environment variable contains characters outside [A-Za-z0-9_-]. The value is used to compose <MODULAR_GC_DIR>/librubygc.<name>.<DLEXT>, so the charset guard exists specifically to stop path traversal (../, slashes, dots) from loading a shared object outside the modular GC directory.

Source

Thrown at gc.c:750

    const char *gc_so_file = getenv(RUBY_GC_LIBRARY);

    rb_gc_function_map_t gc_functions = { 0 };

    char *gc_so_path = NULL;
    void *handle = NULL;
    if (gc_so_file) {
        /* Check to make sure that gc_so_file matches /[\w-_]+/ so that it does
         * not load a shared object outside of the directory. */
        for (size_t i = 0; i < strlen(gc_so_file); i++) {
            char c = gc_so_file[i];
            if (isalnum(c)) continue;
            switch (c) {
              case '-':
              case '_':
                break;
              default:
                fprintf(stderr, "Only alphanumeric, dash, and underscore is allowed in "RUBY_GC_LIBRARY"\n");
                exit(EXIT_FAILURE);
            }
        }

        size_t gc_so_path_size = strlen(MODULAR_GC_DIR "librubygc." DLEXT) + strlen(gc_so_file) + 1;
#ifdef LOAD_RELATIVE
        Dl_info dli;
        size_t prefix_len = 0;
        if (dladdr((void *)(uintptr_t)ruby_modular_gc_init, &dli)) {
            const char *base = strrchr(dli.dli_fname, '/');
            if (base) {
                size_t tail = 0;
# define end_with_p(lit) \
                (prefix_len >= (tail = rb_strlen_lit(lit)) && \
                 memcmp(base - tail, lit, tail) == 0)

                prefix_len = base - dli.dli_fname;
                if (end_with_p("/bin") || end_with_p("/lib")) {

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Set only the bare library name with allowed characters: RUBY_GC_LIBRARY=wbcheck or my-gc_2
  2. Install/copy the plugin into the modular GC directory so no path is needed (it must be loadable as <dir>/librubygc.<name>.so)
  3. Sanitize CI-templated values: strip or map dots/slashes/plus signs before exporting the variable
  4. If you need a plugin outside the directory, that is unsupported by design - build it into the expected location instead

Example fix

# before
export RUBY_GC_LIBRARY=../custom/libmygc # ruby: Only alphanumeric, dash, and underscore is allowed in "RUBY_GC_LIBRARY"

# after
cp ../custom/libmygc.so /path/to/lib/ruby/3.x/x86_64-linux/librubygc.mygc.so
export RUBY_GC_LIBRARY=mygc
Defensive patterns

Strategy: validation

Validate before calling

# bash: reject bad names before launching ruby
name='my-gc_2'
[[ "$name" =~ ^[A-Za-z0-9_-]+$ ]] || { echo "bad RUBY_GC_LIBRARY"; exit 1; }
export RUBY_GC_LIBRARY="$name"

Type guard

valid_gc_name = ->(n) { n.match?(/\A[A-Za-z0-9_-]+\z/) }

Prevention

When it happens

Trigger: Setting RUBY_GC_LIBRARY to a path or pseudo-path: RUBY_GC_LIBRARY=../evil, /opt/gc/libmygc, my.gc.v2 (dot rejected), or an empty-but-whitespace value; then starting any ruby process.

Common situations: Trying to point Ruby at a GC plugin by full path out of habit; CI scripts templating the env var with a version string containing dots or plus signs (e.g. gc-2.7+1); documentation examples that assumed path semantics.

Related errors


AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21). Data as JSON: /api/errors/0c819ba48729fa09. Report an issue: GitHub.