|
| 1 | +/** |
| 2 | + * @name Missing Bank End Call |
| 3 | + * @description Finds paths that end a locking operation on one return |
| 4 | + * path but not on another. |
| 5 | + * @kind problem |
| 6 | + * @problem.severity warning |
| 7 | + * @precision high |
| 8 | + * @id asymmetric-research/missing-bank-end-call |
| 9 | + */ |
| 10 | + |
| 11 | +import cpp |
| 12 | + |
| 13 | +bindingset[base] |
| 14 | +predicate end(FunctionCall u, string base) { |
| 15 | + u.getTarget().hasName("fd_bank_" + base + "_end_locking_modify") or |
| 16 | + u.getTarget().hasName("fd_bank_" + base + "_end_locking_query") |
| 17 | +} |
| 18 | + |
| 19 | +string capTarget(FunctionCall f) { |
| 20 | + result = f.getTarget().getName().regexpCapture("fd_bank_((?!.*(?:^|_)end(?:_|$)).+?)_locking_.*", 1) |
| 21 | +} |
| 22 | + |
| 23 | +/* required for primitive infite type string (base) to be bound in |
| 24 | + forward and backward execution */ |
| 25 | +string genAll() { |
| 26 | + exists(FunctionCall f | |
| 27 | + result = capTarget(f) |
| 28 | + ) |
| 29 | +} |
| 30 | + |
| 31 | +ControlFlowNode nextNoUnlock(ControlFlowNode n, string base) { |
| 32 | + base = genAll() and |
| 33 | + not exists(FunctionCall u | end(u, base) and n = u) and |
| 34 | + ( |
| 35 | + result = n.getASuccessor() and result instanceof ReturnStmt |
| 36 | + or |
| 37 | + result = nextNoUnlock(n.getASuccessor(), base) |
| 38 | + ) |
| 39 | +} |
| 40 | + |
| 41 | +from FunctionCall l, string base |
| 42 | +where |
| 43 | + base = capTarget(l) and |
| 44 | + exists(FunctionCall u | end(u, base) and l.getASuccessor*() = u) and |
| 45 | + exists(nextNoUnlock(l, base)) |
| 46 | +select l, |
| 47 | + "missing " + base + "_end_locking_" + l.getTarget().getName().regexpCapture(".*_locking_(.*)", 1) + |
| 48 | + " call" |
0 commit comments