@@ -145,6 +145,27 @@ fn get_region(ctx: &Ctx, ptr: u32) -> CommunicationResult<Region> {
145145 }
146146}
147147
148+ /// Performs plausibility checks in the given Region. Regions are always created by the
149+ /// contract and this can be used to detect problems in the standard library of the contract.
150+ fn validate_region ( region : & Region ) -> CommunicationResult < ( ) > {
151+ if region. offset == 0 {
152+ return Err ( CommunicationError :: zero_address ( ) ) ;
153+ }
154+ if region. length > region. capacity {
155+ return Err ( CommunicationError :: region_length_exceeds_capacity (
156+ region. length ,
157+ region. capacity ,
158+ ) ) ;
159+ }
160+ if region. capacity > ( u32:: MAX - region. offset ) {
161+ return Err ( CommunicationError :: region_out_of_range (
162+ region. offset ,
163+ region. capacity ,
164+ ) ) ;
165+ }
166+ Ok ( ( ) )
167+ }
168+
148169/// Overrides a Region at ptr in wasm memory with data
149170fn set_region ( ctx : & Ctx , ptr : u32 , data : Region ) -> CommunicationResult < ( ) > {
150171 let memory = ctx. memory ( 0 ) ;
@@ -161,3 +182,119 @@ fn set_region(ctx: &Ctx, ptr: u32, data: Region) -> CommunicationResult<()> {
161182 ) ) ,
162183 }
163184}
185+
186+ #[ cfg( test) ]
187+ mod test {
188+ use super :: * ;
189+
190+ #[ test]
191+ fn validate_region_passes_for_valid_region ( ) {
192+ // empty
193+ let region = Region {
194+ offset : 23 ,
195+ capacity : 500 ,
196+ length : 0 ,
197+ } ;
198+ validate_region ( & region) . unwrap ( ) ;
199+
200+ // half full
201+ let region = Region {
202+ offset : 23 ,
203+ capacity : 500 ,
204+ length : 250 ,
205+ } ;
206+ validate_region ( & region) . unwrap ( ) ;
207+
208+ // full
209+ let region = Region {
210+ offset : 23 ,
211+ capacity : 500 ,
212+ length : 500 ,
213+ } ;
214+ validate_region ( & region) . unwrap ( ) ;
215+
216+ // at end of linear memory (1)
217+ let region = Region {
218+ offset : u32:: MAX ,
219+ capacity : 0 ,
220+ length : 0 ,
221+ } ;
222+ validate_region ( & region) . unwrap ( ) ;
223+
224+ // at end of linear memory (2)
225+ let region = Region {
226+ offset : 1 ,
227+ capacity : u32:: MAX - 1 ,
228+ length : 0 ,
229+ } ;
230+ validate_region ( & region) . unwrap ( ) ;
231+ }
232+
233+ #[ test]
234+ fn validate_region_fails_for_zero_offset ( ) {
235+ let region = Region {
236+ offset : 0 ,
237+ capacity : 500 ,
238+ length : 250 ,
239+ } ;
240+ let result = validate_region ( & region) ;
241+ match result. unwrap_err ( ) {
242+ CommunicationError :: ZeroAddress { .. } => { }
243+ e => panic ! ( "Got unexpected error: {:?}" , e) ,
244+ }
245+ }
246+
247+ #[ test]
248+ fn validate_region_fails_for_length_exceeding_capacity ( ) {
249+ let region = Region {
250+ offset : 23 ,
251+ capacity : 500 ,
252+ length : 501 ,
253+ } ;
254+ let result = validate_region ( & region) ;
255+ match result. unwrap_err ( ) {
256+ CommunicationError :: RegionLengthExceedsCapacity {
257+ length, capacity, ..
258+ } => {
259+ assert_eq ! ( length, 501 ) ;
260+ assert_eq ! ( capacity, 500 ) ;
261+ }
262+ e => panic ! ( "Got unexpected error: {:?}" , e) ,
263+ }
264+ }
265+
266+ #[ test]
267+ fn validate_region_fails_when_exceeding_address_space ( ) {
268+ let region = Region {
269+ offset : 23 ,
270+ capacity : u32:: MAX ,
271+ length : 501 ,
272+ } ;
273+ let result = validate_region ( & region) ;
274+ match result. unwrap_err ( ) {
275+ CommunicationError :: RegionOutOfRange {
276+ offset, capacity, ..
277+ } => {
278+ assert_eq ! ( offset, 23 ) ;
279+ assert_eq ! ( capacity, u32 :: MAX ) ;
280+ }
281+ e => panic ! ( "Got unexpected error: {:?}" , e) ,
282+ }
283+
284+ let region = Region {
285+ offset : u32:: MAX ,
286+ capacity : 1 ,
287+ length : 0 ,
288+ } ;
289+ let result = validate_region ( & region) ;
290+ match result. unwrap_err ( ) {
291+ CommunicationError :: RegionOutOfRange {
292+ offset, capacity, ..
293+ } => {
294+ assert_eq ! ( offset, u32 :: MAX ) ;
295+ assert_eq ! ( capacity, 1 ) ;
296+ }
297+ e => panic ! ( "Got unexpected error: {:?}" , e) ,
298+ }
299+ }
300+ }
0 commit comments