Skip to content

Commit 6b02381

Browse files
committed
WIP, snapshop
1 parent f2f120a commit 6b02381

1 file changed

Lines changed: 125 additions & 100 deletions

File tree

cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll

Lines changed: 125 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -496,11 +496,20 @@ private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) {
496496
}
497497

498498
private predicate isExplosiveVar(StackVariable v) {
499+
// exists(RangeSsaDefinition def, StackVariable v |
500+
// nrOfBoundsDef(def, v)
501+
// )
502+
// or
499503
none() and
500504
64 < count(RangeSsaDefinition def | def.getAVariable() = v and def.isPhiNode(_))
501505
}
502506

503-
// private predicate isWidenedVariable
507+
/**
508+
* Holds if `e` is an expression for which a very large number of bounds might
509+
* be generated during the range analysis.
510+
*/
511+
private predicate isExplosiveExpr(Expr e) { nrOfBounds(e) > 1000000 }
512+
504513
/**
505514
* Holds if the bounds of `e` depend on a recursive definition, meaning that
506515
* `e` is likely to have many candidate bounds during the main recursion.
@@ -512,7 +521,7 @@ private predicate isRecursiveExpr(Expr e) {
512521
}
513522

514523
/** Provides an estimated measure on the number of bounds for an expression. */
515-
private int nrOfBounds(Expr e) {
524+
private float nrOfBounds(Expr e) {
516525
isRecursiveExpr(e) and result = 13 // FIXME: Let's not hardcode this
517526
or
518527
not isRecursiveExpr(e) and
@@ -550,8 +559,6 @@ private int nrOfBounds(Expr e) {
550559
exists(AssignMulByConstantExpr mulExpr |
551560
e = mulExpr and
552561
result = nrOfBounds(mulExpr.getLValue())
553-
// xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and
554-
// result = xLow * mulExpr.getConstant()
555562
)
556563
or
557564
// Handles the `--` and `++` operators
@@ -573,7 +580,7 @@ private int nrOfBounds(Expr e) {
573580
or
574581
exists(RangeSsaDefinition def, StackVariable v |
575582
e = def.getAUse(v) and
576-
result = defNrOfBounds(def, v) and
583+
result = nrOfBoundsDef(def, v) and
577584
not exists(getValue(e).toFloat())
578585
)
579586
or
@@ -593,6 +600,12 @@ private int nrOfBounds(Expr e) {
593600
e instanceof AssignSubExpr or
594601
e instanceof UnsignedAssignMulExpr
595602
)
603+
or
604+
exists(RShiftExpr rsExpr |
605+
e = rsExpr and
606+
exists(getValue(rsExpr.getRightOperand().getFullyConverted()).toInt()) and
607+
result = nrOfBounds(rsExpr.getLeftOperand())
608+
)
596609
)
597610
or
598611
not analyzableExpr(e) and exists(exprMinVal(e)) and result = 1
@@ -608,87 +621,113 @@ int teststst(RangeSsaDefinition def, StackVariable v, VariableAccess access) {
608621
)
609622
}
610623

624+
private predicate hasLinearBoundFromGuard2(
625+
ComparisonOperation guard, VariableAccess v, float p, float q, RelationStrictness strictness,
626+
boolean branch // Which control-flow branch is this bound valid on?
627+
) {
628+
exists(Expr lhs, Expr rhs, RelationDirection dir, RelationStrictness st |
629+
linearAccess(lhs, v, p, q) and
630+
relOpWithSwapAndNegate(guard, lhs, rhs, dir, st, branch)
631+
|
632+
strictness = st
633+
or
634+
strictness = Nonstrict() and
635+
exprTypeBounds(rhs, _, _)
636+
)
637+
or
638+
exists(Expr lhs, Expr rhs |
639+
linearAccess(lhs, v, p, q) and
640+
eqOpWithSwapAndNegate(guard, lhs, rhs, true, branch) and
641+
strictness = Nonstrict()
642+
)
643+
}
644+
645+
/**
646+
* Holds if `lowerBoundFromGuard(guard, v, _, branch)` holds, but without
647+
* relying on range analysis (which would cause non-monotonic recursion
648+
* elsewhere).
649+
*/
650+
predicate hasLowerBoundFromGuard(Expr guard, VariableAccess v, boolean branch) {
651+
hasLinearBoundFromGuard2(guard, v, _, _, _, branch)
652+
or
653+
// lowerBoundFromGuard(guard, v, _, branch)
654+
exists(float p, float q, Expr e |
655+
linearAccess(e, v, p, q) and
656+
eqZeroWithNegate(guard, e, true, branch) // and
657+
// boundValue = (0.0 - q) / p and
658+
// isLowerBound = [false, true] and
659+
// strictness = Nonstrict()
660+
)
661+
}
662+
663+
predicate missing(Expr guard, VariableAccess access, boolean branch) {
664+
lowerBoundFromGuard(guard, access, _, branch) and
665+
not hasLowerBoundFromGuard(guard, access, branch)
666+
}
667+
668+
predicate tooMuch(Expr guard, VariableAccess access, boolean branch) {
669+
not lowerBoundFromGuard(guard, access, _, branch) and
670+
hasLowerBoundFromGuard(guard, access, branch)
671+
}
672+
611673
predicate isGuardPhiWithBound(
612674
RangeSsaDefinition def, StackVariable v, VariableAccess access, Expr guard, boolean branch
613675
) {
614676
def.isGuardPhi(v, access, guard, branch) and
615-
lowerBoundFromGuard(guard, access, _, branch)
677+
hasLowerBoundFromGuard(guard, access, branch)
616678
}
617679

618-
language[monotonicAggregates]
619-
int defNrOfBoundsPhiGuard(RangeSsaDefinition def, StackVariable v) {
620-
v = Debug::getRelevantLocatable() and
621-
(
622-
// NOTE: A phi node can be both a guard phi node and a normal phi node. In
623-
// that case we only treat it as a normal phi node.
624-
// TODO: Should we change this in `getPhiLowerBounds`?
625-
// not exists(VariableAccess access, Expr guard, boolean branch |
626-
// def.isGuardPhi(v, access, guard, branch) and
627-
// lowerBoundFromGuard(guard, access, _, branch)
628-
// ) and
629-
not isGuardPhiWithBound(def, v, _, _, _) and
630-
def.isPhiNode(v) and
631-
result = 0
632-
or
633-
// NOTE: The differenct `access`es are the same variable and the lower
634-
// bounds are the same. The guard may filter some away. Hence adding these
635-
// guards make no sense (the impl will take the union but after dedup taking
636-
// `max` is a better representation).
637-
result =
638-
max(VariableAccess access |
639-
// def.isGuardPhi(v, access, guard, branch) and
640-
// lowerBoundFromGuard(guard, access, _, branch)
641-
isGuardPhiWithBound(def, v, access, _, _)
642-
|
643-
nrOfBounds(access)
644-
)
645-
)
680+
predicate debugThing(RangeSsaDefinition def, StackVariable v, VariableAccess access) {
681+
def.isGuardPhi(v, access, _, _) and
682+
not isGuardPhiWithBound(def, v, access, _, _)
646683
}
647684

648685
language[monotonicAggregates]
649-
int defNrOfBoundsPhiNormal(RangeSsaDefinition def, StackVariable v) {
650-
v = Debug::getRelevantLocatable() and
651-
(
652-
def.isGuardPhi(v, _, _, _) and
653-
not exists(def.getAPhiInput(v)) and
654-
result = 0
655-
or
656-
result =
657-
strictsum(RangeSsaDefinition inputDef |
658-
inputDef = def.getAPhiInput(v)
659-
|
660-
defNrOfBounds(inputDef, v)
661-
)
662-
)
686+
float defNrOfBoundsPhiGuard(RangeSsaDefinition def, StackVariable v) {
687+
def.isPhiNode(v) and
688+
not isGuardPhiWithBound(def, v, _, _, _) and
689+
result = 0
690+
or
691+
// NOTE: The differenct `access`es are the same variable and the lower
692+
// bounds are the same. The guard may filter some away. Hence adding these
693+
// guards make no sense (the impl will take the union but after dedup taking
694+
// `max` is a better representation).
695+
result =
696+
max(VariableAccess access | isGuardPhiWithBound(def, v, access, _, _) | nrOfBounds(access))
663697
}
664698

665-
int nrOfBoundsNEPhi(RangeSsaDefinition def, StackVariable v) {
666-
v = Debug::getRelevantLocatable() and
667-
(
668-
exists(VariableAccess access | isNEPhi(v, def, access, _) and result = nrOfBounds(access))
669-
or
670-
not isNEPhi(v, def, _, _) and result = 0
671-
)
699+
language[monotonicAggregates]
700+
float defNrOfBoundsPhiNormal(RangeSsaDefinition def, StackVariable v) {
701+
def.isPhiNode(v) and
702+
not exists(def.getAPhiInput(v)) and
703+
result = 0
704+
or
705+
result =
706+
strictsum(RangeSsaDefinition inputDef |
707+
inputDef = def.getAPhiInput(v)
708+
|
709+
nrOfBoundsDef(inputDef, v)
710+
)
672711
}
673712

674-
predicate gimmeBug(RangeSsaDefinition def, StackVariable v) {
675-
nrOfBoundsNEPhi(def, v) > 0 and
676-
exists(defNrOfBoundsPhiNormal(def, v)) and
677-
exists(defNrOfBoundsPhiGuard(def, v))
713+
float nrOfBoundsNEPhi(RangeSsaDefinition def, StackVariable v) {
714+
exists(VariableAccess access | isNEPhi(v, def, access, _) and result = nrOfBounds(access))
715+
or
716+
def.isPhiNode(v) and
717+
not isNEPhi(v, def, _, _) and
718+
result = 0
678719
}
679720

680-
int nrOfBoundsPhi(RangeSsaDefinition def, StackVariable v) {
681-
exists(int nePhi, int unsupportedGuardPhi |
721+
float nrOfBoundsPhi(RangeSsaDefinition def, StackVariable v) {
722+
// NOTE: A phi node can be both a guard phi node and a normal phi node. In
723+
// that case we only treat it as a normal phi node.
724+
// TODO: Should we change this in `getPhiLowerBounds`?
725+
exists(int unsupportedGuardPhi |
682726
result =
683727
// Guard phi nodes
684728
defNrOfBoundsPhiGuard(def, v) +
685729
// Normal phi nodes
686-
defNrOfBoundsPhiNormal(def, v) + nePhi + unsupportedGuardPhi and
687-
// (exists(VariableAccess access | isNEPhi(v, def, access, _) and nePhi = nrOfBounds(access))
688-
// or
689-
// not isNEPhi(v, def, _, _) and nePhi = 0.0)
690-
nePhi = nrOfBoundsNEPhi(def, v) and
691-
// unsupportedGuardPhi = 0 and
730+
defNrOfBoundsPhiNormal(def, v) + nrOfBoundsNEPhi(def, v) + unsupportedGuardPhi and
692731
(
693732
exists(VariableAccess access |
694733
isUnsupportedGuardPhi(v, def, access) and
@@ -702,7 +741,7 @@ int nrOfBoundsPhi(RangeSsaDefinition def, StackVariable v) {
702741
}
703742

704743
language[monotonicAggregates]
705-
int defNrOfBounds(RangeSsaDefinition def, StackVariable v) {
744+
float nrOfBoundsDef(RangeSsaDefinition def, StackVariable v) {
706745
v = Debug::getRelevantLocatable() and
707746
(
708747
// Definitions with a defining value
@@ -1777,27 +1816,23 @@ private predicate exprTypeBounds(Expr expr, float boundValue, boolean isLowerBou
17771816
private predicate isNEPhi(
17781817
Variable v, RangeSsaDefinition phi, VariableAccess access, float neConstant
17791818
) {
1780-
v = Debug::getRelevantLocatable() and
1781-
(
1782-
exists(
1783-
ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q,
1784-
float r
1785-
|
1786-
phi.isGuardPhi(v, access, cmp, branch) and
1787-
eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and
1788-
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise
1789-
r = getValue(rExpr).toFloat() and
1790-
linearAccess(linearExpr, access, p, q) and
1791-
neConstant = (r - q) / p
1792-
)
1793-
or
1794-
exists(Expr op, boolean branch, Expr linearExpr, float p, float q |
1795-
phi.isGuardPhi(v, access, op, branch) and
1796-
eqZeroWithNegate(op, linearExpr, false, branch) and
1797-
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise
1798-
linearAccess(linearExpr, access, p, q) and
1799-
neConstant = (0.0 - q) / p
1800-
)
1819+
exists(
1820+
ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q, float r
1821+
|
1822+
phi.isGuardPhi(v, access, cmp, branch) and
1823+
eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and
1824+
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise
1825+
r = getValue(rExpr).toFloat() and
1826+
linearAccess(linearExpr, access, p, q) and
1827+
neConstant = (r - q) / p
1828+
)
1829+
or
1830+
exists(Expr op, boolean branch, Expr linearExpr, float p, float q |
1831+
phi.isGuardPhi(v, access, op, branch) and
1832+
eqZeroWithNegate(op, linearExpr, false, branch) and
1833+
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise
1834+
linearAccess(linearExpr, access, p, q) and
1835+
neConstant = (0.0 - q) / p
18011836
)
18021837
}
18031838

@@ -2117,7 +2152,7 @@ private module Debug {
21172152
Locatable getRelevantLocatable() {
21182153
exists(string filepath, int startline |
21192154
result.getLocation().hasLocationInfo(filepath, startline, _, _, _) and
2120-
// filepath.matches("%/Cmprs_RiceLayersMem.C") and
2155+
// filepath.matches("%/Cmprs_RiceLayersMem.C") // and
21212156
// startline = [1452 .. 1480]
21222157
filepath.matches("%/test.c") // and
21232158
// startline = [845 .. 867]
@@ -2174,16 +2209,6 @@ private module Debug {
21742209
)
21752210
}
21762211

2177-
int debugDefNrOfBounds(RangeSsaDefinition def, StackVariable v) {
2178-
v = getRelevantLocatable() and
2179-
defNrOfBounds(def, v) = result
2180-
}
2181-
2182-
int debugDefNrOfBoundsPhiNormal(RangeSsaDefinition def, StackVariable v) {
2183-
v = getRelevantLocatable() and
2184-
defNrOfBoundsPhiNormal(def, v) = result
2185-
}
2186-
21872212
int nonFunctionalNrOfBounds(Expr e) {
21882213
// e = getRelevantLocatable() and
21892214
strictcount(nrOfBounds(e)) > 1 and

0 commit comments

Comments
 (0)