@@ -6,7 +6,6 @@ use fvm_shared::address::Address;
66use fvm_shared:: error:: ErrorNumber ;
77
88use crate :: kernel:: { ClassifyResult , Context as _, Result } ;
9- use crate :: syscalls:: MAX_CID_LEN ;
109
1110pub struct Context < ' a , K > {
1211 pub kernel : & ' a mut K ,
@@ -52,9 +51,22 @@ impl Memory {
5251 }
5352
5453 pub fn read_cid ( & self , offset : u32 ) -> Result < Cid > {
55- Cid :: read_bytes ( self . try_slice ( offset, MAX_CID_LEN as u32 ) ?)
56- . or_error ( ErrorNumber :: IllegalArgument )
57- . context ( "failed to parse CID" )
54+ // NOTE: Be very careful when changing this code.
55+ //
56+ // We intentionally read the CID till the end of memory. We intentionally do not "slice"
57+ // with a fixed end.
58+ // - We _can't_ slice MAX_CID_LEN because there may not be MAX_CID_LEN addressable memory
59+ // after the offset.
60+ // - We can safely read from an "arbitrary" sized slice because `Cid::read_bytes` will never
61+ // read more than 4 u64 varints and 64 bytes of digest.
62+ Cid :: read_bytes (
63+ self . 0
64+ . get ( offset as usize ..)
65+ . ok_or_else ( || format ! ( "cid at offset {} is out of bounds" , offset) )
66+ . or_error ( ErrorNumber :: IllegalArgument ) ?,
67+ )
68+ . or_error ( ErrorNumber :: IllegalArgument )
69+ . context ( "failed to parse cid" )
5870 }
5971
6072 pub fn read_address ( & self , offset : u32 , len : u32 ) -> Result < Address > {
@@ -67,3 +79,75 @@ impl Memory {
6779 from_slice ( bytes) . or_error ( ErrorNumber :: IllegalArgument )
6880 }
6981}
82+
83+ #[ cfg( test) ]
84+ mod test {
85+ use cid:: multihash:: MultihashDigest ;
86+
87+ use super :: * ;
88+
89+ // TODO: move this somewhere more useful.
90+ macro_rules! expect_syscall_err {
91+ ( $code: ident, $res: expr) => {
92+ match $res. expect_err( "expected syscall to fail" ) {
93+ $crate:: kernel:: ExecutionError :: Syscall ( $crate:: kernel:: SyscallError (
94+ _,
95+ fvm_shared:: error:: ErrorNumber :: $code,
96+ ) ) => { }
97+ $crate:: kernel:: ExecutionError :: Syscall ( $crate:: kernel:: SyscallError (
98+ msg,
99+ code,
100+ ) ) => {
101+ panic!(
102+ "expected {}, got {}: {}" ,
103+ fvm_shared:: error:: ErrorNumber :: $code,
104+ code,
105+ msg
106+ )
107+ }
108+ $crate:: kernel:: ExecutionError :: Fatal ( err) => {
109+ panic!( "got unexpected fatal error: {}" , err)
110+ }
111+ $crate:: kernel:: ExecutionError :: OutOfGas => {
112+ panic!( "got unexpected out of gas" )
113+ }
114+ }
115+ } ;
116+ }
117+
118+ #[ test]
119+ fn test_read_cid ( ) {
120+ let k = Cid :: new_v1 ( 0x55 , cid:: multihash:: Code :: Sha2_256 . digest ( b"foo" ) ) ;
121+ let mut k_bytes = k. to_bytes ( ) ;
122+ let mem = Memory :: new ( & mut k_bytes) ;
123+ let k2 = mem. read_cid ( 0 ) . expect ( "failed to read cid" ) ;
124+ assert_eq ! ( k, k2) ;
125+ }
126+
127+ #[ test]
128+ fn test_read_cid_truncated ( ) {
129+ let k = Cid :: new_v1 ( 0x55 , cid:: multihash:: Code :: Sha2_256 . digest ( b"foo" ) ) ;
130+ let mut k_bytes = k. to_bytes ( ) ;
131+ let mem = Memory :: new ( & mut k_bytes[ ..20 ] ) ;
132+ expect_syscall_err ! ( IllegalArgument , mem. read_cid( 0 ) ) ;
133+ }
134+
135+ #[ test]
136+ fn test_read_cid_out_of_bounds ( ) {
137+ let mem = Memory :: new ( & mut [ ] ) ;
138+ expect_syscall_err ! ( IllegalArgument , mem. read_cid( 200 ) ) ;
139+ }
140+
141+ #[ test]
142+ fn test_read_slice_out_of_bounds ( ) {
143+ let mem = Memory :: new ( & mut [ ] ) ;
144+ expect_syscall_err ! ( IllegalArgument , mem. try_slice( 10 , 0 ) ) ;
145+ expect_syscall_err ! ( IllegalArgument , mem. try_slice( u32 :: MAX , 0 ) ) ;
146+ }
147+
148+ #[ test]
149+ fn test_read_slice_empty ( ) {
150+ let mem = Memory :: new ( & mut [ ] ) ;
151+ mem. try_slice ( 0 , 0 ) . expect ( "slice was in bounds" ) ;
152+ }
153+ }
0 commit comments