Injection: ret and call

Replace the return of the current function; call a firmware function and get its result.

since 0.3.0

Methods

EntrySignatureAvailable sinceAPI 3
retret(value=None) -> dict0.3.0unchanged
callcall(function, *args, this=None, signature=None, timeout=None) -> dict0.3.0await in async; timeout=

API 3 changes (0.5.0)

call is awaited in async; timeout= bounds the call (0.5.0). ret does not execute the function body.

Recommended

After ret, continue to caller processing and check consumption, skipped effects and the next input (tests/controlled-input). SRAM readback does not prove consumption. For a buffer: a packet in an experiment-owned buffer, call through Pointer with the exact length, ordering, rejection, re-entry and the next ordinary packet (tests/buffer-consumption). ret checks the caller; call uses an explicit timeout. In the 0.6.0 candidate namespace/static require one symbol; A4.2 supports explicit this and exact signature; A4.3a adds Pointer/Reference with type/SRAM checks. A4.3b adjusts this/Pointer/Reference to an unambiguous non-virtual DWARF base; converting Pointer requires count=1. Compare the subobject address with an independent oracle. Count does not constrain the function body. Check outcome/return_state before return_value; pass logical time as an argument.

t.reach("sample_input")
result = t.ret(1)
t.check("forced", result["outcome"], "forced")
t.reach("after_processing")  # Caller must run before checking consumption.
t.check("caller consumed the value", t.read("input_state.consumed"), 1)

value = t.call("app_checksum", 7, timeout=2)       # async def: await t.call(...)
t.check("returned", value["outcome"], "returned")
t.check("value available", value["return_state"], "available")
t.check("checksum(7)", value["return_value"], 22)

# Separate tests/logical-time ELF: ticks are not host seconds.
t.reach("ready")
t.call("start", 100, 10, timeout=2)
result = t.call("poll", 110, timeout=2)
t.check("returned", result["outcome"], "returned")
t.check("value available", result["return_state"], "available")
t.check("DONE", result["return_value"], 2)

Avoid

A call inside an expression is refused; a call without a timeout is bounded only by the scenario limit. ret does not restore an interrupted call. Software substitution does not establish a physical button press or peripheral failure. Writing a buffer without a call is not consumption; calling a handler does not test DMA or the interrupt.

t.check("DONE", t.call("poll", 110), 2)   # dict is not the returned number

t.read("app_checksum(7)")   # refused: expression_call_forbidden
t.call("app_wait_forever")   # no timeout: only the scenario limit stops it
t.call("app_log", "text")   # string argument: unsupported_argument
t.call("demo::overloaded", 1)   # ambiguous_function, no overload guessing
t.call("Probe::add", 1)   # unsupported_method: explicit this is required

The fragments show refused or discouraged patterns, not a working recipe.

Fragments for a scenario body; firmware symbols are illustrative.

← ChecksAll groupsPoints →