Skip to content
This repository was archived by the owner on Oct 20, 2024. It is now read-only.

Commit 28020a4

Browse files
committed
feat: check real stack changes inside fn vs its definition
1 parent 813b6b6 commit 28020a4

File tree

3 files changed

+196
-1
lines changed

3 files changed

+196
-1
lines changed

huff_parser/src/lib.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use huff_utils::{
88
ast::*,
99
error::*,
1010
files,
11-
prelude::{bytes32_to_string, hash_bytes, str_to_bytes32, Span},
11+
prelude::{bytes32_to_string, hash_bytes, str_to_bytes32, Opcode, Span},
1212
token::{Token, TokenKind},
1313
types::*,
1414
};
@@ -521,6 +521,51 @@ impl Parser {
521521

522522
let macro_statements: Vec<Statement> = self.parse_body()?;
523523

524+
let (body_statements_take, body_statements_return) =
525+
macro_statements.iter().fold((0i16, 0i16), |acc, st| {
526+
let (statement_takes, statement_returns) = match st.ty {
527+
StatementType::Literal(_) => (0i8, 1i8),
528+
StatementType::Opcode(opcode) => {
529+
let stack_changes = opcode.stack_changes();
530+
(stack_changes.0 as i8, stack_changes.1 as i8)
531+
}
532+
_ => (0i8, 0i8),
533+
};
534+
535+
// acc.1 is always non negative
536+
// acc.0 is always non positive
537+
let stack_takes = acc.0 + acc.1 - statement_takes as i16;
538+
let stack_returns = if statement_takes as i16 > acc.1 {
539+
statement_returns as i16
540+
} else {
541+
acc.1 - statement_takes as i16 + statement_returns as i16
542+
};
543+
(stack_takes, stack_returns)
544+
});
545+
546+
if outlined {
547+
if body_statements_take.abs() != macro_takes as i16 {
548+
return Err(ParserError {
549+
kind: ParserErrorKind::InvalidStackAnnotation(TokenKind::Takes),
550+
hint: Some(format!(
551+
"Fn specified to take {macro_takes} elements from the stack, but it takes {}",
552+
body_statements_take.abs()
553+
)),
554+
spans: AstSpan(self.spans.clone()),
555+
});
556+
}
557+
if body_statements_return != macro_returns as i16 {
558+
return Err(ParserError {
559+
kind: ParserErrorKind::InvalidStackAnnotation(TokenKind::Returns),
560+
hint: Some(format!(
561+
"Fn specified to return {macro_returns} elements to the stack, but it returns {}",
562+
body_statements_return
563+
)),
564+
spans: AstSpan(self.spans.clone()),
565+
});
566+
}
567+
}
568+
524569
Ok(MacroDefinition::new(
525570
macro_name,
526571
decorator,

huff_utils/src/error.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ pub enum ParserErrorKind {
6363
InvalidDecoratorFlag(String),
6464
/// Invalid decorator flag argument
6565
InvalidDecoratorFlagArg(TokenKind),
66+
/// Invalid stack annotation
67+
InvalidStackAnnotation(TokenKind),
6668
}
6769

6870
/// A Lexing Error
@@ -488,6 +490,14 @@ impl fmt::Display for CompilerError {
488490
pe.spans.error(pe.hint.as_ref())
489491
)
490492
}
493+
ParserErrorKind::InvalidStackAnnotation(rt) => {
494+
write!(
495+
f,
496+
"\nError: Invalid stack {} annotation in function definition \n{}\n",
497+
rt,
498+
pe.spans.error(pe.hint.as_ref())
499+
)
500+
}
491501
},
492502
CompilerError::PathBufRead(os_str) => {
493503
write!(

huff_utils/src/evm.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,146 @@ impl Opcode {
836836

837837
false
838838
}
839+
840+
/// Returns stack changes by the given opcode
841+
pub fn stack_changes(&self) -> (u8, u8) {
842+
match self {
843+
Opcode::Stop => (0, 0),
844+
Opcode::Add | Opcode::Mul | Opcode::Sub | Opcode::Div => (2, 1),
845+
Opcode::Sdiv | Opcode::Mod | Opcode::Smod => (2, 1),
846+
Opcode::Addmod | Opcode::Mulmod => (3, 1),
847+
Opcode::Exp => (2, 1),
848+
Opcode::Signextend => (2, 1),
849+
Opcode::Lt | Opcode::Gt => (2, 1),
850+
Opcode::Slt | Opcode::Sgt => (2, 1),
851+
Opcode::Eq => (2, 1),
852+
Opcode::Iszero => (1, 1),
853+
Opcode::And | Opcode::Or | Opcode::Xor => (2, 1),
854+
Opcode::Not => (1, 1),
855+
Opcode::Byte => (2, 1),
856+
Opcode::Shl | Opcode::Shr | Opcode::Sar => (2, 1),
857+
Opcode::Sha3 => (2, 1),
858+
Opcode::Address => (0, 1),
859+
Opcode::Balance => (1, 1),
860+
Opcode::Origin => (0, 1),
861+
Opcode::Caller => (0, 1),
862+
Opcode::Callvalue => (0, 1),
863+
Opcode::Calldataload => (1, 1),
864+
Opcode::Calldatasize => (0, 1),
865+
Opcode::Calldatacopy => (3, 0),
866+
Opcode::Codesize => (0, 1),
867+
Opcode::Codecopy => (3, 0),
868+
Opcode::Gasprice => (0, 1),
869+
Opcode::Extcodesize => (1, 1),
870+
Opcode::Extcodecopy => (4, 0),
871+
Opcode::Returndatasize => (0, 1),
872+
Opcode::Returndatacopy => (3, 0),
873+
Opcode::Extcodehash => (1, 1),
874+
Opcode::Blockhash => (1, 1),
875+
Opcode::Coinbase => (0, 1),
876+
Opcode::Timestamp => (0, 1),
877+
Opcode::Number => (0, 1),
878+
Opcode::Difficulty => (0, 1),
879+
Opcode::Prevrandao => (0, 1),
880+
Opcode::Gaslimit => (0, 1),
881+
Opcode::Chainid => (0, 1),
882+
Opcode::Selfbalance => (0, 1),
883+
Opcode::Basefee => (0, 1),
884+
Opcode::Pop => (1, 0),
885+
Opcode::Mload => (1, 1),
886+
Opcode::Mstore | Opcode::Mstore8 => (2, 0),
887+
Opcode::Sload => (1, 1),
888+
Opcode::Sstore => (2, 0),
889+
Opcode::Jump => (1, 0),
890+
Opcode::Jumpi => (2, 0),
891+
Opcode::Pc => (0, 1),
892+
Opcode::Msize => (0, 1),
893+
Opcode::Gas => (0, 1),
894+
Opcode::Jumpdest => (0, 0),
895+
Opcode::Push0 => (0, 1),
896+
Opcode::Push1 => (0, 1),
897+
Opcode::Push2 => (0, 1),
898+
Opcode::Push3 => (0, 1),
899+
Opcode::Push4 => (0, 1),
900+
Opcode::Push5 => (0, 1),
901+
Opcode::Push6 => (0, 1),
902+
Opcode::Push7 => (0, 1),
903+
Opcode::Push8 => (0, 1),
904+
Opcode::Push9 => (0, 1),
905+
Opcode::Push10 => (0, 1),
906+
Opcode::Push11 => (0, 1),
907+
Opcode::Push12 => (0, 1),
908+
Opcode::Push13 => (0, 1),
909+
Opcode::Push14 => (0, 1),
910+
Opcode::Push15 => (0, 1),
911+
Opcode::Push16 => (0, 1),
912+
Opcode::Push17 => (0, 1),
913+
Opcode::Push18 => (0, 1),
914+
Opcode::Push19 => (0, 1),
915+
Opcode::Push20 => (0, 1),
916+
Opcode::Push21 => (0, 1),
917+
Opcode::Push22 => (0, 1),
918+
Opcode::Push23 => (0, 1),
919+
Opcode::Push24 => (0, 1),
920+
Opcode::Push25 => (0, 1),
921+
Opcode::Push26 => (0, 1),
922+
Opcode::Push27 => (0, 1),
923+
Opcode::Push28 => (0, 1),
924+
Opcode::Push29 => (0, 1),
925+
Opcode::Push30 => (0, 1),
926+
Opcode::Push31 => (0, 1),
927+
Opcode::Push32 => (0, 1),
928+
Opcode::Dup1 => (0, 1),
929+
Opcode::Dup2 => (0, 1),
930+
Opcode::Dup3 => (0, 1),
931+
Opcode::Dup4 => (0, 1),
932+
Opcode::Dup5 => (0, 1),
933+
Opcode::Dup6 => (0, 1),
934+
Opcode::Dup7 => (0, 1),
935+
Opcode::Dup8 => (0, 1),
936+
Opcode::Dup9 => (0, 1),
937+
Opcode::Dup10 => (0, 1),
938+
Opcode::Dup11 => (0, 1),
939+
Opcode::Dup12 => (0, 1),
940+
Opcode::Dup13 => (0, 1),
941+
Opcode::Dup14 => (0, 1),
942+
Opcode::Dup15 => (0, 1),
943+
Opcode::Dup16 => (0, 1),
944+
Opcode::Swap1 => (0, 0),
945+
Opcode::Swap2 => (0, 0),
946+
Opcode::Swap3 => (0, 0),
947+
Opcode::Swap4 => (0, 0),
948+
Opcode::Swap5 => (0, 0),
949+
Opcode::Swap6 => (0, 0),
950+
Opcode::Swap7 => (0, 0),
951+
Opcode::Swap8 => (0, 0),
952+
Opcode::Swap9 => (0, 0),
953+
Opcode::Swap10 => (0, 0),
954+
Opcode::Swap11 => (0, 0),
955+
Opcode::Swap12 => (0, 0),
956+
Opcode::Swap13 => (0, 0),
957+
Opcode::Swap14 => (0, 0),
958+
Opcode::Swap15 => (0, 0),
959+
Opcode::Swap16 => (0, 0),
960+
Opcode::Log0 => (2, 0),
961+
Opcode::Log1 => (3, 0),
962+
Opcode::Log2 => (4, 0),
963+
Opcode::Log3 => (5, 0),
964+
Opcode::Log4 => (6, 0),
965+
Opcode::TLoad => (1, 1),
966+
Opcode::TStore => (2, 0),
967+
Opcode::Create => (3, 1),
968+
Opcode::Call => (7, 1),
969+
Opcode::Callcode => (7, 1),
970+
Opcode::Return => (2, 0),
971+
Opcode::Delegatecall => (6, 1),
972+
Opcode::Create2 => (4, 1),
973+
Opcode::Staticcall => (6, 1),
974+
Opcode::Revert => (2, 0),
975+
Opcode::Invalid => (0, 0),
976+
Opcode::Selfdestruct => (1, 0),
977+
}
978+
}
839979
}
840980

841981
impl fmt::Display for Opcode {

0 commit comments

Comments
 (0)