fix(runtime): prevent dlclose() to avoid SIGSEGV on runtime teardown
Wrap LoadedRuntime._library in ManuallyDrop so dlclose() is never called. dlclose() unmaps the library code; thread-local destructors inside liblua.so then SIGSEGV when they try to run against the unmapped addresses. Also filter out non-.lua plugins in the Lua runtime's discover_plugins() so liblua.so does not attempt to load Rune plugins.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
//! Note: This module is infrastructure for the runtime architecture. Full integration
|
||||
//! is pending Phase 5 (AUR Packaging) when runtime packages will be available.
|
||||
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -69,8 +70,11 @@ pub struct ScriptRuntimeVTable {
|
||||
pub struct LoadedRuntime {
|
||||
/// Runtime name (for logging)
|
||||
name: &'static str,
|
||||
/// Keep library alive
|
||||
_library: Arc<Library>,
|
||||
/// Keep library alive — wrapped in ManuallyDrop so we never call dlclose().
|
||||
/// dlclose() unmaps the library code; any thread-local destructors inside the
|
||||
/// library then SIGSEGV when they try to run against the unmapped addresses.
|
||||
/// Runtime libraries live for the process lifetime, so leaking the handle is safe.
|
||||
_library: ManuallyDrop<Arc<Library>>,
|
||||
/// Runtime vtable
|
||||
vtable: &'static ScriptRuntimeVTable,
|
||||
/// Runtime handle (state)
|
||||
@@ -138,7 +142,7 @@ impl LoadedRuntime {
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
_library: library,
|
||||
_library: ManuallyDrop::new(library),
|
||||
vtable,
|
||||
handle,
|
||||
providers,
|
||||
@@ -166,6 +170,8 @@ impl LoadedRuntime {
|
||||
impl Drop for LoadedRuntime {
|
||||
fn drop(&mut self) {
|
||||
(self.vtable.drop)(self.handle);
|
||||
// Do NOT drop _library: ManuallyDrop ensures dlclose() is never called.
|
||||
// See field comment for rationale.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,6 +186,10 @@ pub fn discover_plugins(
|
||||
|
||||
match PluginManifest::load(&manifest_path) {
|
||||
Ok(manifest) => {
|
||||
// Skip plugins whose entry point is not a Lua file
|
||||
if !manifest.plugin.entry.ends_with(".lua") {
|
||||
continue;
|
||||
}
|
||||
let id = manifest.plugin.id.clone();
|
||||
if plugins.contains_key(&id) {
|
||||
eprintln!(
|
||||
|
||||
Reference in New Issue
Block a user