Plug-ins: a call with nothing to make it fails the run

vc_call returning -11 (from the start function, or in a run that can't make
calls) now fails the run like every other code, so a plug-in that ignores
it can't report success for a call that never ran. Calls are allowed once
the module has loaded, so a start-function call gets -11 instead of
trapping.
This commit is contained in:
dotCooCoo
2026-11-10 11:58:08 -08:00
parent 5a81c1caba
commit 9689f79eca
4 changed files with 30 additions and 18 deletions
+7 -7
View File
@@ -122,7 +122,7 @@ pub const CALL_LIMIT: i32 = -9;
/// What `vc_call_result` returns: no call has a result yet.
pub const CALL_NO_RESULT: i32 = -10;
/// What `vc_call` returns: nothing can be called now (while the module is being loaded, or in a
/// run that isn't a filter's run on a document).
/// run that isn't a filter's run on a document). In a run, this fails it too.
pub const CALL_NO_CONTEXT: i32 = -11;
/// Most `vc_call` calls one run makes.
@@ -370,8 +370,8 @@ pub(crate) struct Run {
storage: Option<Arc<dyn Storage>>,
storage_calls: usize,
storage_bytes: usize,
/// The commands `vc_call` may run (the manifest's `commandAllowlist`), when the run has
/// something to run them ([`Run::with_calls`]); `None` otherwise.
/// The commands `vc_call` may run (the manifest's `commandAllowlist`), once the module has
/// loaded and when the run has something to run them ([`Run::allow_calls`]); `None` otherwise.
allowed: Option<Vec<String>>,
/// How many `vc_call` calls the run made, and the bytes of arguments and results they moved.
calls: usize,
@@ -416,10 +416,9 @@ impl Run {
self
}
/// The run, with `vc_call` running the commands in `allowed`.
pub(crate) fn with_calls(mut self, allowed: Vec<String>) -> Self {
/// From now on, `vc_call` runs the commands in `allowed`.
pub(crate) fn allow_calls(&mut self, allowed: Vec<String>) {
self.allowed = Some(allowed);
self
}
/// Records the run's first failed call, `e`, and returns `code`.
@@ -434,7 +433,8 @@ impl Run {
fn call_request(&mut self, memory: &[u8], id: (usize, usize), args: (usize, usize)) -> std::result::Result<(), i32> {
self.call_result = None;
if self.allowed.is_none() {
return Err(CALL_NO_CONTEXT);
let why = "vc_call: no command can be called here (while the module loads, or in a run that can't make calls)";
return Err(self.fail(CALL_NO_CONTEXT, Error::Abi(why.into())));
}
let shown = || {
id.0.checked_add(id.1)
+5 -4
View File
@@ -372,11 +372,12 @@ impl Plugin {
total.ok_or_else(|| Error::Limit(SELECTION_TOO_LARGE.into()))?;
let deadline = Deadline::new(limits.wall_time_ms);
let m = &self.manifest;
let mut run = Run::new(&m.id, m.kind != Kind::Effect, true, deadline).with_storage(crate::registry::storage(&m.id));
if bridge.is_some() {
run = run.with_calls(m.command_allowlist.clone());
}
let run = Run::new(&m.id, m.kind != Kind::Effect, true, deadline).with_storage(crate::registry::storage(&m.id));
let mut live = self.instantiate(run, &m.permissions(), report)?;
// Calls can be made from `vc_run` on, not from the start function.
if bridge.is_some() {
live.store.data_mut().run.allow_calls(m.command_allowlist.clone());
}
let out = self.run_live(&mut live, input, params, limits, &deadline, bridge);
let state = &mut live.store.data_mut().run;
*report = std::mem::take(&mut state.report);