|
4 | 4 |
|
5 | 5 | import csharp |
6 | 6 | private import ControlFlow::SuccessorTypes |
| 7 | +private import semmle.code.csharp.commons.Assertions |
7 | 8 | private import semmle.code.csharp.commons.ComparisonTest |
8 | 9 | private import semmle.code.csharp.commons.StructuralComparison::Internal |
9 | 10 | private import semmle.code.csharp.controlflow.BasicBlocks |
@@ -472,30 +473,69 @@ module Internal { |
472 | 473 | pragma [noinline] |
473 | 474 | private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) { |
474 | 475 | target = e.getTarget() and |
475 | | - controls(bb, _, e, _) |
| 476 | + exists(Expr e0 | |
| 477 | + e = e0.getAChildExpr*() | |
| 478 | + controls(bb, e0, _) |
| 479 | + or |
| 480 | + controlsNode(bb.getANode(), e0, _) |
| 481 | + ) |
476 | 482 | } |
477 | 483 | } |
478 | 484 |
|
479 | | - /** |
480 | | - * Holds if basic block `bb` only is reached when `e` has abstract value `v`. |
481 | | - * SSA qualified expression `sub` is a sub expression of `e`. |
482 | | - */ |
483 | | - private predicate controls(BasicBlock bb, Expr e, AccessOrCallExpr sub, AbstractValue v) { |
| 485 | + /** Holds if basic block `bb` only is reached when `e` has abstract value `v`. */ |
| 486 | + private predicate controls(BasicBlock bb, Expr e, AbstractValue v) { |
484 | 487 | exists(ConditionBlock cb, ConditionalSuccessor s, AbstractValue v0, Expr cond | |
485 | 488 | cb.controls(bb, s) | |
486 | 489 | v0.branchImplies(cb.getLastNode().getElement(), s, cond) and |
487 | | - impliesSteps(cond, v0, e, v) and |
488 | | - sub = e.getAChildExpr*() |
| 490 | + impliesSteps(cond, v0, e, v) |
| 491 | + ) |
| 492 | + } |
| 493 | + |
| 494 | + /** |
| 495 | + * Holds if assertion `a` directly asserts that expression `e` evaluates to |
| 496 | + * value `v`. |
| 497 | + */ |
| 498 | + predicate asserts(Assertion a, Expr e, AbstractValue v) { |
| 499 | + e = a.getExpr() and |
| 500 | + ( |
| 501 | + a.getAssertMethod() instanceof AssertTrueMethod and |
| 502 | + v.(BooleanValue).getValue() = true |
| 503 | + or |
| 504 | + a.getAssertMethod() instanceof AssertFalseMethod and |
| 505 | + v.(BooleanValue).getValue() = false |
| 506 | + or |
| 507 | + a.getAssertMethod() instanceof AssertNullMethod and |
| 508 | + v.(NullValue).isNull() |
| 509 | + or |
| 510 | + a.getAssertMethod() instanceof AssertNonNullMethod and |
| 511 | + v = any(NullValue nv | not nv.isNull()) |
| 512 | + ) |
| 513 | + } |
| 514 | + |
| 515 | + /** Holds if control flow node `cfn` only is reached when `e` evaluates to `v`. */ |
| 516 | + private predicate controlsNode(ControlFlow::Node cfn, Expr e, AbstractValue v) { |
| 517 | + exists(Assertion a, Expr e0, AbstractValue v0 | |
| 518 | + a.getAControlFlowNode().dominates(cfn) | |
| 519 | + asserts(a, e0, v0) and |
| 520 | + impliesSteps(e0, v0, e, v) |
489 | 521 | ) |
490 | 522 | } |
491 | 523 |
|
492 | 524 | private cached module Cached { |
| 525 | + pragma[noinline] |
| 526 | + private predicate isGuardedBy0(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) { |
| 527 | + exists(ControlFlow::Node cfn | |
| 528 | + (controls(cfn.getBasicBlock(), e, v) or controlsNode(cfn, e, v)) and |
| 529 | + cfn = guarded.getAControlFlowNode() and |
| 530 | + exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) |
| 531 | + ) |
| 532 | + } |
| 533 | + |
493 | 534 | cached |
494 | 535 | predicate isGuardedBy(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) { |
495 | | - exists(BasicBlock bb | |
496 | | - controls(bb, e, sub, v) and |
497 | | - bb = guarded.getAControlFlowNode().getBasicBlock() and |
498 | | - exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) | |
| 536 | + isGuardedBy0(guarded, e, sub, v) and |
| 537 | + sub = e.getAChildExpr*() and |
| 538 | + ( |
499 | 539 | not guarded.hasSsaQualifier() and not sub.hasSsaQualifier() |
500 | 540 | or |
501 | 541 | guarded.getSsaQualifier() = sub.getSsaQualifier() |
@@ -647,6 +687,13 @@ module Internal { |
647 | 687 | e2 = e1 and |
648 | 688 | v2 = v1 |
649 | 689 | or |
| 690 | + exists(Assertion a | |
| 691 | + e1 = a.getExpr() | |
| 692 | + asserts(a, e1, v1) and |
| 693 | + e2 = e1 and |
| 694 | + v2 = v1 |
| 695 | + ) |
| 696 | + or |
650 | 697 | exists(Expr mid, AbstractValue vMid | |
651 | 698 | impliesSteps(e1, v1, mid, vMid) | |
652 | 699 | impliesStep(mid, vMid, e2, v2) |
|
0 commit comments