fix(plugin): guard plugin calls across host shutdown generations
Tests (and any host that shuts down then rescans) can hold instances of a PREVIOUS plugin generation; their entry points dangle after dlclose, so the next shutdown's destroyInstance notification jumped into unmapped memory (SIGSEGV on Linux; masked on macOS). Plugin gains an flag set by unload_all before dlclose; call_action/call_entry fail fast instead of calling into freed code.
This commit is contained in:
@@ -605,6 +605,11 @@ pub struct Plugin {
|
||||
/// OfxPlugin 结构指针(kOfxImageEffectPropPluginHandle 属性用;
|
||||
/// 公开:测试构造假插件需要)。
|
||||
pub ofx_plugin: *mut c_void,
|
||||
/// 二进制已卸载(host shutdown / unload_all)。置位后任何
|
||||
/// call_action/call_entry 直接失败而不触碰入口——插件入口指向
|
||||
/// 已 dlclose 的代码,调用即 SIGSEGV(测试串行 shutdown/重扫描
|
||||
/// 会产生跨代实例,它们持有的正是旧代插件记录)。
|
||||
pub unloaded: std::sync::atomic::AtomicBool,
|
||||
}
|
||||
|
||||
// dlopen 句柄与 OfxPlugin 指针是**不透明令牌**(只经 dlsym/插件
|
||||
@@ -654,6 +659,9 @@ impl Plugin {
|
||||
in_args: &PropertySet,
|
||||
out_args: &PropertySet,
|
||||
) -> i32 {
|
||||
if self.unloaded.load(std::sync::atomic::Ordering::Acquire) {
|
||||
return status::ERR_FATAL;
|
||||
}
|
||||
// 属性集经裸指针(标签 0)传给插件(property suite 接受)。
|
||||
let in_ptr = in_args as *const PropertySet as *mut c_void;
|
||||
let out_ptr = out_args as *const PropertySet as *mut c_void;
|
||||
@@ -676,6 +684,9 @@ impl Plugin {
|
||||
in_args: &PropertySet,
|
||||
out_args: &PropertySet,
|
||||
) -> i32 {
|
||||
if self.unloaded.load(std::sync::atomic::Ordering::Acquire) {
|
||||
return status::ERR_FATAL;
|
||||
}
|
||||
let in_ptr = in_args as *const PropertySet as *mut c_void;
|
||||
let out_ptr = out_args as *const PropertySet as *mut c_void;
|
||||
let action = cs(action);
|
||||
@@ -991,6 +1002,7 @@ impl PluginCache {
|
||||
lib,
|
||||
entry,
|
||||
ofx_plugin: ofx as *mut c_void,
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
};
|
||||
|
||||
// 根描述符属性(HS: effectDescriptorStuff,ofxhImageEffect.cpp:133-155)。
|
||||
@@ -1070,7 +1082,16 @@ impl PluginCache {
|
||||
|
||||
/// 卸载全部(shutdown 路径)。`scanned_paths` 一并清空——
|
||||
/// 否则再 init 后的扫描会被去重短路(缓存已空但路径仍在)。
|
||||
/// 卸载前先给每个插件置 `unloaded`:实例可能跨代存活(测试的
|
||||
/// 串行 shutdown/重扫描),它们持有的旧代入口已随 dlclose 失效,
|
||||
/// 置位后 call_action 直接失败而非跳野指针。
|
||||
pub(crate) fn unload_all(&self) {
|
||||
{
|
||||
let plugins = self.plugins.lock().unwrap_or_else(|e| e.into_inner());
|
||||
for p in plugins.iter() {
|
||||
p.unloaded.store(true, std::sync::atomic::Ordering::Release);
|
||||
}
|
||||
}
|
||||
self.plugins
|
||||
.lock()
|
||||
.unwrap_or_else(|e| e.into_inner())
|
||||
|
||||
@@ -1131,6 +1131,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: dummy_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
});
|
||||
let mut params = ParamSetInstance { params: Vec::new() };
|
||||
params.params.push(Box::new(ParamInstance::from_def(ParamDef::new(
|
||||
@@ -1235,6 +1236,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: dummy_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
});
|
||||
let inst = crate::instance::Instance {
|
||||
props: crate::property::PropertySet::new(),
|
||||
|
||||
@@ -574,6 +574,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: dummy_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
}),
|
||||
context: "OfxImageEffectContextFilter".into(),
|
||||
params: crate::param::ParamSetInstance { params: vec![] },
|
||||
|
||||
@@ -575,6 +575,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: dummy_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
};
|
||||
let interact = Interact::new(Arc::new(plugin), dummy_entry, std::ptr::null_mut());
|
||||
let handle = interact.handle();
|
||||
@@ -648,6 +649,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: recording_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
};
|
||||
let interact = Interact::new(Arc::new(plugin), recording_entry, std::ptr::null_mut());
|
||||
|
||||
@@ -717,6 +719,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: capture_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
};
|
||||
let interact = Interact::new(Arc::new(plugin), capture_entry, std::ptr::null_mut());
|
||||
// 设 pixelScale=2 → canonical = viewport/2。
|
||||
@@ -768,6 +771,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: capture_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
};
|
||||
let interact = Interact::new(Arc::new(plugin), capture_entry, std::ptr::null_mut());
|
||||
assert_eq!(interact.key_down(crate::host::KEY_RETURN, "", 1.0), status::OK);
|
||||
@@ -805,6 +809,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: counting_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
};
|
||||
let interact = Interact::new(Arc::new(plugin), counting_entry, std::ptr::null_mut());
|
||||
interact.destroy();
|
||||
|
||||
@@ -772,6 +772,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: dummy_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -449,6 +449,7 @@ mod tests {
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: dummy_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ fn dummy_plugin(descriptor: EffectDescriptor) -> std::sync::Arc<oakplugin::host:
|
||||
lib: std::ptr::null_mut(),
|
||||
entry: dummy_entry,
|
||||
ofx_plugin: std::ptr::null_mut(),
|
||||
unloaded: std::sync::atomic::AtomicBool::new(false),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user