Skip to content

Commit ca8cf39

Browse files
committed
Fixing counting algo
1 parent 0272a72 commit ca8cf39

File tree

3 files changed

+112
-166
lines changed

3 files changed

+112
-166
lines changed

scripts/python/examine_statistics.py

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@ def calculate_statistics(file_path):
55

66
total_opcodes = 0
77
total_jumps = 0
8-
solved_jumps = 0
9-
definitely_unreachable_jumps = 0
10-
maybe_unreachable_jumps = 0
11-
total_solved_jumps = 0
12-
unsound_jumps = 0
13-
maybe_unsound_jumps = 0
14-
total_solved_percent = 0
8+
resolved_jumps = 0
9+
unknown_jumps = 0
10+
unreachable_jumps = 0
11+
erroneous_jumps = 0
12+
edges = 0
1513
time_millis = 0
1614
rows = 0
1715

@@ -22,56 +20,42 @@ def calculate_statistics(file_path):
2220

2321
total_opcodes_index = header.index(" Total Opcodes")
2422
total_jumps_index = header.index(" Total Jumps")
25-
solved_jumps_index = header.index(" Solved Jumps")
26-
definitely_unreachable_jumps_index = header.index(" Definitely unreachable jumps")
27-
maybe_unreachable_jumps_index = header.index(" Maybe unreachable jumps")
28-
total_solved_jumps_index = header.index(" Total solved Jumps")
29-
unsound_jumps_index = header.index(" Unsound jumps")
30-
maybe_unsound_jumps_index = header.index(" Maybe unsound jumps")
31-
total_solved_percent_index = header.index(" % Total Solved")
23+
resolved_jumps_index = header.index(" Resolved Jumps")
24+
unknown_jumps_index = header.index(" Unknown jumps")
25+
unreachable_jumps_index = header.index(" Unreachable jumps")
26+
erroneous_jumps_index = header.index(" Erroneous Jumps")
27+
edges_index = header.index(" Edges")
3228
time_millis_index = header.index(" Time (millis)")
33-
sound = 0
3429

3530
for row in reader:
36-
if int(row[maybe_unreachable_jumps_index]) == 0 and int(row[maybe_unsound_jumps_index]) == 0 and int(row[unsound_jumps_index]) == 0:
37-
sound += 1
38-
# print(row[header.index("Smart Contract")])
39-
4031
rows += 1
4132
total_opcodes += int(row[total_opcodes_index])
4233
total_jumps += int(row[total_jumps_index])
43-
solved_jumps += int(row[solved_jumps_index])
44-
definitely_unreachable_jumps += int(row[definitely_unreachable_jumps_index])
45-
maybe_unreachable_jumps += int(row[maybe_unreachable_jumps_index])
46-
total_solved_jumps += int(row[total_solved_jumps_index])
47-
unsound_jumps += int(row[unsound_jumps_index])
48-
maybe_unsound_jumps += int(row[maybe_unsound_jumps_index])
49-
total_solved_percent += float(row[total_solved_percent_index])
34+
resolved_jumps += int(row[resolved_jumps_index])
35+
unknown_jumps += int(row[unknown_jumps_index])
36+
unreachable_jumps += int(row[unreachable_jumps_index])
37+
erroneous_jumps += int(row[erroneous_jumps_index])
38+
edges += int(row[edges_index])
5039
time_millis += int(row[time_millis_index])
5140

52-
53-
avg_total_solved_percent = total_solved_percent / rows if rows else None
5441
avg_time_millis = time_millis / rows if rows else None
55-
avg_unsolved = unsound_jumps / total_jumps
42+
classified = resolved_jumps + unknown_jumps + unreachable_jumps + erroneous_jumps
5643

