Skip to content

Commit

Permalink
add CompilerError and fix JitValue::BoundedInt range check (#693)
Browse files Browse the repository at this point in the history
* add CompilerError and fix BoundedInt range check

* fix clippy

* small fix

* Update src/error.rs

Co-authored-by: Mario Rugiero <[email protected]>

---------

Co-authored-by: Mario Rugiero <[email protected]>
Co-authored-by: Iñaki Garay <[email protected]>
Co-authored-by: Edgar <[email protected]>
  • Loading branch information
4 people authored Jul 22, 2024
1 parent fa2fa40 commit 3fba00d
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 11 deletions.
14 changes: 12 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use cairo_lang_sierra::extensions::modules::utils::Range;
use cairo_lang_sierra::{
edit_state::EditStateError, ids::ConcreteTypeId, program_registry::ProgramRegistryError,
};
use num_bigint::BigInt;
use std::{alloc::LayoutError, num::TryFromIntError};
use thiserror::Error;

Expand Down Expand Up @@ -44,8 +45,8 @@ pub enum Error {
#[error(transparent)]
SierraAssert(SierraAssertError),

#[error("a compiler related error happened: {0}")]
Error(String),
#[error(transparent)]
Compiler(#[from] CompilerError),

#[error(transparent)]
EditStateError(#[from] EditStateError),
Expand Down Expand Up @@ -79,6 +80,15 @@ pub enum SierraAssertError {
Range { ranges: Box<(Range, Range)> },
}

#[derive(Error, Debug)]
pub enum CompilerError {
#[error("BoundedInt value is out of range: {:?} not within [{:?}, {:?})", value, range.0, range.1)]
BoundedIntOutOfRange {
value: Box<BigInt>,
range: Box<(BigInt, BigInt)>,
},
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
172 changes: 163 additions & 9 deletions src/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! A Rusty interface to provide parameters to JIT calls.
use crate::{
error::CompilerError,
error::Error,
types::{felt252::PRIME, TypeBuilder},
utils::{felt252_bigint, get_integer_layout, layout_repeat, next_multiple_of_usize},
Expand Down Expand Up @@ -204,22 +205,27 @@ impl JitValue {
} => {
let value = value.to_bigint();

if lower < upper {
return Err(Error::Error("BoundedInt range is invalid".to_string()));
if lower >= upper {
// If lower bound is greater than or equal to upper bound
// Should not happen with correct range definition
return Err(CompilerError::BoundedIntOutOfRange {
value: Box::new(value),
range: Box::new((lower.clone(), upper.clone())),
}
.into());
}

let prime = &PRIME.to_bigint().unwrap();
let lower = lower.rem_euclid(prime);
let upper = upper.rem_euclid(prime);

if lower <= upper {
if !(lower <= value && value < upper) {
return Err(Error::Error(
"BoundedInt value is out of range".to_string(),
));
// Check if value is within the valid range
if !(lower <= value && value < upper) {
return Err(CompilerError::BoundedIntOutOfRange {
value: Box::new(value),
range: Box::new((lower, upper)),
}
} else if !(upper > value && value >= lower) {
return Err(Error::Error("BoundedInt value is out of range".to_string()));
.into());
}

let ptr = arena.alloc_layout(get_integer_layout(252)).cast();
Expand Down Expand Up @@ -1252,6 +1258,154 @@ mod test {
assert!(result.is_ok());
}

#[test]
fn test_to_jit_bounded_int_valid() {
// Parse the program
let program = ProgramParser::new()
.parse(
"type felt252 = felt252;
type BoundedInt = BoundedInt<10, 510>;",
)
.unwrap();

// Create the registry for the program
let registry = ProgramRegistry::<CoreType, CoreLibfunc>::new(&program).unwrap();

// Valid case
assert_eq!(
unsafe {
*JitValue::BoundedInt {
value: Felt::from(16),
range: Range {
lower: BigInt::from(10),
upper: BigInt::from(510),
},
}
.to_jit(&Bump::new(), &registry, &program.type_declarations[1].id)
.unwrap()
.cast::<[u32; 8]>()
.as_ptr()
},
[16, 0, 0, 0, 0, 0, 0, 0]
);
}

#[test]
fn test_to_jit_bounded_int_lower_bound_greater_than_upper() {
// Parse the program
let program = ProgramParser::new()
.parse(
"type felt252 = felt252;
type BoundedInt = BoundedInt<10, 510>;", // Note: lower > upper
)
.unwrap();

// Create the registry for the program
let registry = ProgramRegistry::<CoreType, CoreLibfunc>::new(&program).unwrap();

// Error case: lower bound greater than upper bound
let result = JitValue::BoundedInt {
value: Felt::from(16),
range: Range {
lower: BigInt::from(510),
upper: BigInt::from(10),
},
}
.to_jit(&Bump::new(), &registry, &program.type_declarations[1].id);

assert!(matches!(
result,
Err(Error::Compiler(CompilerError::BoundedIntOutOfRange { .. }))
));
}

#[test]
fn test_to_jit_bounded_int_value_less_than_lower_bound() {
// Parse the program
let program = ProgramParser::new()
.parse(
"type felt252 = felt252;
type BoundedInt = BoundedInt<10, 510>;",
)
.unwrap();

// Create the registry for the program
let registry = ProgramRegistry::<CoreType, CoreLibfunc>::new(&program).unwrap();

// Error case: value less than lower bound
let result = JitValue::BoundedInt {
value: Felt::from(9),
range: Range {
lower: BigInt::from(10),
upper: BigInt::from(510),
},
}
.to_jit(&Bump::new(), &registry, &program.type_declarations[1].id);

assert!(matches!(
result,
Err(Error::Compiler(CompilerError::BoundedIntOutOfRange { .. }))
));
}

#[test]
fn test_to_jit_bounded_int_value_greater_than_or_equal_to_upper_bound() {
// Parse the program
let program = ProgramParser::new()
.parse(
"type felt252 = felt252;
type BoundedInt = BoundedInt<10, 510>;",
)
.unwrap();

// Create the registry for the program
let registry = ProgramRegistry::<CoreType, CoreLibfunc>::new(&program).unwrap();

// Error case: value greater than or equal to upper bound
let result = JitValue::BoundedInt {
value: Felt::from(512),
range: Range {
lower: BigInt::from(10),
upper: BigInt::from(510),
},
}
.to_jit(&Bump::new(), &registry, &program.type_declarations[1].id);

assert!(matches!(
result,
Err(Error::Compiler(CompilerError::BoundedIntOutOfRange { .. }))
));
}

#[test]
fn test_to_jit_bounded_int_equal_bounds_and_value() {
// Parse the program
let program = ProgramParser::new()
.parse(
"type felt252 = felt252;
type BoundedInt = BoundedInt<10, 10>;", // Note: lower = upper
)
.unwrap();

// Create the registry for the program
let registry = ProgramRegistry::<CoreType, CoreLibfunc>::new(&program).unwrap();

// Error case: value equals lower and upper bound (upper bound is exclusive)
let result = JitValue::BoundedInt {
value: Felt::from(10),
range: Range {
lower: BigInt::from(10),
upper: BigInt::from(10),
},
}
.to_jit(&Bump::new(), &registry, &program.type_declarations[1].id);

assert!(matches!(
result,
Err(Error::Compiler(CompilerError::BoundedIntOutOfRange { .. }))
));
}

#[test]
#[should_panic(expected = "Variant index out of range.")]
fn test_to_jit_enum_variant_out_of_range() {
Expand Down

0 comments on commit 3fba00d

Please sign in to comment.