Skip to content

Commit 73fec68

Browse files
authored
fix(cast): disassembler PC & end of code push padding (#10520)
* fix da * fix da test * fix fmt
1 parent 38536c9 commit 73fec68

File tree

2 files changed

+25
-12
lines changed

2 files changed

+25
-12
lines changed

crates/cast/src/lib.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2387,16 +2387,21 @@ mod tests {
23872387
#[test]
23882388
fn disassemble_incomplete_sequence() {
23892389
let incomplete = &hex!("60"); // PUSH1
2390-
let disassembled = Cast::disassemble(incomplete);
2391-
assert!(disassembled.is_err());
2390+
let disassembled = Cast::disassemble(incomplete).unwrap();
2391+
assert_eq!(disassembled, "00000000: PUSH1 0x00\n");
23922392

23932393
let complete = &hex!("6000"); // PUSH1 0x00
23942394
let disassembled = Cast::disassemble(complete);
23952395
assert!(disassembled.is_ok());
23962396

23972397
let incomplete = &hex!("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // PUSH32 with 31 bytes
2398-
let disassembled = Cast::disassemble(incomplete);
2399-
assert!(disassembled.is_err());
2398+
2399+
let disassembled = Cast::disassemble(incomplete).unwrap();
2400+
2401+
assert_eq!(
2402+
disassembled,
2403+
"00000000: PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\n"
2404+
);
24002405

24012406
let complete = &hex!("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // PUSH32 with 32 bytes
24022407
let disassembled = Cast::disassemble(complete);

crates/evm/core/src/ic.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,34 +98,42 @@ fn make_map<const PC_FIRST: bool>(code: &[u8]) -> FxHashMap<u32, u32> {
9898
}
9999

100100
/// Represents a single instruction consisting of the opcode and its immediate data.
101-
pub struct Instruction<'a> {
101+
pub struct Instruction {
102102
/// OpCode, if it could be decoded.
103103
pub op: Option<OpCode>,
104104
/// Immediate data following the opcode.
105-
pub immediate: &'a [u8],
105+
pub immediate: Box<[u8]>,
106106
/// Program counter of the opcode.
107107
pub pc: u32,
108108
}
109109

110110
/// Decodes raw opcode bytes into [`Instruction`]s.
111-
pub fn decode_instructions(code: &[u8]) -> Result<Vec<Instruction<'_>>> {
111+
pub fn decode_instructions(code: &[u8]) -> Result<Vec<Instruction>> {
112112
assert!(code.len() <= u32::MAX as usize, "bytecode is too big");
113113

114114
let mut pc = 0usize;
115115
let mut steps = Vec::new();
116116

117117
while pc < code.len() {
118118
let op = OpCode::new(code[pc]);
119-
pc += 1;
120-
let immediate_size = op.map(|op| immediate_size(op, &code[pc..])).unwrap_or(0) as usize;
119+
let next_pc = pc + 1;
120+
let immediate_size =
121+
op.map(|op| immediate_size(op, &code[next_pc..])).unwrap_or(0) as usize;
122+
let is_normal_push = op.map(|op| op.is_push()).unwrap_or(false);
121123

122-
if pc + immediate_size > code.len() {
124+
if !is_normal_push && next_pc + immediate_size > code.len() {
123125
eyre::bail!("incomplete sequence of bytecode");
124126
}
125127

126-
steps.push(Instruction { op, pc: pc as u32, immediate: &code[pc..pc + immediate_size] });
128+
// Ensure immediate is padded if needed.
129+
let immediate_end = (next_pc + immediate_size).min(code.len());
130+
let mut immediate = vec![0u8; immediate_size];
131+
let immediate_part = &code[next_pc..immediate_end];
132+
immediate[..immediate_part.len()].copy_from_slice(immediate_part);
133+
134+
steps.push(Instruction { op, pc: pc as u32, immediate: immediate.into_boxed_slice() });
127135

128-
pc += immediate_size;
136+
pc = next_pc + immediate_size;
129137
}
130138

131139
Ok(steps)

0 commit comments

Comments
 (0)