@@ -6,7 +6,6 @@ use fvm_shared::address::Address;
6
6
use fvm_shared:: error:: ErrorNumber ;
7
7
8
8
use crate :: kernel:: { ClassifyResult , Context as _, Result } ;
9
- use crate :: syscalls:: MAX_CID_LEN ;
10
9
11
10
pub struct Context < ' a , K > {
12
11
pub kernel : & ' a mut K ,
@@ -52,9 +51,22 @@ impl Memory {
52
51
}
53
52
54
53
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" )
58
70
}
59
71
60
72
pub fn read_address ( & self , offset : u32 , len : u32 ) -> Result < Address > {
@@ -67,3 +79,75 @@ impl Memory {
67
79
from_slice ( bytes) . or_error ( ErrorNumber :: IllegalArgument )
68
80
}
69
81
}
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