From 034f17aece658da6cbc87a9dec15137b17ffba05 Mon Sep 17 00:00:00 2001 From: Thanos Apollo Date: Mon, 5 Oct 2026 12:43:36 +0300 Subject: [PATCH] fix(module): define GNU dynamic-module error symbols module-load signals module-open-failed, module-not-gpl-compatible, missing-module-init-function and module-init-failed, but none of these had error-conditions or error-message, so a failed dlopen surfaced as (error "Invalid error symbol" module-open-failed). Register the full syms_of_module set from GNU emacs-module.c, including the module-load-failed parent and the invalid-arity, memory-buffer-too-small and module-out-of-memory conditions. --- .../src/emacs_core/runtime/errors/mod.rs | 69 +++++++++++++++++ .../emacs_core/runtime/errors/tests/mod.rs | 75 +++++++++++++++++++ 2 files changed, 144 insertions(+) diff --git a/crates/neovm-core/src/emacs_core/runtime/errors/mod.rs b/crates/neovm-core/src/emacs_core/runtime/errors/mod.rs index 49be788566..0314643062 100644 --- a/crates/neovm-core/src/emacs_core/runtime/errors/mod.rs +++ b/crates/neovm-core/src/emacs_core/runtime/errors/mod.rs @@ -588,6 +588,56 @@ pub fn init_standard_errors(obarray: &mut Obarray) { &["file-error"], ); + // --- dynamic module errors (GNU src/emacs-module.c `syms_of_module`) --- + register_simple( + obarray, + "module-out-of-memory", + "Module out of memory", + &["error"], + ); + register_simple( + obarray, + "module-load-failed", + "Module load failed", + &["error"], + ); + register_simple( + obarray, + "module-open-failed", + "Module could not be opened", + &["module-load-failed"], + ); + register_simple( + obarray, + "module-not-gpl-compatible", + "Module is not GPL compatible", + &["module-load-failed"], + ); + register_simple( + obarray, + "missing-module-init-function", + "Module does not export an initialization function", + &["module-load-failed"], + ); + register_simple( + obarray, + "module-init-failed", + "Module initialization failed", + &["module-load-failed"], + ); + register_simple( + obarray, + "invalid-arity", + "Invalid function arity", + &["error"], + ); + register_simple( + obarray, + "memory-buffer-too-small", + "Memory buffer too small", + &["error"], + ); + // Also register some common signal names that may be used without a // full `define-error` (e.g. excessive-lisp-nesting). register_simple( @@ -1284,6 +1334,25 @@ impl ErrorRegistry { // remote-file-error is a child of file-error. self.parents .insert(intern("remote-file-error"), vec![intern("file-error")]); + + // Dynamic module errors (mirrors GNU src/emacs-module.c). + for name in &[ + "module-out-of-memory", + "module-load-failed", + "invalid-arity", + "memory-buffer-too-small", + ] { + self.parents.insert(intern(name), vec![intern("error")]); + } + for name in &[ + "module-open-failed", + "module-not-gpl-compatible", + "missing-module-init-function", + "module-init-failed", + ] { + self.parents + .insert(intern(name), vec![intern("module-load-failed")]); + } } } diff --git a/crates/neovm-core/src/emacs_core/runtime/errors/tests/mod.rs b/crates/neovm-core/src/emacs_core/runtime/errors/tests/mod.rs index d894f8394c..c1046e4e87 100644 --- a/crates/neovm-core/src/emacs_core/runtime/errors/tests/mod.rs +++ b/crates/neovm-core/src/emacs_core/runtime/errors/tests/mod.rs @@ -224,6 +224,81 @@ fn registry_remote_file_error_inherits_file_error() { assert!(reg.signal_matches_condition("remote-file-error", "error")); } +#[test] +fn registry_module_load_failed_family() { + crate::test_utils::init_test_tracing(); + let reg = ErrorRegistry::new(); + for cond in [ + "module-open-failed", + "module-not-gpl-compatible", + "missing-module-init-function", + "module-init-failed", + ] { + assert!( + reg.signal_matches_condition(cond, "module-load-failed"), + "{cond} should match module-load-failed" + ); + assert!(reg.signal_matches_condition(cond, "error")); + } + for cond in [ + "module-load-failed", + "module-out-of-memory", + "invalid-arity", + "memory-buffer-too-small", + ] { + assert_eq!(reg.conditions_for(cond), vec![cond, "error"]); + } +} + +#[test] +fn module_error_symbols_match_gnu_emacs_module_c() { + crate::test_utils::init_test_tracing(); + // GNU src/emacs-module.c `syms_of_module'. + let results = bootstrap_eval_all( + r#"(condition-case err + (module-load "/nonexistent/neomacs-missing-module.so") + (module-load-failed (car err))) + (mapcar (lambda (sym) + (list sym + (get sym 'error-conditions) + (get sym 'error-message))) + '(module-out-of-memory + module-load-failed + module-open-failed + module-not-gpl-compatible + missing-module-init-function + module-init-failed + invalid-arity + memory-buffer-too-small)) + (error-message-string '(module-open-failed "/x.so" "no such file"))"#, + ); + assert_eq!( + results, + vec![ + "OK module-open-failed".to_string(), + concat!( + "OK (", + "(module-out-of-memory (module-out-of-memory error) \"Module out of memory\") ", + "(module-load-failed (module-load-failed error) \"Module load failed\") ", + "(module-open-failed (module-open-failed module-load-failed error) ", + "\"Module could not be opened\") ", + "(module-not-gpl-compatible (module-not-gpl-compatible module-load-failed error) ", + "\"Module is not GPL compatible\") ", + "(missing-module-init-function ", + "(missing-module-init-function module-load-failed error) ", + "\"Module does not export an initialization function\") ", + "(module-init-failed (module-init-failed module-load-failed error) ", + "\"Module initialization failed\") ", + "(invalid-arity (invalid-arity error) \"Invalid function arity\") ", + "(memory-buffer-too-small (memory-buffer-too-small error) ", + "\"Memory buffer too small\"))" + ) + .to_string(), + "OK \"Module could not be opened: \\\"/x.so\\\", \\\"no such file\\\"\"".to_string(), + ] + ); +} + // ======================================================================= // Obarray-based hierarchy tests // =======================================================================