Skip to main content

fluentbase_runtime/syscall_handler/host/
read_output.rs

1//! Builtin to copy a slice of the current return_data into linear memory.
2use crate::syscall_handler::syscall_process_exit_code;
3use crate::RuntimeContext;
4use fluentbase_types::ExitCode;
5use rwasm::{StoreTr, TrapCode, Value};
6
7/// Reads [offset, offset+length) from ctx.execution_result.return_data and writes it at target_ptr.
8pub fn syscall_read_output_handler(
9    ctx: &mut impl StoreTr<RuntimeContext>,
10    params: &[Value],
11    _result: &mut [Value],
12) -> Result<(), TrapCode> {
13    let (target_ptr, offset, length) = (
14        params[0].i32().unwrap() as usize,
15        params[1].i32().unwrap() as u32,
16        params[2].i32().unwrap() as u32,
17    );
18    let input = syscall_read_output_impl(ctx.data_mut(), offset, length)
19        .map_err(|exit_code| syscall_process_exit_code(ctx, exit_code))?;
20    ctx.memory_write(target_ptr, &input)?;
21    Ok(())
22}
23
24pub fn syscall_read_output_impl(
25    ctx: &mut RuntimeContext,
26    offset: u32,
27    length: u32,
28) -> Result<Vec<u8>, ExitCode> {
29    let offset_length = offset
30        .checked_add(length)
31        .ok_or(ExitCode::InputOutputOutOfBounds)?;
32    if offset_length <= ctx.execution_result.return_data.len() as u32 {
33        Ok(
34            ctx.execution_result.return_data
35                [(offset as usize)..(offset as usize + length as usize)]
36                .to_vec(),
37        )
38    } else {
39        Err(ExitCode::InputOutputOutOfBounds)
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn test_offset_overflow_causes_memory_out_of_bounds() {
49        let mut ctx = RuntimeContext::default();
50        let exit_code = syscall_read_output_impl(&mut ctx, u32::MAX, 100).unwrap_err();
51        assert_eq!(exit_code, ExitCode::InputOutputOutOfBounds);
52    }
53}