From a4931b55cb676ab29832966935eeda4513f38d05 Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 25 Jul 2024 09:27:17 +0200 Subject: [PATCH 1/3] wip: test --- .../interpreter/src/interpreter/analysis.rs | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/crates/interpreter/src/interpreter/analysis.rs b/crates/interpreter/src/interpreter/analysis.rs index 864e5c3a73..cdbc3763b5 100644 --- a/crates/interpreter/src/interpreter/analysis.rs +++ b/crates/interpreter/src/interpreter/analysis.rs @@ -160,6 +160,21 @@ pub fn validate_eof_codes( // first code section is accessed by default. tracker.codes[0] = true; + // start validation from code section 0. + let mut stack = Vec::with_capacity(16); + stack.push(0); + while let Some(index) = stack.pop() { + let code = &eof.body.code_section[index]; + validate_eof_code( + code, + eof.header.data_size as usize, + index, + eof.body.container_section.len(), + &eof.body.types_section, + &mut tracker, + )?; + } + for (index, code) in eof.body.code_section.iter().enumerate() { validate_eof_code( code, @@ -302,6 +317,8 @@ pub struct AccessTracker { pub this_container_code_type: Option, /// Vector of accessed codes. pub codes: Vec, + /// Stack of codes section that needs to be processed. + pub processing_stack: Vec, /// Code accessed by subcontainer and expected subcontainer first code type. /// EOF code can be invoked in EOFCREATE mode or used in RETURNCONTRACT opcode. /// if SubContainer is called from EOFCREATE it needs to be ReturnContract type. @@ -313,15 +330,38 @@ pub struct AccessTracker { impl AccessTracker { /// Returns a new instance of `CodeSubContainerAccess`. + /// + /// Mark first code section as accessed and push first it to the stack. + /// + /// # Panics + /// + /// Panics if `codes_size` is zero. pub fn new( this_container_code_type: Option, codes_size: usize, subcontainers_size: usize, ) -> Self { - Self { + if codes_size == 0 { + panic!("There should be at least one code section"); + } + let mut this = Self { this_container_code_type, codes: vec![false; codes_size], + processing_stack: Vec::with_capacity(4), subcontainers: vec![None; subcontainers_size], + }; + this.codes[0] = true; + this.processing_stack.push(0); + this + } + + /// Mark code as accessed. + /// + /// If code was not accessed before, it will be added to the processing stack. + pub fn access_code(&mut self, index: usize) { + if !self.codes[index] { + self.codes[index] = true; + self.processing_stack.push(index); } } @@ -843,4 +883,28 @@ mod test { ); assert!(eof.is_ok()); } + + #[test] + fn test() { + let eof = validate_raw_eof_inner( + hex!("ef0001010004020001000504ff0300008000023a60cbee1800").into(), + None, + ); + assert_eq!( + eof, + Err(EofError::Validation(EofValidationError::DataNotFilled)) + ); + } + + #[test] + fn unreachable_code_section() { + let eof = validate_raw_eof_inner( + hex!("ef00010100040200010001040000000080000000").into(), + None, + ); + assert_eq!( + eof, + Err(EofError::Validation(EofValidationError::DataNotFilled)) + ); + } } From 5d380da647eacff862faa181325e7387fe09b5f6 Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 25 Jul 2024 09:49:31 +0200 Subject: [PATCH 2/3] fix(EOF): Validate code access in stack --- .../interpreter/src/interpreter/analysis.rs | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/crates/interpreter/src/interpreter/analysis.rs b/crates/interpreter/src/interpreter/analysis.rs index cdbc3763b5..6ddcddbf5f 100644 --- a/crates/interpreter/src/interpreter/analysis.rs +++ b/crates/interpreter/src/interpreter/analysis.rs @@ -11,7 +11,7 @@ use crate::{ }, OPCODE_INFO_JUMPTABLE, STACK_LIMIT, }; -use core::convert::identity; +use core::{convert::identity, mem}; use std::{borrow::Cow, fmt, sync::Arc, vec, vec::Vec}; const EOF_NON_RETURNING_FUNCTION: u8 = 0x80; @@ -157,13 +157,9 @@ pub fn validate_eof_codes( eof.body.code_section.len(), eof.body.container_section.len(), ); - // first code section is accessed by default. - tracker.codes[0] = true; - // start validation from code section 0. - let mut stack = Vec::with_capacity(16); - stack.push(0); - while let Some(index) = stack.pop() { + while let Some(index) = tracker.processing_stack.pop() { + // assume index is correct. let code = &eof.body.code_section[index]; validate_eof_code( code, @@ -175,16 +171,6 @@ pub fn validate_eof_codes( )?; } - for (index, code) in eof.body.code_section.iter().enumerate() { - validate_eof_code( - code, - eof.header.data_size as usize, - index, - eof.body.container_section.len(), - &eof.body.types_section, - &mut tracker, - )?; - } // iterate over accessed codes and check if all are accessed. if !tracker.codes.into_iter().all(identity) { return Err(EofValidationError::CodeSectionNotAccessed); @@ -358,9 +344,11 @@ impl AccessTracker { /// Mark code as accessed. /// /// If code was not accessed before, it will be added to the processing stack. + /// + /// Assumes that index is valid. pub fn access_code(&mut self, index: usize) { - if !self.codes[index] { - self.codes[index] = true; + let was_accessed = mem::replace(&mut self.codes[index], true); + if !was_accessed { self.processing_stack.push(index); } } @@ -899,12 +887,15 @@ mod test { #[test] fn unreachable_code_section() { let eof = validate_raw_eof_inner( - hex!("ef00010100040200010001040000000080000000").into(), + hex!("ef000101000c02000300030001000304000000008000000080000000800000e50001fee50002") + .into(), None, ); assert_eq!( eof, - Err(EofError::Validation(EofValidationError::DataNotFilled)) + Err(EofError::Validation( + EofValidationError::CodeSectionNotAccessed + )) ); } } From e33ddcd3a7a05574c5eb67c3c549061f1082a5d6 Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 25 Jul 2024 09:52:00 +0200 Subject: [PATCH 3/3] add code access --- crates/interpreter/src/interpreter/analysis.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/interpreter/src/interpreter/analysis.rs b/crates/interpreter/src/interpreter/analysis.rs index 6ddcddbf5f..fe88b5ca6c 100644 --- a/crates/interpreter/src/interpreter/analysis.rs +++ b/crates/interpreter/src/interpreter/analysis.rs @@ -617,7 +617,7 @@ pub fn validate_eof_code( // stack diff depends on input/output of the called code. stack_io_diff = target_types.io_diff(); // mark called code as accessed. - tracker.codes[section_i] = true; + tracker.access_code(section_i); // we decrement by `types.inputs` as they are considered as send // to the called code and included in types.max_stack_size. @@ -645,7 +645,7 @@ pub fn validate_eof_code( // stack overflow return Err(EofValidationError::StackOverflow); } - tracker.codes[target_index] = true; + tracker.access_code(target_index); if target_types.outputs == EOF_NON_RETURNING_FUNCTION { // if it is not returning