5744
print(f"Smart contracts examined: {rows}")
58-
print(f"Smart contracts sound: {sound}")
5945
print(f"Total Opcodes: {total_opcodes}")
6046
print(f"Total Jumps: {total_jumps}")
61-
print(f"Solved (reachable) Jumps: {solved_jumps}")
62-
print(f"Total solved Jumps: {total_solved_jumps}")
63-
print(f"Definitely unreachable jumps: {definitely_unreachable_jumps}")
64-
print(f"Maybe unreachable jumps: {maybe_unreachable_jumps}")
65-
print(f"Unsound jumps: {unsound_jumps}")
66-
print(f"Maybe unsound jumps: {maybe_unsound_jumps}")
67-
print(f"Average % Total unsolved: {percentuale(avg_unsolved)}")
68-
print(f"Average % Total Solved: {percentuale(1 - avg_unsolved)}")
47+
print(f"Resolved Jumps: {resolved_jumps} ({percentuale(resolved_jumps,total_jumps)}%)")
48+
print(f"Unknown jumps: {unknown_jumps} ({percentuale(unknown_jumps,total_jumps)}%)")
49+
print(f"Unreachable jumps: {unreachable_jumps} ({percentuale(unreachable_jumps,total_jumps)}%)")
50+
print(f"Erroneous jumps: {erroneous_jumps} ({percentuale(erroneous_jumps,total_jumps)}%)")
51+
print(f"Total jumps with classification: {classified} ({'match' if classified == total_jumps else 'mismatch'})")
52+
print(f"Edges: {edges}")
6953
print(f"Average Time (seconds): {avg_time_millis / 1000}")
7054

71-
def percentuale(numero_decimale):
72-
if numero_decimale is None:
55+
def percentuale(num, den):
56+
if num is None or den is None or den == 0:
7357
return "N/A"
74-
percentuale_str = "{:.4f}%".format(numero_decimale * 100)
58+
percentuale_str = "{:.4f}%".format((num/den) * 100)
7559
return percentuale_str
7660

7761
if __name__ == "__main__":

