Skip to content
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#### Upcoming Changes

* Fix bug affecting cairo1 programs with input and System builtin [#2207](https://github.com/lambdaclass/cairo-vm/pull/2207)

* chore: Pin generic-array version to 0.14.7 or lower. [#2227](https://github.com/lambdaclass/cairo-vm/pull/2227)

* fix: Added `cairo_1_test_contracts` and `cairo_2_test_contracts` as dependencies for `test-extensive_hints` target [#2201](https://github.com/lambdaclass/cairo-vm/pull/2201)
Expand Down
49 changes: 25 additions & 24 deletions cairo1-run/src/cairo_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ use num_bigint::{BigInt, Sign};
use num_traits::{cast::ToPrimitive, Zero};
use std::{collections::HashMap, iter::Peekable};

// Necessary memory gaps for the values created on the entry code of each implicit builtin
const SEGMENT_ARENA_GAPS: usize = 4;
const GAS_BUILTIN_GAPS: usize = 1;
const SYSTEM_BUILTIN_GAPS: usize = 1;

/// Representation of a cairo argument
/// Can consist of a single Felt or an array of Felts
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -469,20 +474,13 @@ fn load_arguments(
cairo_run_config: &Cairo1RunConfig,
main_func: &Function,
) -> Result<(), Error> {
let got_gas_builtin = main_func
.signature
.param_types
.iter()
.any(|ty| ty.debug_name.as_ref().is_some_and(|n| n == "GasBuiltin"));
let got_gas_builtin = got_implicit_builtin(&main_func.signature.param_types, "GasBuiltin");
if cairo_run_config.args.is_empty() && !got_gas_builtin {
// Nothing to be done
return Ok(());
}
let got_segment_arena = main_func
.signature
.param_types
.iter()
.any(|ty| ty.debug_name.as_ref().is_some_and(|n| n == "SegmentArena"));
let got_segment_arena = got_implicit_builtin(&main_func.signature.param_types, "SegmentArena");
let got_system_builtin = got_implicit_builtin(&main_func.signature.param_types, "System");
// This AP correction represents the memory slots taken up by the values created by `create_entry_code`:
// These include:
// * The builtin bases (not including output)
Expand All @@ -497,10 +495,13 @@ fn load_arguments(
ap_offset += runner.get_program().builtins_len() - 1;
}
if got_segment_arena {
ap_offset += 4;
ap_offset += SEGMENT_ARENA_GAPS;
}
if got_gas_builtin {
ap_offset += 1;
ap_offset += GAS_BUILTIN_GAPS;
}
if got_system_builtin {
ap_offset += SYSTEM_BUILTIN_GAPS;
}
for arg in cairo_run_config.args {
match arg {
Expand Down Expand Up @@ -547,16 +548,9 @@ fn create_entry_code(
) -> Result<(CasmContext, Vec<BuiltinName>), Error> {
let copy_to_output_builtin = config.copy_to_output();
let signature = &func.signature;
let got_segment_arena = signature.param_types.iter().any(|ty| {
get_info(sierra_program_registry, ty)
.map(|x| x.long_id.generic_id == SegmentArenaType::ID)
.unwrap_or_default()
});
let got_gas_builtin = signature.param_types.iter().any(|ty| {
get_info(sierra_program_registry, ty)
.map(|x| x.long_id.generic_id == GasBuiltinType::ID)
.unwrap_or_default()
});
let got_segment_arena = got_implicit_builtin(&signature.param_types, "SegmentArena");
let got_gas_builtin = got_implicit_builtin(&signature.param_types, "GasBuiltin");
let got_system_builtin = got_implicit_builtin(&signature.param_types, "System");
// The builtins in the formatting expected by the runner.
let (builtins, builtin_offset) =
get_function_builtins(&signature.param_types, copy_to_output_builtin);
Expand Down Expand Up @@ -738,10 +732,12 @@ fn create_entry_code(
// We lost the output_ptr var after re-scoping, so we need to create it again
// The last instruction will write the last output ptr so we can find it in [ap - 1]
let output_ptr = ctx.add_var(CellExpression::Deref(deref!([ap - 1])));
// len(builtins - output) + len(builtins) + if segment_arena: segment_arena_ptr + info_ptr + 0 + (segment_arena_ptr + 3) + (gas_builtin)
// len(builtins - output) + len(builtins) + if segment_arena: segment_arena_ptr +
// info_ptr + 0 + (segment_arena_ptr + 3) + (gas_builtin) + (system_builtin)
let offset = (2 * builtins.len() - 1
+ 4 * got_segment_arena as usize
+ got_gas_builtin as usize) as i16;
+ got_gas_builtin as usize
+ got_system_builtin as usize) as i16;
let array_start_ptr = ctx.add_var(CellExpression::Deref(deref!([fp + offset])));
let array_end_ptr = ctx.add_var(CellExpression::Deref(deref!([fp + offset + 1])));
casm_build_extend! {ctx,
Expand Down Expand Up @@ -1008,6 +1004,11 @@ fn check_only_array_felt_return_type(
_ => false,
}
}
fn got_implicit_builtin(param_types: &[ConcreteTypeId], builtin_name: &str) -> bool {
param_types
.iter()
.any(|ty| ty.debug_name.as_ref().is_some_and(|n| n == builtin_name))
}
Comment on lines +1007 to +1011
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use BuiltinName here instead of a &str, just to be safe. You can convert a ty.debug_name with BuiltinName::from(s)

Copy link
Contributor Author

@DiegoCivi DiegoCivi Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to implement it but there is no BuiltinName variant for the gas builtin or system builtin


fn is_panic_result(return_type_id: Option<&ConcreteTypeId>) -> bool {
return_type_id
Expand Down
21 changes: 21 additions & 0 deletions cairo1-run/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,27 @@ mod tests {
None,
None
)]
#[case(
"with_input/implicit_system_builtin.cairo",
"[1 2]",
"[1 2]",
Some("[1 2]"),
Some("[1 2]")
)]
#[case(
"with_input/implicit_gas_builtin.cairo",
"[1 2]",
"[1 2]",
Some("[1 2]"),
Some("[1 2]")
)]
#[case(
"with_input/system_segment_gas.cairo",
"[1 2]",
"[1 2]",
Some("[1 2]"),
Some("[1 2]")
)]
fn test_run_program(
#[case] program: &str,
#[case] expected_output: &str,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main(input: Array<felt252>) -> Array<felt252> {
core::internal::require_implicit::<GasBuiltin>();
input
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main(input: Array<felt252>) -> Array<felt252> {
core::internal::require_implicit::<System>();
input
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn main(input:Array<felt252>) -> Array<felt252> {
core::internal::require_implicit::<System>();
let _elements: Felt252Dict<Nullable<Span<u8>>> = Default::default();
input
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main(input: Array<felt252>) -> Array<felt252> {
core::internal::require_implicit::<GasBuiltin>();
input
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main(input: Array<felt252>) -> Array<felt252> {
core::internal::require_implicit::<System>();
input
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn main(input:Array<felt252>) -> Array<felt252> {
core::internal::require_implicit::<System>();
let _elements: Felt252Dict<Nullable<Span<u8>>> = Default::default();
input
}
Loading