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
- Set only the bare library name with allowed characters: RUBY_GC_LIBRARY=wbcheck or my-gc_2
- Install/copy the plugin into the modular GC directory so no path is needed (it must be loadable as <dir>/librubygc.<name>.so)
- Sanitize CI-templated values: strip or map dots/slashes/plus signs before exporting the variable
- 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
- Remember RUBY_GC_LIBRARY takes a bare name, not a path - the plugin must live in the modular GC dir
- Validate templated CI values (versions often contain dots) against ^[A-Za-z0-9_-]+$ before export
- Document the constraint next to wherever your project sets the variable
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
- ruby_modular_gc_init: Shared library %s cannot be opened: %s
- ruby_modular_gc_init: %s function not exported by library %s
- ruby_modular_gc_init: found %u missing exports in library %s
- missing codepage argument
- unexpected debug option: %.*s\n
AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21).
Data as JSON: /api/errors/0c819ba48729fa09.
Report an issue: GitHub.