Skip to content

Commit b800758

Browse files
committed
Backport #450
1 parent fd22e30 commit b800758

File tree

19 files changed

+244
-124
lines changed

19 files changed

+244
-124
lines changed

.github/workflows/develop.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
ln -snf .. ckb-vm-test-suite/ckb-vm
7070
docker run --rm -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20210804 cp -r /riscv /code/riscv
7171
cd ckb-vm-test-suite
72-
git checkout 441e0f2149c097ccad133b040544dca13caeb01e
72+
git checkout 898edc351eeb4de974ca4f0ff8d1e4943a95aecb
7373
git submodule update --init --recursive
7474
RISCV=`pwd`/../riscv ./test.sh
7575
@@ -136,13 +136,13 @@ jobs:
136136
ln -snf .. ckb-vm-test-suite/ckb-vm
137137
docker run --rm -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20210804 cp -r /riscv /code/riscv
138138
cd ckb-vm-test-suite
139-
git checkout 441e0f2149c097ccad133b040544dca13caeb01e
139+
git checkout 898edc351eeb4de974ca4f0ff8d1e4943a95aecb
140140
git submodule update --init --recursive
141141
RISCV=`pwd`/../riscv ./test.sh --build-only
142142
cd ..
143143
- name: Run test suite
144144
run: |
145-
sudo apt install -y qemu binfmt-support qemu-user-static
145+
sudo apt install -y qemu-system binfmt-support qemu-user-static
146146
sudo apt install -y gcc-multilib
147147
sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu clang
148148
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

