@@ -36,12 +36,13 @@ public enum BranchType
36
36
OK , // One of the branches may return without exception
37
37
THROW , // All branches surely has exceptions, but can be catched
38
38
ABORT , // All branches abort, and cannot be catched
39
+ UNCOVERED ,
39
40
}
40
41
41
42
[ Strategy ( Priority = int . MaxValue ) ]
42
43
public static ( NefFile , ContractManifest , JObject ) RemoveUncoveredInstructions ( NefFile nef , ContractManifest manifest , JObject debugInfo )
43
44
{
44
- Dictionary < int , bool > coveredMap = FindCoveredInstructions ( nef , manifest , debugInfo ) ;
45
+ Dictionary < int , BranchType > coveredMap = FindCoveredInstructions ( nef , manifest , debugInfo ) ;
45
46
Script oldScript = nef . Script ;
46
47
List < ( int , Instruction ) > oldAddressAndInstructionsList = oldScript . EnumerateInstructions ( ) . ToList ( ) ;
47
48
Dictionary < int , Instruction > oldAddressToInstruction = new ( ) ;
@@ -53,7 +54,7 @@ public static (NefFile, ContractManifest, JObject) RemoveUncoveredInstructions(N
53
54
int currentAddress = 0 ;
54
55
foreach ( ( int a , Instruction i ) in oldAddressAndInstructionsList )
55
56
{
56
- if ( coveredMap [ a ] )
57
+ if ( coveredMap [ a ] != BranchType . UNCOVERED )
57
58
{
58
59
simplifiedInstructionsToAddress . Add ( i , currentAddress ) ;
59
60
currentAddress += i . Size ;
@@ -160,13 +161,13 @@ public static (NefFile, ContractManifest, JObject) RemoveUncoveredInstructions(N
160
161
return ( nef , manifest , debugInfo ) ;
161
162
}
162
163
163
- public static Dictionary < int , bool >
164
+ public static Dictionary < int , BranchType >
164
165
FindCoveredInstructions ( NefFile nef , ContractManifest manifest , JToken debugInfo )
165
166
{
166
167
Script script = nef . Script ;
167
- Dictionary < int , bool > coveredMap = new ( ) ;
168
+ Dictionary < int , BranchType > coveredMap = new ( ) ;
168
169
foreach ( ( int addr , Instruction _ ) in script . EnumerateInstructions ( ) )
169
- coveredMap . Add ( addr , false ) ;
170
+ coveredMap . Add ( addr , BranchType . UNCOVERED ) ;
170
171
171
172
Dictionary < int , string > publicMethodStartingAddressToName = new ( ) ;
172
173
foreach ( ContractMethodDescriptor method in manifest . Abi . Methods )
@@ -201,8 +202,9 @@ public static Dictionary<int, bool>
201
202
/// <returns>Whether it is possible to return without exception</returns>
202
203
/// <exception cref="BadScriptException"></exception>
203
204
/// <exception cref="NotImplementedException"></exception>
204
- public static BranchType CoverInstruction ( int addr , Script script , Dictionary < int , bool > coveredMap , Stack < ( ( int returnAddr , int finallyAddr ) , TryStack stackType ) > ? stack = null , bool throwed = false )
205
+ public static BranchType CoverInstruction ( int addr , Script script , Dictionary < int , BranchType > coveredMap , Stack < ( ( int returnAddr , int finallyAddr ) , TryStack stackType ) > ? stack = null , bool throwed = false )
205
206
{
207
+ int entranceAddr = addr ;
206
208
stack ??= new ( ) ;
207
209
if ( stack . Count == 0 )
208
210
stack . Push ( ( ( - 1 , - 1 ) , TryStack . ENTRY ) ) ;
@@ -244,25 +246,32 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
244
246
HANDLE_NORMAL_CASE :
245
247
if ( ! coveredMap . ContainsKey ( addr ) )
246
248
throw new BadScriptException ( $ "wrong address { addr } ") ;
247
- if ( coveredMap [ addr ] )
249
+ if ( coveredMap [ addr ] != BranchType . UNCOVERED )
248
250
// We have visited the code. Skip it.
249
- return BranchType . OK ;
251
+ return coveredMap [ addr ] ;
250
252
Instruction instruction = script . GetInstruction ( addr ) ;
251
253
if ( instruction . OpCode != OpCode . NOP )
252
- coveredMap [ addr ] = true ;
254
+ coveredMap [ addr ] = BranchType . OK ;
253
255
254
256
// TODO: ABORTMSG may THROW instead of ABORT. Just throw new NotImplementedException for ABORTMSG?
255
257
if ( instruction . OpCode == OpCode . ABORT || instruction . OpCode == OpCode . ABORTMSG )
256
258
{
257
259
// See if we are in a try. There may still be runtime exceptions
258
260
( ( catchAddr , finallyAddr ) , stackType ) = stack . Peek ( ) ;
259
261
if ( stackType == TryStack . TRY && catchAddr != - 1 )
262
+ {
260
263
// Visit catchAddr because there may still be exceptions at runtime
261
- return CoverInstruction ( catchAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
264
+ coveredMap [ entranceAddr ] = CoverInstruction ( catchAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
265
+ return coveredMap [ entranceAddr ] ;
266
+ }
262
267
if ( stackType == TryStack . CATCH && finallyAddr != - 1 )
268
+ {
263
269
// Visit finallyAddr because there may still be exceptions at runtime
264
- return CoverInstruction ( finallyAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
265
- return BranchType . ABORT ;
270
+ coveredMap [ entranceAddr ] = CoverInstruction ( finallyAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
271
+ return coveredMap [ entranceAddr ] ;
272
+ }
273
+ coveredMap [ entranceAddr ] = BranchType . ABORT ;
274
+ return coveredMap [ entranceAddr ] ;
266
275
}
267
276
if ( callWithJump . Contains ( instruction . OpCode ) )
268
277
{
@@ -278,12 +287,19 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
278
287
// See if we are in a try. There may still be runtime exceptions
279
288
( ( catchAddr , finallyAddr ) , stackType ) = stack . Peek ( ) ;
280
289
if ( stackType == TryStack . TRY && catchAddr != - 1 )
290
+ {
281
291
// Visit catchAddr because there may still be exceptions at runtime
282
- return CoverInstruction ( catchAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
292
+ coveredMap [ entranceAddr ] = CoverInstruction ( catchAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
293
+ return coveredMap [ entranceAddr ] ;
294
+ }
283
295
if ( stackType == TryStack . CATCH && finallyAddr != - 1 )
296
+ {
284
297
// Visit finallyAddr because there may still be exceptions at runtime
285
- return CoverInstruction ( finallyAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
286
- return BranchType . ABORT ;
298
+ coveredMap [ entranceAddr ] = CoverInstruction ( finallyAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
299
+ return coveredMap [ entranceAddr ] ;
300
+ }
301
+ coveredMap [ entranceAddr ] = BranchType . ABORT ;
302
+ return coveredMap [ entranceAddr ] ;
287
303
}
288
304
if ( returnedType == BranchType . THROW )
289
305
goto HANDLE_THROW ;
@@ -298,7 +314,8 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
298
314
if ( stackType == TryStack . CATCH && finallyAddr != - 1 )
299
315
// Visit finallyAddr because there may still be exceptions at runtime
300
316
CoverInstruction ( finallyAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
301
- return BranchType . OK ;
317
+ coveredMap [ entranceAddr ] = BranchType . OK ;
318
+ return coveredMap [ entranceAddr ] ;
302
319
}
303
320
if ( tryThrowFinally . Contains ( instruction . OpCode ) )
304
321
{
@@ -373,19 +390,27 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
373
390
if ( stackType == TryStack . CATCH && finallyAddr != - 1 )
374
391
// Visit finallyAddr because there may still be exceptions at runtime
375
392
CoverInstruction ( finallyAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
376
- return BranchType . OK ;
393
+ coveredMap [ entranceAddr ] = BranchType . OK ;
394
+ return coveredMap [ entranceAddr ] ;
377
395
}
378
396
if ( noJump == BranchType . ABORT && jump == BranchType . ABORT )
379
397
{
380
398
// See if we are in a try. There may still be runtime exceptions
381
399
( ( catchAddr , finallyAddr ) , stackType ) = stack . Peek ( ) ;
382
400
if ( stackType == TryStack . TRY && catchAddr != - 1 )
401
+ {
383
402
// Visit catchAddr because there may still be exceptions at runtime
384
- return CoverInstruction ( catchAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
403
+ coveredMap [ entranceAddr ] = CoverInstruction ( catchAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
404
+ return coveredMap [ entranceAddr ] ;
405
+ }
385
406
if ( stackType == TryStack . CATCH && finallyAddr != - 1 )
407
+ {
386
408
// Visit finallyAddr because there may still be exceptions at runtime
387
- return CoverInstruction ( finallyAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
388
- return BranchType . ABORT ;
409
+ coveredMap [ entranceAddr ] = CoverInstruction ( finallyAddr , script , coveredMap , stack : new ( stack . Reverse ( ) ) , throwed : true ) ;
410
+ return coveredMap [ entranceAddr ] ;
411
+ }
412
+ coveredMap [ entranceAddr ] = BranchType . ABORT ;
413
+ return coveredMap [ entranceAddr ] ;
389
414
}
390
415
if ( noJump == BranchType . THROW || jump == BranchType . THROW ) // THROW, ABORT => THROW
391
416
goto HANDLE_THROW ;
@@ -394,7 +419,8 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
394
419
395
420
addr += instruction . Size ;
396
421
}
397
- return throwed ? BranchType . THROW : BranchType . OK ;
422
+ coveredMap [ entranceAddr ] = throwed ? BranchType . THROW : BranchType . OK ;
423
+ return coveredMap [ entranceAddr ] ;
398
424
}
399
425
}
400
426
}
0 commit comments