diff --git a/compiler/noirc_evaluator/src/acir/call/intrinsics/vector_ops.rs b/compiler/noirc_evaluator/src/acir/call/intrinsics/vector_ops.rs index a8ba751b8c5..422fa140dc9 100644 --- a/compiler/noirc_evaluator/src/acir/call/intrinsics/vector_ops.rs +++ b/compiler/noirc_evaluator/src/acir/call/intrinsics/vector_ops.rs @@ -362,7 +362,7 @@ impl Context<'_> { let vector_typ = dfg.type_of_value(vector_contents); let block_id = self.ensure_array_is_initialized(vector_contents, dfg)?; - // Check if we're trying to pop from an empty vector + // Check if we're trying to pop from a known empty vector. if self.has_zero_length(vector_contents, dfg) { // Make sure this code is disabled, or fail with "Index out of bounds". let msg = "cannot pop from a vector with length 0".to_string(); @@ -388,6 +388,19 @@ impl Context<'_> { return Ok(results); } + // Check that the vector length is not zero. + // This is different from the previous check as this is a runtime check. + let zero = self.acir_context.add_constant(FieldElement::zero()); + let assert_message = self.acir_context.generate_assertion_message_payload( + "Attempt to pop_front from an empty vector".to_string(), + ); + self.acir_context.assert_neq_var( + vector_length, + zero, + self.current_side_effects_enabled_var, + Some(assert_message), + )?; + let one = self.acir_context.add_constant(FieldElement::one()); let new_vector_length = self.acir_context.sub_var(vector_length, one)?; diff --git a/test_programs/execution_failure/conditional_pop_back_from_empty_vector/Nargo.toml b/test_programs/execution_failure/conditional_pop_back_from_empty_vector/Nargo.toml new file mode 100644 index 00000000000..be43c7c09cb --- /dev/null +++ b/test_programs/execution_failure/conditional_pop_back_from_empty_vector/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "conditional_pop_back_from_empty_vector" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] diff --git a/test_programs/execution_failure/conditional_pop_back_from_empty_vector/Prover.toml b/test_programs/execution_failure/conditional_pop_back_from_empty_vector/Prover.toml new file mode 100644 index 00000000000..c3aeb7874fd --- /dev/null +++ b/test_programs/execution_failure/conditional_pop_back_from_empty_vector/Prover.toml @@ -0,0 +1,2 @@ +input = [1] +b = true diff --git a/test_programs/execution_failure/conditional_pop_back_from_empty_vector/src/main.nr b/test_programs/execution_failure/conditional_pop_back_from_empty_vector/src/main.nr new file mode 100644 index 00000000000..bf02b0d7002 --- /dev/null +++ b/test_programs/execution_failure/conditional_pop_back_from_empty_vector/src/main.nr @@ -0,0 +1,14 @@ +pub fn main(input: [u32; 1], b: bool) -> pub u32 { + let mut s = input.as_vector(); + + if (b) { + let (new_slice, _) = s.pop_back(); + s = new_slice; + } else { + s = s.push_front(5); + } + + let (_, ret) = s.pop_back(); + + ret +} diff --git a/test_programs/execution_failure/conditional_pop_front_from_empty_vector/Nargo.toml b/test_programs/execution_failure/conditional_pop_front_from_empty_vector/Nargo.toml new file mode 100644 index 00000000000..6e8e5dbd098 --- /dev/null +++ b/test_programs/execution_failure/conditional_pop_front_from_empty_vector/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "conditional_pop_front_from_empty_vector" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] diff --git a/test_programs/execution_failure/conditional_pop_front_from_empty_vector/Prover.toml b/test_programs/execution_failure/conditional_pop_front_from_empty_vector/Prover.toml new file mode 100644 index 00000000000..c3aeb7874fd --- /dev/null +++ b/test_programs/execution_failure/conditional_pop_front_from_empty_vector/Prover.toml @@ -0,0 +1,2 @@ +input = [1] +b = true diff --git a/test_programs/execution_failure/conditional_pop_front_from_empty_vector/src/main.nr b/test_programs/execution_failure/conditional_pop_front_from_empty_vector/src/main.nr new file mode 100644 index 00000000000..0813b9c5962 --- /dev/null +++ b/test_programs/execution_failure/conditional_pop_front_from_empty_vector/src/main.nr @@ -0,0 +1,14 @@ +pub fn main(input: [u32; 1], b: bool) -> pub u32 { + let mut s = input.as_vector(); + + if (b) { + let (_, new_slice) = s.pop_front(); + s = new_slice; + } else { + s = s.push_front(5); + } + + let (ret, _) = s.pop_front(); + + ret +} diff --git a/test_programs/execution_failure/conditional_remove_from_empty_vector/Nargo.toml b/test_programs/execution_failure/conditional_remove_from_empty_vector/Nargo.toml new file mode 100644 index 00000000000..9e4d4e129dc --- /dev/null +++ b/test_programs/execution_failure/conditional_remove_from_empty_vector/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "conditional_remove_from_empty_vector" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] diff --git a/test_programs/execution_failure/conditional_remove_from_empty_vector/Prover.toml b/test_programs/execution_failure/conditional_remove_from_empty_vector/Prover.toml new file mode 100644 index 00000000000..c3aeb7874fd --- /dev/null +++ b/test_programs/execution_failure/conditional_remove_from_empty_vector/Prover.toml @@ -0,0 +1,2 @@ +input = [1] +b = true diff --git a/test_programs/execution_failure/conditional_remove_from_empty_vector/src/main.nr b/test_programs/execution_failure/conditional_remove_from_empty_vector/src/main.nr new file mode 100644 index 00000000000..43a99b83fe7 --- /dev/null +++ b/test_programs/execution_failure/conditional_remove_from_empty_vector/src/main.nr @@ -0,0 +1,14 @@ +pub fn main(input: [u32; 1], b: bool) -> pub u32 { + let mut s = input.as_vector(); + + if (b) { + let (new_slice, _) = s.remove(0); + s = new_slice; + } else { + s = s.push_front(5); + } + + let (_, ret) = s.remove(0); + + ret +}