Skip to main content

fluentbase_runtime/syscall_handler/host/
forward_output.rs

1//! Builtin to append a slice of return_data to the output buffer.
2use crate::RuntimeContext;
3use fluentbase_types::ExitCode;
4use rwasm::{StoreTr, TrapCode, Value};
5
6/// Copies [offset, offset+length) from return_data into output; halts on out-of-bounds.
7pub fn syscall_forward_output_handler(
8    caller: &mut impl StoreTr<RuntimeContext>,
9    params: &[Value],
10    _result: &mut [Value],
11) -> Result<(), TrapCode> {
12    let (offset, length) = (
13        params[0].i32().unwrap() as u32,
14        params[1].i32().unwrap() as u32,
15    );
16    syscall_forward_output_impl(caller.data_mut(), offset, length).map_err(|err| {
17        caller.data_mut().execution_result.exit_code = err.into_i32();
18        TrapCode::ExecutionHalted
19    })
20}
21
22pub fn syscall_forward_output_impl(
23    ctx: &mut RuntimeContext,
24    offset: u32,
25    length: u32,
26) -> Result<(), ExitCode> {
27    let offset_length = offset
28        .checked_add(length)
29        .ok_or(ExitCode::InputOutputOutOfBounds)?;
30    if offset_length <= ctx.execution_result.return_data.len() as u32 {
31        let ret_data = &ctx.execution_result.return_data
32            [(offset as usize)..(offset as usize + length as usize)]
33            .to_vec();
34        ctx.execution_result.output.extend_from_slice(ret_data);
35        Ok(())
36    } else {
37        Err(ExitCode::InputOutputOutOfBounds)
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn test_offset_overflow_causes_memory_out_of_bounds() {
47        let mut ctx = RuntimeContext::default();
48        let exit_code = syscall_forward_output_impl(&mut ctx, u32::MAX, 100).unwrap_err();
49        assert_eq!(exit_code, ExitCode::InputOutputOutOfBounds);
50    }
51}