src/main/java/it/unipr/EVMLiSA.java

Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -650,75 +650,59 @@ public static MyLogger dumpStatistics(JumpSolver checker, Set<Statement> soundly
650650

651651
log.info("### Calculating statistics ###");
652652

653-
Set<Statement> unreachableJumpNodes = checker.getUnreachableJumps(); // LN: BOTTOM
654-
655-
int resolved = 0; // LN: RESOLVED
656-
int unreachable = 0; // LN: UNREACHABLE
657-
int bottom = unreachableJumpNodes.size(); // LN: BOTTOM
658-
int conservative = 0; // LN: CONSERVATIVE
659-
final int maybeUnsoundJumps = 0; // checker.getMaybeUnsoundJumps().size();
660-
661653
if (cfg.getEntrypoints().stream().findAny().isEmpty()) {
662654
log.warn("There are no entrypoints.");
663655
return null;
664656
}
665657

666658
Statement entryPoint = cfg.getEntrypoints().stream().findAny().get();
659+
int total = cfg.getAllJumps().size();
660+
int resolved = 0;
661+
int unreachable = 0;
662+
int erroneous = 0;
663+
int unknown = 0;
667664

668665
// we are safe supposing that we have a single entry point
669-
for (Statement jumpNode : cfg.getAllJumps()) {
670-
if ((jumpNode instanceof Jump) || (jumpNode instanceof Jumpi)) {
671-
boolean reachableFrom;
672-
int key = cfg.hashCode() + entryPoint.hashCode() + jumpNode.hashCode();
673-
674-
if (MyCache.getInstance().existsInReachableFrom(key)) {
675-
reachableFrom = MyCache.getInstance().isReachableFrom(key); // Caching
676-
log.debug("Value cached");
677-
} else {
678-
reachableFrom = cfg.reachableFrom(entryPoint, jumpNode);
679-
MyCache.getInstance().addReachableFrom(key, reachableFrom);
680-
}
681-
682-
Set<StackElement> topStackValuesPerJump = checker.getTopStackValuesPerJump(jumpNode);
683-
684-
if (cfg.getAllPushedJumps().contains(jumpNode))
685-
resolved++;
686-
else if (checker.getMaybeUnsoundJumps().contains(jumpNode))
687-
conservative++;
688-
else if (checker.getUnreachableJumps().contains(jumpNode) || !reachableFrom || topStackValuesPerJump.isEmpty())
666+
for (Statement jumpNode : cfg.getAllJumps())
667+
if ((jumpNode instanceof Jump) || (jumpNode instanceof Jumpi))
668+
if (!cfg.reachableFrom(entryPoint, jumpNode) || checker.getUnreachableJumps().contains(jumpNode))
669+
// getUnreachableJumps() contains jumps where the whole value state went to bottom
689670
unreachable++;
671+
else if (checker.getMaybeUnsoundJumps().contains(jumpNode))
672+
// getMaybeUnsoundJumps() contains jumps where the whole value state went to top
673+
unknown++;
674+
else if (cfg.getAllPushedJumps().contains(jumpNode))
675+
// stacks of pushed jumps are not stored for optimization
676+
resolved++;
690677
else {
691-
boolean allBot = true, oneTop = false;
692-
for (StackElement e : topStackValuesPerJump) {
693-
allBot &= e.isBottom();
694-
oneTop |= e.isTop();
695-
}
696-
697-
if (allBot)
698-
bottom++;
699-
else if (oneTop)
700-
conservative++;
678+
Set<StackElement> topStacks = checker.getTopStackValuesPerJump(jumpNode);
679+
if (topStacks.isEmpty())
680+
unreachable++;
681+
else if (topStacks.stream().allMatch(StackElement::isBottom))
682+
erroneous++;
683+
else if (topStacks.stream().anyMatch(StackElement::isTop))
684+
unknown++;
701685
else
702686
resolved++;
703687
}
704-
}
705-
}
706688

707689
log.info("Total opcodes: {}", cfg.getOpcodeCount());
708-
log.info("Total jumps: {}", cfg.getAllJumps().size());
690+
log.info("Total jumps: {}", total);
709691
log.info("Resolved jumps: {}", resolved);
692+
log.info("Unknown jumps: {}", unknown);
710693
log.info("Unreachable jumps: {}", unreachable);
711-
log.info("Bottom jumps: {}", bottom);
712-
log.info("Conservative jumps: {}", conservative);
694+
log.info("Erroneous jumps: {}", erroneous);
695+
int edges = cfg.getEdgesCount();
696+
log.info("Edges: {}", edges);
713697

714698
return MyLogger.newLogger()
715699
.opcodes(cfg.getOpcodeCount())
716-
.jumps(cfg.getAllJumps().size())
717-
.preciselyResolvedJumps(resolved)
718-
.definitelyUnreachableJumps(unreachable)
719-
.maybeUnreachableJumps(bottom)
720-
.unsoundJumps(conservative)
721-
.maybeUnsoundJumps(maybeUnsoundJumps);
700+
.jumps(total)
701+
.resolvedJumps(resolved)
702+
.unreachableJumps(unreachable)
703+
.erroneousJumps(erroneous)
704+
.unknownJumps(unknown)
705+
.edges(edges);
722706
}
723707

724708
/**
@@ -812,10 +796,20 @@ public static void toFile(String FILE_PATH, String stats) {
812796
if (!idea.exists()) {
813797
FileWriter myWriter = new FileWriter(idea, true);
814798

815-
String init = "Smart Contract, Total Opcodes, Total Jumps, Solved Jumps, Definitely unreachable jumps, Maybe unreachable jumps, Total solved Jumps, "
816-
+ "Unsound jumps, Maybe unsound jumps, % Total Solved, Time (millis), Time lost to get Storage, Actual time, Notes \n";
817-
818-
myWriter.write(init + stats);
799+
String header = "Smart Contract, "
800+
+ "Total Opcodes, "
801+
+ "Total Jumps, "
802+
+ "Resolved Jumps, "
803+
+ "Unknown jumps, "
804+
+ "Unreachable jumps, "
805+
+ "Erroneous Jumps, "
806+
+ "Edges, "
807+
+ "Time (millis), "
808+
+ "Time lost to get Storage, "
809+
+ "Actual time, "
810+
+ "Notes";
811+
812+
myWriter.write(header + "\n" + stats);
819813
myWriter.close();
820814

821815
} else {

0 commit comments

Comments
 (0)