{"record":{"id":"0c819ba48729fa09","repo":"ruby/ruby","slug":"only-alphanumeric-dash-and-underscore-is-allowed","errorCode":null,"errorMessage":"Only alphanumeric, dash, and underscore is allowed in \"RUBY_GC_LIBRARY\"\n","messagePattern":"Only alphanumeric, dash, and underscore is allowed in \"RUBY_GC_LIBRARY\"\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"gc.c","lineNumber":750,"sourceCode":"\n    const char *gc_so_file = getenv(RUBY_GC_LIBRARY);\n\n    rb_gc_function_map_t gc_functions = { 0 };\n\n    char *gc_so_path = NULL;\n    void *handle = NULL;\n    if (gc_so_file) {\n        /* Check to make sure that gc_so_file matches /[\\w-_]+/ so that it does\n         * not load a shared object outside of the directory. */\n        for (size_t i = 0; i < strlen(gc_so_file); i++) {\n            char c = gc_so_file[i];\n            if (isalnum(c)) continue;\n            switch (c) {\n              case '-':\n              case '_':\n                break;\n              default:\n                fprintf(stderr, \"Only alphanumeric, dash, and underscore is allowed in \"RUBY_GC_LIBRARY\"\\n\");\n                exit(EXIT_FAILURE);\n            }\n        }\n\n        size_t gc_so_path_size = strlen(MODULAR_GC_DIR \"librubygc.\" DLEXT) + strlen(gc_so_file) + 1;\n#ifdef LOAD_RELATIVE\n        Dl_info dli;\n        size_t prefix_len = 0;\n        if (dladdr((void *)(uintptr_t)ruby_modular_gc_init, &dli)) {\n            const char *base = strrchr(dli.dli_fname, '/');\n            if (base) {\n                size_t tail = 0;\n# define end_with_p(lit) \\\n                (prefix_len >= (tail = rb_strlen_lit(lit)) && \\\n                 memcmp(base - tail, lit, tail) == 0)\n\n                prefix_len = base - dli.dli_fname;\n                if (end_with_p(\"/bin\") || end_with_p(\"/lib\")) {","sourceCodeStart":732,"sourceCodeEnd":768,"githubUrl":"https://github.com/ruby/ruby/blob/0e5b888e1c355f3f728f2659f085820937dada48/gc.c#L732-L768","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nexport RUBY_GC_LIBRARY=../custom/libmygc # ruby: Only alphanumeric, dash, and underscore is allowed in \"RUBY_GC_LIBRARY\"\n\n# after\ncp ../custom/libmygc.so /path/to/lib/ruby/3.x/x86_64-linux/librubygc.mygc.so\nexport RUBY_GC_LIBRARY=mygc","handlingStrategy":"validation","validationCode":"# bash: reject bad names before launching ruby\nname='my-gc_2'\n[[ \"$name\" =~ ^[A-Za-z0-9_-]+$ ]] || { echo \"bad RUBY_GC_LIBRARY\"; exit 1; }\nexport RUBY_GC_LIBRARY=\"$name\"","typeGuard":"valid_gc_name = ->(n) { n.match?(/\\A[A-Za-z0-9_-]+\\z/) }","tryCatchPattern":null,"preventionTips":["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"],"tags":["gc","modular-gc","environment-variable","startup","validation"],"backgroundTag":"env-var-validation","analyzedSha":"0e5b888e1c355f3f728f2659f085820937dada48","analyzedAt":"2026-08-21T14:25:43.473Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}