benches/vm_benchmark.rs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ use std::fs;
1717
fn interpret_benchmark(c: &mut Criterion) {
1818
c.bench_function("interpret secp256k1_bench", |b| {
1919
let buffer = fs::read("benches/data/secp256k1_bench").unwrap().into();
20-
let args: Vec<Bytes> = vec!["secp256k1_bench",
21-
"033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f",
22-
"304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3",
23-
"foo",
24-
"bar"].into_iter().map(|a| a.into()).collect();
25-
20+
let args: Vec<Bytes> = vec![
21+
"secp256k1_bench",
22+
"033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f",
23+
"304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3",
24+
"foo",
25+
"bar"
26+
].into_iter().map(|a| a.into()).collect();
2627
b.iter(|| run::<u64, SparseMemory<u64>>(&buffer, &args[..], RISCV_MAX_MEMORY).unwrap());
2728
});
2829
}
@@ -31,17 +32,18 @@ fn interpret_benchmark(c: &mut Criterion) {
3132
fn asm_benchmark(c: &mut Criterion) {
3233
c.bench_function("interpret secp256k1_bench via assembly", |b| {
3334
let buffer = fs::read("benches/data/secp256k1_bench").unwrap().into();
34-
let args: Vec<Bytes> = vec!["secp256k1_bench",
35-
"033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f",
36-
"304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3",
37-
"foo",
38-
"bar"].into_iter().map(|a| a.into()).collect();
39-
35+
let args = [
36+
"secp256k1_bench",
37+
"033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f",
38+
"304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3",
39+
"foo",
40+
"bar",
41+
].into_iter().map(|a| Ok(a.into()));
4042
b.iter(|| {
4143
let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::max_value());
4244
let core = DefaultMachineBuilder::new(asm_core).build();
4345
let mut machine = AsmMachine::new(core);
44-
machine.load_program(&buffer, &args[..]).unwrap();
46+
machine.load_program(&buffer, args.clone()).unwrap();
4547
machine.run().unwrap()
4648
});
4749
});
@@ -51,17 +53,19 @@ fn asm_benchmark(c: &mut Criterion) {
5153
fn mop_benchmark(c: &mut Criterion) {
5254
c.bench_function("interpret secp256k1_bench via assembly mop", |b| {
5355
let buffer = fs::read("benches/data/secp256k1_bench").unwrap().into();
54-
let args: Vec<Bytes> = vec!["secp256k1_bench",
55-
"033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f",
56-
"304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3",
57-
"foo",
58-
"bar"].into_iter().map(|a| a.into()).collect();
56+
let args = [
57+
"secp256k1_bench",
58+
"033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f",
59+
"304402203679d909f43f073c7c1dcf8468a485090589079ee834e6eed92fea9b09b06a2402201e46f1075afa18f306715e7db87493e7b7e779569aa13c64ab3d09980b3560a3",
60+
"foo",
61+
"bar",
62+
].into_iter().map(|a| Ok(a.into()));
5963
b.iter(|| {
6064
let asm_core = AsmCoreMachine::new(ISA_IMC | ISA_B | ISA_MOP, VERSION2, u64::max_value());
6165
let core = DefaultMachineBuilder::<Box<AsmCoreMachine>>::new(asm_core)
6266
.build();
6367
let mut machine = AsmMachine::new(core);
64-
machine.load_program(&buffer, &args).unwrap();
68+
machine.load_program(&buffer, args.clone()).unwrap();
6569
machine.run().unwrap()
6670
});
6771
});

examples/check_real_memory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ fn check_asm(memory_size: usize) -> Result<(), ()> {
173173
let core = DefaultMachineBuilder::new(asm_core).build();
174174
let mut machine = AsmMachine::new(core);
175175
machine
176-
.load_program(&BIN_PATH_BUFFER, &vec![BIN_NAME.clone().into()])
176+
.load_program(&BIN_PATH_BUFFER, [Ok(BIN_NAME.clone().into())].into_iter())
177177
.unwrap();
178178
let result = machine.run();
179179
assert!(result.is_ok());
@@ -198,7 +198,7 @@ fn check_asm_in_thread(memory_size: usize) -> Result<(), ()> {
198198
let core = DefaultMachineBuilder::new(asm_core).build();
199199
let mut machine = AsmMachine::new(core);
200200
machine
201-
.load_program(&BIN_PATH_BUFFER, &vec![BIN_NAME.clone().into()])
201+
.load_program(&BIN_PATH_BUFFER, [Ok(BIN_NAME.clone().into())].into_iter())
202202
.unwrap();
203203
let thread_join_handle = thread::spawn(move || {
204204
let result = machine.run();

examples/ckb-vm-runner.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ fn main_asm(code: Bytes, args: Vec<Bytes>) -> Result<(), Box<dyn std::error::Err
4949
.syscall(Box::new(DebugSyscall {}))
5050
.build();
5151
let mut machine = ckb_vm::machine::asm::AsmMachine::new(core);
52-
machine.load_program(&code, &args)?;
52+
machine.load_program(&code, args.into_iter().map(Ok))?;
5353
let exit = machine.run();
5454
let cycles = machine.machine.cycles();
5555
println!(
@@ -71,7 +71,7 @@ fn main_int(code: Bytes, args: Vec<Bytes>) -> Result<(), Box<dyn std::error::Err
7171
let machine_builder = ckb_vm::DefaultMachineBuilder::new(core_machine)
7272
.instruction_cycle_func(Box::new(estimate_cycles));
7373
let mut machine = machine_builder.syscall(Box::new(DebugSyscall {})).build();
74-
machine.load_program(&code, &args)?;
74+
machine.load_program(&code, args.into_iter().map(Ok))?;
7575
let exit = machine.run();
7676
let cycles = machine.cycles();
7777
println!(

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub use crate::{
2222
instructions::{Instruction, Register},
2323
machine::{
2424
trace::TraceMachine, CoreMachine, DefaultCoreMachine, DefaultMachine,
25-
DefaultMachineBuilder, InstructionCycleFunc, Machine, SupportMachine,
25+
DefaultMachineBuilder, FlattenedArgsReader, InstructionCycleFunc, Machine, SupportMachine,
2626
},
2727
memory::{flat::FlatMemory, sparse::SparseMemory, wxorx::WXorXMemory, Memory},
2828
syscalls::Syscalls,
@@ -49,7 +49,7 @@ pub fn run<R: Register, M: Memory<REG = R>>(
4949
memory_size,
5050
);
5151
let mut machine = TraceMachine::new(DefaultMachineBuilder::new(core_machine).build());
52-
machine.load_program(program, args)?;
52+
machine.load_program(program, args.iter().map(|e| Ok(e.clone())))?;
5353
machine.run()
5454
}
5555

src/machine/asm/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,15 +482,19 @@ impl AsmMachine {
482482
self.machine.inner.max_cycles = cycles;
483483
}
484484

485-
pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result<u64, Error> {
485+
pub fn load_program(
486+
&mut self,
487+
program: &Bytes,
488+
args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
489+
) -> Result<u64, Error> {
486490
self.machine.load_program(program, args)
487491
}
488492

489493
pub fn load_program_with_metadata(
490494
&mut self,
491495
program: &Bytes,
492496
metadata: &ProgramMetadata,
493-
args: &[Bytes],
497+
args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
494498
) -> Result<u64, Error> {
495499
self.machine
496500
.load_program_with_metadata(program, metadata, args)

src/machine/mod.rs

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use super::debugger::Debugger;
1212
use super::decoder::{build_decoder, Decoder};
1313
use super::elf::{parse_elf, LoadingAction, ProgramMetadata};
1414
use super::instructions::{execute, Instruction, Register};
15-
use super::memory::Memory;
15+
use super::memory::{load_c_string_byte_by_byte, Memory};
1616
use super::syscalls::Syscalls;
1717
use super::{
1818
registers::{A0, A7, REGISTER_ABI_NAMES, SP},
@@ -171,7 +171,7 @@ pub trait SupportMachine: CoreMachine {
171171

172172
fn initialize_stack(
173173
&mut self,
174-
args: &[Bytes],
174+
args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
175175
stack_start: u64,
176176
stack_size: u64,
177177
) -> Result<u64, Error> {
@@ -183,7 +183,7 @@ pub trait SupportMachine: CoreMachine {
183183
// reading "argc" will return an unexpected data. This situation is not very common.
184184
//
185185
// See https://github.com/nervosnetwork/ckb-vm/issues/106 for more details.
186-
if self.version() >= VERSION1 && args.is_empty() {
186+
if self.version() >= VERSION1 && args.len() == 0 {
187187
let argc_size = u64::from(Self::REG::BITS / 8);
188188
let origin_sp = stack_start + stack_size;
189189
let unaligned_sp_address = origin_sp - argc_size;
@@ -200,15 +200,21 @@ pub trait SupportMachine: CoreMachine {
200200
// of each argv object.
201201
let mut values = vec![Self::REG::from_u64(args.len() as u64)];
202202
for arg in args {
203+
let arg = arg?;
203204
let len = Self::REG::from_u64(arg.len() as u64 + 1);
204205
let address = self.registers()[SP].overflowing_sub(&len);
205206

206-
self.memory_mut().store_bytes(address.to_u64(), arg)?;
207+
self.memory_mut().store_bytes(address.to_u64(), &arg)?;
207208
self.memory_mut()
208209
.store_byte(address.to_u64() + arg.len() as u64, 1, 0)?;
209210

210211
values.push(address.clone());
211-
self.set_register(SP, address);
212+
self.set_register(SP, address.clone());
213+
214+
if self.version() >= VERSION2 && address.to_u64() < stack_start {
215+
// Provides an early exit to large argv array.
216+
return Err(Error::MemOutOfStack);
217+
}
212218
}
213219
if self.version() >= VERSION1 {
214220
// There are 2 standard requirements of the initialized stack:
@@ -246,7 +252,7 @@ pub trait SupportMachine: CoreMachine {
246252
self.set_register(SP, address);
247253
}
248254
if self.registers()[SP].to_u64() < stack_start {
249-
// args exceed stack size
255+
// Args exceed stack size.
250256
return Err(Error::MemOutOfStack);
251257
}
252258
Ok(stack_start + stack_size - self.registers()[SP].to_u64())
@@ -572,7 +578,11 @@ impl<Inner: CoreMachine> Display for DefaultMachine<Inner> {
572578
}
573579

574580
impl<Inner: SupportMachine> DefaultMachine<Inner> {
575-
pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result<u64, Error> {
581+
pub fn load_program(
582+
&mut self,
583+
program: &Bytes,
584+
args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
585+
) -> Result<u64, Error> {
576586
let elf_bytes = self.load_elf(program, true)?;
577587
let stack_bytes = self.initialize(args)?;
578588
let bytes = elf_bytes.checked_add(stack_bytes).ok_or_else(|| {
@@ -587,7 +597,7 @@ impl<Inner: SupportMachine> DefaultMachine<Inner> {
587597
&mut self,
588598
program: &Bytes,
589599
metadata: &ProgramMetadata,
590-
args: &[Bytes],
600+
args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
591601
) -> Result<u64, Error> {
592602
let elf_bytes = self.load_binary(program, metadata, true)?;
593603
let stack_bytes = self.initialize(args)?;
@@ -599,7 +609,10 @@ impl<Inner: SupportMachine> DefaultMachine<Inner> {
599609
Ok(bytes)
600610
}
601611

602-
fn initialize(&mut self, args: &[Bytes]) -> Result<u64, Error> {
612+
fn initialize(
613+
&mut self,
614+
args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
615+
) -> Result<u64, Error> {
603616
for syscall in &mut self.syscalls {
604617
syscall.initialize(&mut self.inner)?;
605618
}
@@ -759,6 +772,55 @@ impl Pause {
759772
}
760773
}
761774

775+
pub struct FlattenedArgsReader<'a, M: Memory> {
776+
memory: &'a mut M,
777+
argc: M::REG,
778+
argv: M::REG,
779+
cidx: M::REG,
780+
}
781+
impl<'a, M: Memory> FlattenedArgsReader<'a, M> {
782+
pub fn new(memory: &'a mut M, argc: M::REG, argv: M::REG) -> Self {
783+
Self {
784+
memory,
785+
argc,
786+
argv,
787+
cidx: M::REG::zero(),
788+
}
789+
}
790+
}
791+
impl<'a, M: Memory> Iterator for FlattenedArgsReader<'a, M> {
792+
type Item = Result<Bytes, Error>;
793+
fn next(&mut self) -> Option<Self::Item> {
794+
if self.cidx.ge(&self.argc).to_u8() == 1 {
795+
return None;
796+
}
797+
let addr = match M::REG::BITS {
798+
32 => self.memory.load32(&self.argv),
799+
64 => self.memory.load64(&self.argv),
800+
_ => unreachable!(),
801+
};
802+
if let Err(err) = addr {
803+
return Some(Err(err));
804+
};
805+
let addr = addr.unwrap();
806+
let cstr = load_c_string_byte_by_byte(self.memory, &addr);
807+
if let Err(err) = cstr {
808+
return Some(Err(err));
809+
};
810+
let cstr = cstr.unwrap();
811+
self.cidx = self.cidx.overflowing_add(&M::REG::from_u8(1));
812+
self.argv = self
813+
.argv
814+
.overflowing_add(&M::REG::from_u8(M::REG::BITS / 8));
815+
Some(Ok(cstr))
816+
}
817+
}
818+
impl<'a, M: Memory> ExactSizeIterator for FlattenedArgsReader<'a, M> {
819+
fn len(&self) -> usize {
820+
self.argc.to_u64() as usize
821+
}
822+
}
823+
762824
#[cfg(test)]
763825
mod tests {
764826
use std::sync::atomic::AtomicU8;

src/machine/trace.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,19 @@ impl<Inner: SupportMachine> TraceMachine<Inner> {
113113
}
114114
}
115115

116-
pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result<u64, Error> {
116+
pub fn load_program(
117+
&mut self,
118+
program: &Bytes,
119+
args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
120+
) -> Result<u64, Error> {
117121
self.machine.load_program(program, args)
118122
}
119123

120124
pub fn load_program_with_metadata(
121125
&mut self,
122126
program: &Bytes,
123127
metadata: &ProgramMetadata,
124-
args: &[Bytes],
128+
args: impl ExactSizeIterator<Item = Result<Bytes, Error>>,
125129
) -> Result<u64, Error> {
126130
self.machine
127131
.load_program_with_metadata(program, metadata, args)

src/memory/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,20 @@ pub fn memset(slice: &mut [u8], value: u8) {
144144
ptr::write_bytes(p, value, slice.len());
145145
}
146146
}
147+
148+
pub fn load_c_string_byte_by_byte<M: Memory>(
149+
memory: &mut M,
150+
addr: &M::REG,
151+
) -> Result<Bytes, Error> {
152+
let mut buffer = Vec::new();
153+
let mut addr = addr.clone();
154+
loop {
155+
let byte = memory.load8(&addr)?.to_u8();
156+
if byte == 0 {
157+
break;
158+
}
159+
buffer.push(byte);
160+
addr = addr.overflowing_add(&M::REG::from_u8(1));
161+
}
162+
Ok(Bytes::from(buffer))
163+
}

0 commit comments

Comments
 (0)