mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge branch 'main' into mathiasvp/read-step-without-memory-operands
This commit is contained in:
@@ -33,10 +33,10 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` should be a barrier in all global taint flow configurations
|
||||
* Holds if `node` should be a sanitizer in all global taint flow configurations
|
||||
* but not in local taint.
|
||||
*/
|
||||
predicate defaultTaintBarrier(DataFlow::Node node) { none() }
|
||||
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
|
||||
|
||||
@@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
isSanitizer(node) or
|
||||
defaultTaintBarrier(node)
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
|
||||
@@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
isSanitizer(node) or
|
||||
defaultTaintBarrier(node)
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
|
||||
@@ -402,7 +402,7 @@ class Expr extends StmtParent, @expr {
|
||||
*/
|
||||
predicate hasImplicitConversion() {
|
||||
exists(Expr e |
|
||||
exprconv(underlyingElement(this), unresolveElement(e)) and e.(Cast).isImplicit()
|
||||
exprconv(underlyingElement(this), unresolveElement(e)) and e.(Conversion).isImplicit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ class Expr extends StmtParent, @expr {
|
||||
*/
|
||||
predicate hasExplicitConversion() {
|
||||
exists(Expr e |
|
||||
exprconv(underlyingElement(this), unresolveElement(e)) and not e.(Cast).isImplicit()
|
||||
exprconv(underlyingElement(this), unresolveElement(e)) and not e.(Conversion).isImplicit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -453,12 +453,14 @@ class Expr extends StmtParent, @expr {
|
||||
* cast from B to C. Only (1) and (2) would be included.
|
||||
*/
|
||||
Expr getExplicitlyConverted() {
|
||||
// result is this or one of its conversions
|
||||
result = this.getConversion*() and
|
||||
// result is not an implicit conversion - it's either the expr or an explicit cast
|
||||
(result = this or not result.(Cast).isImplicit()) and
|
||||
// there is no further explicit conversion after result
|
||||
not exists(Cast other | other = result.getConversion+() and not other.isImplicit())
|
||||
// For performance, we avoid a full transitive closure over `getConversion`.
|
||||
// Since there can be several implicit conversions before and after an
|
||||
// explicit conversion, use `getImplicitlyConverted` to step over them
|
||||
// cheaply. Then, if there is an explicit conversion following the implict
|
||||
// conversion sequence, recurse to handle multiple explicit conversions.
|
||||
if this.getImplicitlyConverted().hasExplicitConversion()
|
||||
then result = this.getImplicitlyConverted().getConversion().getExplicitlyConverted()
|
||||
else result = this
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -100,10 +100,10 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` should be a barrier in all global taint flow configurations
|
||||
* Holds if `node` should be a sanitizer in all global taint flow configurations
|
||||
* but not in local taint.
|
||||
*/
|
||||
predicate defaultTaintBarrier(DataFlow::Node node) { none() }
|
||||
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `instrIn` to `instrOut` through a call to a
|
||||
|
||||
@@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
isSanitizer(node) or
|
||||
defaultTaintBarrier(node)
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
|
||||
@@ -76,20 +76,20 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
isSanitizer(node) or
|
||||
defaultTaintBarrier(node)
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
||||
|
||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
|
||||
@@ -18,3 +18,4 @@ private import implementations.StdContainer
|
||||
private import implementations.StdString
|
||||
private import implementations.Swap
|
||||
private import implementations.GetDelim
|
||||
private import implementations.SmartPointer
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
|
||||
/**
|
||||
* The `std::shared_ptr` and `std::unique_ptr` template classes.
|
||||
*/
|
||||
class UniqueOrSharedPtr extends Class {
|
||||
UniqueOrSharedPtr() { this.hasQualifiedName("std", ["shared_ptr", "unique_ptr"]) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::make_shared` and `std::make_unique` template functions.
|
||||
*/
|
||||
class MakeUniqueOrShared extends TaintFunction {
|
||||
MakeUniqueOrShared() { this.hasQualifiedName("std", ["make_shared", "make_unique"]) }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// Exclude the specializations of `std::make_shared` and `std::make_unique` that allocate arrays
|
||||
// since these just take a size argument, which we don't want to propagate taint through.
|
||||
not this.isArray() and
|
||||
input.isParameter(_) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function returns a `shared_ptr<T>` (or `unique_ptr<T>`) where `T` is an
|
||||
* array type (i.e., `U[]` for some type `U`).
|
||||
*/
|
||||
predicate isArray() {
|
||||
this.getTemplateArgument(0).(Type).getUnderlyingType() instanceof ArrayType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A prefix `operator*` member function for a `shared_ptr` or `unique_ptr` type.
|
||||
*/
|
||||
class UniqueOrSharedDereferenceMemberOperator extends MemberFunction, TaintFunction {
|
||||
UniqueOrSharedDereferenceMemberOperator() {
|
||||
this.hasName("operator*") and
|
||||
this.getDeclaringType() instanceof UniqueOrSharedPtr
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::shared_ptr` or `std::unique_ptr` function `get`.
|
||||
*/
|
||||
class UniqueOrSharedGet extends TaintFunction {
|
||||
UniqueOrSharedGet() {
|
||||
this.hasName("get") and
|
||||
this.getDeclaringType() instanceof UniqueOrSharedPtr
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
@@ -171,6 +171,65 @@ predicate eqOpWithSwapAndNegate(EqualityOperation cmp, Expr a, Expr b, boolean i
|
||||
eqOpWithSwap(cmp, a, b, branch.booleanNot()) and isEQ = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cmp` is an unconverted conversion of `a` to a Boolean that
|
||||
* evalutes to `isEQ` iff `a` is 0.
|
||||
*
|
||||
* Note that `a` can be `cmp` itself or a conversion thereof.
|
||||
*/
|
||||
private predicate eqZero(Expr cmp, Expr a, boolean isEQ) {
|
||||
// The `!a` expression tests `a` equal to zero when `a` is a number converted
|
||||
// to a Boolean.
|
||||
isEQ = true and
|
||||
exists(Expr notOperand | notOperand = cmp.(NotExpr).getOperand().getFullyConverted() |
|
||||
// In C++ code there will be a BoolConversion in `!myInt`
|
||||
a = notOperand.(BoolConversion).getExpr()
|
||||
or
|
||||
// In C code there is no conversion since there was no bool type before C99
|
||||
a = notOperand and
|
||||
not a instanceof BoolConversion // avoid overlap with the case above
|
||||
)
|
||||
or
|
||||
// The `(bool)a` expression tests `a` NOT equal to zero when `a` is a number
|
||||
// converted to a Boolean. To avoid overlap with the case above, this case
|
||||
// excludes conversions that are right below a `!`.
|
||||
isEQ = false and
|
||||
linearAccess(cmp, _, _, _) and
|
||||
// This test for `isCondition` implies that `cmp` is unconverted and that the
|
||||
// parent of `cfg` is not a `NotExpr` -- the CFG doesn't do branching from
|
||||
// inside `NotExpr`.
|
||||
cmp.isCondition() and
|
||||
// The GNU two-operand conditional expression is not supported for the
|
||||
// purpose of guards, but the value of the conditional expression itself is
|
||||
// modeled in the range analysis.
|
||||
not exists(ConditionalExpr cond | cmp = cond.getCondition() and cond.isTwoOperand()) and
|
||||
(
|
||||
// In C++ code there will be a BoolConversion in `if (myInt)`
|
||||
a = cmp.getFullyConverted().(BoolConversion).getExpr()
|
||||
or
|
||||
// In C code there is no conversion since there was no bool type before C99
|
||||
a = cmp.getFullyConverted() and
|
||||
not a instanceof BoolConversion // avoid overlap with the case above
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `branch` of `cmp` is taken when `a` compares `isEQ` to zero.
|
||||
*
|
||||
* Note that `a` can be `cmp` itself or a conversion thereof.
|
||||
*/
|
||||
predicate eqZeroWithNegate(Expr cmp, Expr a, boolean isEQ, boolean branch) {
|
||||
// The comparison for _equality_ to zero is on the `true` branch when `cmp`
|
||||
// compares equal to zero and on the `false` branch when `cmp` compares not
|
||||
// equal to zero.
|
||||
eqZero(cmp, a, branch) and isEQ = true
|
||||
or
|
||||
// The comparison for _inequality_ to zero is on the `false` branch when
|
||||
// `cmp` compares equal to zero and on the `true` branch when `cmp` compares
|
||||
// not equal to zero.
|
||||
eqZero(cmp, a, branch.booleanNot()) and isEQ = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` is equivalent to `p*v + q`, where `p` is a non-zero
|
||||
* number. This takes into account the associativity, commutativity and
|
||||
|
||||
@@ -40,21 +40,20 @@ library class RangeSSA extends SSAHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate guard_defn(
|
||||
VariableAccess v, ComparisonOperation guard, BasicBlock b, boolean branch
|
||||
) {
|
||||
private predicate guard_defn(VariableAccess v, Expr guard, BasicBlock b, boolean branch) {
|
||||
guardCondition(guard, v, branch) and
|
||||
guardSuccessor(guard, branch, b)
|
||||
}
|
||||
|
||||
private predicate guardCondition(ComparisonOperation guard, VariableAccess v, boolean branch) {
|
||||
private predicate guardCondition(Expr guard, VariableAccess v, boolean branch) {
|
||||
exists(Expr lhs | linearAccess(lhs, v, _, _) |
|
||||
relOpWithSwapAndNegate(guard, lhs, _, _, _, branch) or
|
||||
eqOpWithSwapAndNegate(guard, lhs, _, _, branch)
|
||||
eqOpWithSwapAndNegate(guard, lhs, _, _, branch) or
|
||||
eqZeroWithNegate(guard, lhs, _, branch)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate guardSuccessor(ComparisonOperation guard, boolean branch, BasicBlock succ) {
|
||||
private predicate guardSuccessor(Expr guard, boolean branch, BasicBlock succ) {
|
||||
branch = true and succ = guard.getATrueSuccessor()
|
||||
or
|
||||
branch = false and succ = guard.getAFalseSuccessor()
|
||||
@@ -98,7 +97,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
* If this definition is a phi node corresponding to a guard,
|
||||
* then return the variable and the guard.
|
||||
*/
|
||||
predicate isGuardPhi(VariableAccess v, ComparisonOperation guard, boolean branch) {
|
||||
predicate isGuardPhi(VariableAccess v, Expr guard, boolean branch) {
|
||||
guard_defn(v, guard, this, branch)
|
||||
}
|
||||
|
||||
|
||||
@@ -427,11 +427,11 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria
|
||||
private predicate phiDependsOnDef(
|
||||
RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
|
||||
) {
|
||||
exists(VariableAccess access, ComparisonOperation guard |
|
||||
exists(VariableAccess access, Expr guard |
|
||||
access = v.getAnAccess() and
|
||||
phi.isGuardPhi(access, guard, _)
|
||||
|
|
||||
exprDependsOnDef(guard.getAnOperand(), srcDef, srcVar) or
|
||||
exprDependsOnDef(guard.(ComparisonOperation).getAnOperand(), srcDef, srcVar) or
|
||||
exprDependsOnDef(access, srcDef, srcVar)
|
||||
)
|
||||
or
|
||||
@@ -1132,9 +1132,7 @@ private float boolConversionUpperBound(Expr expr) {
|
||||
* use the guard to deduce that the lower bound is 2 inside the block.
|
||||
*/
|
||||
private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
exists(
|
||||
VariableAccess access, ComparisonOperation guard, boolean branch, float defLB, float guardLB
|
||||
|
|
||||
exists(VariableAccess access, Expr guard, boolean branch, float defLB, float guardLB |
|
||||
access = v.getAnAccess() and
|
||||
phi.isGuardPhi(access, guard, branch) and
|
||||
lowerBoundFromGuard(guard, access, guardLB, branch) and
|
||||
@@ -1146,13 +1144,13 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
or
|
||||
exists(VariableAccess access, float neConstant, float lower |
|
||||
isNEPhi(v, phi, access, neConstant) and
|
||||
lower = getFullyConvertedLowerBounds(access) and
|
||||
lower = getTruncatedLowerBounds(access) and
|
||||
if lower = neConstant then result = lower + 1 else result = lower
|
||||
)
|
||||
or
|
||||
exists(VariableAccess access |
|
||||
isUnsupportedGuardPhi(v, phi, access) and
|
||||
result = getFullyConvertedLowerBounds(access)
|
||||
result = getTruncatedLowerBounds(access)
|
||||
)
|
||||
or
|
||||
result = getDefLowerBounds(phi.getAPhiInput(v), v)
|
||||
@@ -1160,9 +1158,7 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
|
||||
/** See comment for `getPhiLowerBounds`, above. */
|
||||
private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
exists(
|
||||
VariableAccess access, ComparisonOperation guard, boolean branch, float defUB, float guardUB
|
||||
|
|
||||
exists(VariableAccess access, Expr guard, boolean branch, float defUB, float guardUB |
|
||||
access = v.getAnAccess() and
|
||||
phi.isGuardPhi(access, guard, branch) and
|
||||
upperBoundFromGuard(guard, access, guardUB, branch) and
|
||||
@@ -1174,13 +1170,13 @@ private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
or
|
||||
exists(VariableAccess access, float neConstant, float upper |
|
||||
isNEPhi(v, phi, access, neConstant) and
|
||||
upper = getFullyConvertedUpperBounds(access) and
|
||||
upper = getTruncatedUpperBounds(access) and
|
||||
if upper = neConstant then result = upper - 1 else result = upper
|
||||
)
|
||||
or
|
||||
exists(VariableAccess access |
|
||||
isUnsupportedGuardPhi(v, phi, access) and
|
||||
result = getFullyConvertedUpperBounds(access)
|
||||
result = getTruncatedUpperBounds(access)
|
||||
)
|
||||
or
|
||||
result = getDefUpperBounds(phi.getAPhiInput(v), v)
|
||||
@@ -1334,7 +1330,7 @@ private predicate unanalyzableDefBounds(RangeSsaDefinition def, StackVariable v,
|
||||
* inferences about `v`.
|
||||
*/
|
||||
bindingset[guard, v, branch]
|
||||
predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boolean branch) {
|
||||
predicate nonNanGuardedVariable(Expr guard, VariableAccess v, boolean branch) {
|
||||
getVariableRangeType(v.getTarget()) instanceof IntegralType
|
||||
or
|
||||
getVariableRangeType(v.getTarget()) instanceof FloatingPointType and
|
||||
@@ -1353,9 +1349,7 @@ predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boo
|
||||
* predicate uses the bounds information for `r` to compute a lower bound
|
||||
* for `v`.
|
||||
*/
|
||||
private predicate lowerBoundFromGuard(
|
||||
ComparisonOperation guard, VariableAccess v, float lb, boolean branch
|
||||
) {
|
||||
private predicate lowerBoundFromGuard(Expr guard, VariableAccess v, float lb, boolean branch) {
|
||||
exists(float childLB, RelationStrictness strictness |
|
||||
boundFromGuard(guard, v, childLB, true, strictness, branch)
|
||||
|
|
||||
@@ -1375,9 +1369,7 @@ private predicate lowerBoundFromGuard(
|
||||
* predicate uses the bounds information for `r` to compute a upper bound
|
||||
* for `v`.
|
||||
*/
|
||||
private predicate upperBoundFromGuard(
|
||||
ComparisonOperation guard, VariableAccess v, float ub, boolean branch
|
||||
) {
|
||||
private predicate upperBoundFromGuard(Expr guard, VariableAccess v, float ub, boolean branch) {
|
||||
exists(float childUB, RelationStrictness strictness |
|
||||
boundFromGuard(guard, v, childUB, false, strictness, branch)
|
||||
|
|
||||
@@ -1397,7 +1389,7 @@ private predicate upperBoundFromGuard(
|
||||
* `linearBoundFromGuard`.
|
||||
*/
|
||||
private predicate boundFromGuard(
|
||||
ComparisonOperation guard, VariableAccess v, float boundValue, boolean isLowerBound,
|
||||
Expr guard, VariableAccess v, float boundValue, boolean isLowerBound,
|
||||
RelationStrictness strictness, boolean branch
|
||||
) {
|
||||
exists(float p, float q, float r, boolean isLB |
|
||||
@@ -1410,6 +1402,15 @@ private predicate boundFromGuard(
|
||||
or
|
||||
p < 0 and isLowerBound = isLB.booleanNot()
|
||||
)
|
||||
or
|
||||
// When `!e` is true, we know that `0 <= e <= 0`
|
||||
exists(float p, float q, Expr e |
|
||||
linearAccess(e, v, p, q) and
|
||||
eqZeroWithNegate(guard, e, true, branch) and
|
||||
boundValue = (0.0 - q) / p and
|
||||
isLowerBound = [false, true] and
|
||||
strictness = Nonstrict()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1487,6 +1488,15 @@ private predicate isNEPhi(
|
||||
linearAccess(linearExpr, access, p, q) and
|
||||
neConstant = (r - q) / p
|
||||
)
|
||||
or
|
||||
exists(Expr op, boolean branch, Expr linearExpr, float p, float q |
|
||||
access.getTarget() = v and
|
||||
phi.isGuardPhi(access, op, branch) and
|
||||
eqZeroWithNegate(op, linearExpr, false, branch) and
|
||||
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise
|
||||
linearAccess(linearExpr, access, p, q) and
|
||||
neConstant = (0.0 - q) / p
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1496,10 +1506,13 @@ private predicate isNEPhi(
|
||||
* compile-time constant.
|
||||
*/
|
||||
private predicate isUnsupportedGuardPhi(Variable v, RangeSsaDefinition phi, VariableAccess access) {
|
||||
exists(ComparisonOperation cmp, boolean branch |
|
||||
exists(Expr cmp, boolean branch |
|
||||
eqOpWithSwapAndNegate(cmp, _, _, false, branch)
|
||||
or
|
||||
eqZeroWithNegate(cmp, _, false, branch)
|
||||
|
|
||||
access.getTarget() = v and
|
||||
phi.isGuardPhi(access, cmp, branch) and
|
||||
eqOpWithSwapAndNegate(cmp, _, _, false, branch) and
|
||||
not isNEPhi(v, phi, access, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -439,6 +439,46 @@
|
||||
| movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT |
|
||||
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT |
|
||||
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:11:65:11 | call to operator= | TAINT |
|
||||
| smart_pointer.cpp:11:30:11:50 | call to make_shared | smart_pointer.cpp:12:11:12:11 | p | |
|
||||
| smart_pointer.cpp:11:30:11:50 | call to make_shared | smart_pointer.cpp:13:10:13:10 | p | |
|
||||
| smart_pointer.cpp:11:52:11:57 | call to source | smart_pointer.cpp:11:30:11:50 | call to make_shared | TAINT |
|
||||
| smart_pointer.cpp:12:11:12:11 | p | smart_pointer.cpp:12:10:12:10 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:18:11:18:11 | p | |
|
||||
| smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:19:10:19:10 | p | |
|
||||
| smart_pointer.cpp:18:11:18:11 | p | smart_pointer.cpp:18:10:18:10 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:23:30:23:50 | call to make_unique | smart_pointer.cpp:24:11:24:11 | p | |
|
||||
| smart_pointer.cpp:23:30:23:50 | call to make_unique | smart_pointer.cpp:25:10:25:10 | p | |
|
||||
| smart_pointer.cpp:23:52:23:57 | call to source | smart_pointer.cpp:23:30:23:50 | call to make_unique | TAINT |
|
||||
| smart_pointer.cpp:24:11:24:11 | p | smart_pointer.cpp:24:10:24:10 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:30:11:30:11 | p | |
|
||||
| smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:31:10:31:10 | p | |
|
||||
| smart_pointer.cpp:30:11:30:11 | p | smart_pointer.cpp:30:10:30:10 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:37:6:37:6 | p | |
|
||||
| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:38:10:38:10 | p | |
|
||||
| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:39:11:39:11 | p | |
|
||||
| smart_pointer.cpp:37:5:37:17 | ... = ... | smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | |
|
||||
| smart_pointer.cpp:37:6:37:6 | p | smart_pointer.cpp:37:5:37:5 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:37:10:37:15 | call to source | smart_pointer.cpp:37:5:37:17 | ... = ... | |
|
||||
| smart_pointer.cpp:38:10:38:10 | ref arg p | smart_pointer.cpp:39:11:39:11 | p | |
|
||||
| smart_pointer.cpp:39:11:39:11 | p | smart_pointer.cpp:39:10:39:10 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:45:6:45:6 | p | |
|
||||
| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:46:10:46:10 | p | |
|
||||
| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:47:11:47:11 | p | |
|
||||
| smart_pointer.cpp:45:5:45:17 | ... = ... | smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | |
|
||||
| smart_pointer.cpp:45:6:45:6 | p | smart_pointer.cpp:45:5:45:5 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:45:10:45:15 | call to source | smart_pointer.cpp:45:5:45:17 | ... = ... | |
|
||||
| smart_pointer.cpp:46:10:46:10 | ref arg p | smart_pointer.cpp:47:11:47:11 | p | |
|
||||
| smart_pointer.cpp:47:11:47:11 | p | smart_pointer.cpp:47:10:47:10 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:51:30:51:50 | call to make_shared | smart_pointer.cpp:52:10:52:10 | p | |
|
||||
| smart_pointer.cpp:51:52:51:57 | call to source | smart_pointer.cpp:51:30:51:50 | call to make_shared | TAINT |
|
||||
| smart_pointer.cpp:52:10:52:10 | p | smart_pointer.cpp:52:12:52:14 | call to get | TAINT |
|
||||
| smart_pointer.cpp:56:30:56:50 | call to make_unique | smart_pointer.cpp:57:10:57:10 | p | |
|
||||
| smart_pointer.cpp:56:52:56:57 | call to source | smart_pointer.cpp:56:30:56:50 | call to make_unique | TAINT |
|
||||
| smart_pointer.cpp:57:10:57:10 | p | smart_pointer.cpp:57:12:57:14 | call to get | TAINT |
|
||||
| smart_pointer.cpp:65:28:65:46 | call to make_unique | smart_pointer.cpp:66:10:66:10 | p | |
|
||||
| smart_pointer.cpp:65:28:65:46 | call to make_unique | smart_pointer.cpp:67:10:67:10 | p | |
|
||||
| smart_pointer.cpp:65:48:65:53 | call to source | smart_pointer.cpp:65:28:65:46 | call to make_unique | TAINT |
|
||||
| smart_pointer.cpp:65:58:65:58 | 0 | smart_pointer.cpp:65:28:65:46 | call to make_unique | TAINT |
|
||||
| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:40:11:40:17 | source1 | |
|
||||
| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:41:12:41:18 | source1 | |
|
||||
| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:42:14:42:20 | source1 | |
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "stl.h"
|
||||
|
||||
int source();
|
||||
void sink(int);
|
||||
void sink(int*);
|
||||
|
||||
template<typename T> void sink(std::shared_ptr<T>&);
|
||||
template<typename T> void sink(std::unique_ptr<T>&);
|
||||
|
||||
void test_make_shared() {
|
||||
std::shared_ptr<int> p = std::make_shared<int>(source());
|
||||
sink(*p); // tainted
|
||||
sink(p); // tainted
|
||||
}
|
||||
|
||||
void test_make_shared_array() {
|
||||
std::shared_ptr<int[]> p = std::make_shared<int[]>(source());
|
||||
sink(*p); // not tainted
|
||||
sink(p); // not tainted
|
||||
}
|
||||
|
||||
void test_make_unique() {
|
||||
std::unique_ptr<int> p = std::make_unique<int>(source());
|
||||
sink(*p); // tainted
|
||||
sink(p); // tainted
|
||||
}
|
||||
|
||||
void test_make_unique_array() {
|
||||
std::unique_ptr<int[]> p = std::make_unique<int[]>(source());
|
||||
sink(*p); // not tainted
|
||||
sink(p); // not tainted
|
||||
}
|
||||
|
||||
void test_reverse_taint_shared() {
|
||||
std::shared_ptr<int> p = std::make_shared<int>();
|
||||
|
||||
*p = source();
|
||||
sink(p); // tainted [NOT DETECTED]
|
||||
sink(*p); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_reverse_taint_unique() {
|
||||
std::unique_ptr<int> p = std::unique_ptr<int>();
|
||||
|
||||
*p = source();
|
||||
sink(p); // tainted [NOT DETECTED]
|
||||
sink(*p); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_shared_get() {
|
||||
std::shared_ptr<int> p = std::make_shared<int>(source());
|
||||
sink(p.get()); // tainted
|
||||
}
|
||||
|
||||
void test_unique_get() {
|
||||
std::unique_ptr<int> p = std::make_unique<int>(source());
|
||||
sink(p.get()); // tainted
|
||||
}
|
||||
|
||||
struct A {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
void test_shared_field_member() {
|
||||
std::unique_ptr<A> p = std::make_unique<A>(source(), 0);
|
||||
sink(p->x); // tainted [NOT DETECTED]
|
||||
sink(p->y); // not tainted
|
||||
}
|
||||
@@ -249,3 +249,43 @@ namespace std {
|
||||
void clear() noexcept;
|
||||
};
|
||||
}
|
||||
|
||||
// --- make_shared / make_unique ---
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
class shared_ptr {
|
||||
public:
|
||||
shared_ptr() noexcept;
|
||||
explicit shared_ptr(T*);
|
||||
template<class U> shared_ptr(const shared_ptr<U>&) noexcept;
|
||||
template<class U> shared_ptr(shared_ptr<U>&&) noexcept;
|
||||
|
||||
shared_ptr<T>& operator=(const shared_ptr<T>&) noexcept;
|
||||
shared_ptr<T>& operator=(shared_ptr<T>&&) noexcept;
|
||||
|
||||
T& operator*() const noexcept;
|
||||
T* operator->() const noexcept;
|
||||
|
||||
T* get() const noexcept;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class unique_ptr {
|
||||
public:
|
||||
constexpr unique_ptr() noexcept;
|
||||
explicit unique_ptr(T*) noexcept;
|
||||
unique_ptr(unique_ptr<T>&&) noexcept;
|
||||
|
||||
unique_ptr<T>& operator=(unique_ptr<T>&&) noexcept;
|
||||
|
||||
T& operator*() const;
|
||||
T* operator->() const noexcept;
|
||||
|
||||
T* get() const noexcept;
|
||||
};
|
||||
|
||||
template<typename T, class... Args> unique_ptr<T> make_unique(Args&&...);
|
||||
|
||||
template<typename T, class... Args> shared_ptr<T> make_shared(Args&&...);
|
||||
}
|
||||
@@ -37,6 +37,12 @@
|
||||
| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source |
|
||||
| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source |
|
||||
| movableclass.cpp:65:11:65:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source |
|
||||
| smart_pointer.cpp:12:10:12:10 | call to operator* | smart_pointer.cpp:11:52:11:57 | call to source |
|
||||
| smart_pointer.cpp:13:10:13:10 | p | smart_pointer.cpp:11:52:11:57 | call to source |
|
||||
| smart_pointer.cpp:24:10:24:10 | call to operator* | smart_pointer.cpp:23:52:23:57 | call to source |
|
||||
| smart_pointer.cpp:25:10:25:10 | p | smart_pointer.cpp:23:52:23:57 | call to source |
|
||||
| smart_pointer.cpp:52:12:52:14 | call to get | smart_pointer.cpp:51:52:51:57 | call to source |
|
||||
| smart_pointer.cpp:57:12:57:14 | call to get | smart_pointer.cpp:56:52:56:57 | call to source |
|
||||
| standalone_iterators.cpp:40:10:40:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
|
||||
| standalone_iterators.cpp:41:10:41:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
|
||||
| standalone_iterators.cpp:42:10:42:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
|
||||
|
||||
@@ -38,6 +38,12 @@
|
||||
| format.cpp:115:8:115:13 | format.cpp:114:37:114:50 | AST only |
|
||||
| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only |
|
||||
| movableclass.cpp:65:11:65:21 | movableclass.cpp:65:13:65:18 | IR only |
|
||||
| smart_pointer.cpp:12:10:12:10 | smart_pointer.cpp:11:52:11:57 | AST only |
|
||||
| smart_pointer.cpp:13:10:13:10 | smart_pointer.cpp:11:52:11:57 | AST only |
|
||||
| smart_pointer.cpp:24:10:24:10 | smart_pointer.cpp:23:52:23:57 | AST only |
|
||||
| smart_pointer.cpp:25:10:25:10 | smart_pointer.cpp:23:52:23:57 | AST only |
|
||||
| smart_pointer.cpp:52:12:52:14 | smart_pointer.cpp:51:52:51:57 | AST only |
|
||||
| smart_pointer.cpp:57:12:57:14 | smart_pointer.cpp:56:52:56:57 | AST only |
|
||||
| standalone_iterators.cpp:40:10:40:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
|
||||
| standalone_iterators.cpp:41:10:41:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
|
||||
| standalone_iterators.cpp:42:10:42:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
|
||||
|
||||
@@ -540,7 +540,7 @@
|
||||
| test.c:548:9:548:9 | n | 0 |
|
||||
| test.c:551:8:551:8 | n | 0 |
|
||||
| test.c:552:9:552:9 | n | 0 |
|
||||
| test.c:554:9:554:9 | n | 0 |
|
||||
| test.c:554:9:554:9 | n | 1 |
|
||||
| test.c:557:10:557:10 | n | 0 |
|
||||
| test.c:558:5:558:5 | n | 1 |
|
||||
| test.c:561:7:561:7 | n | 0 |
|
||||
@@ -549,7 +549,7 @@
|
||||
| test.c:569:9:569:9 | n | 0 |
|
||||
| test.c:571:9:571:9 | n | 1 |
|
||||
| test.c:574:7:574:7 | n | 0 |
|
||||
| test.c:575:9:575:9 | n | 0 |
|
||||
| test.c:575:9:575:9 | n | 1 |
|
||||
| test.c:577:9:577:9 | n | 0 |
|
||||
| test.c:580:10:580:10 | n | 0 |
|
||||
| test.c:581:5:581:5 | n | 1 |
|
||||
@@ -563,6 +563,25 @@
|
||||
| test.c:601:7:601:7 | n | -32768 |
|
||||
| test.c:601:22:601:22 | n | -32767 |
|
||||
| test.c:602:9:602:9 | n | -32766 |
|
||||
| test.c:605:7:605:7 | n | -32768 |
|
||||
| test.c:606:5:606:5 | n | 0 |
|
||||
| test.c:606:10:606:10 | n | 1 |
|
||||
| test.c:606:14:606:14 | n | 0 |
|
||||
| test.c:607:6:607:6 | n | 0 |
|
||||
| test.c:607:10:607:10 | n | 0 |
|
||||
| test.c:607:14:607:14 | n | 1 |
|
||||
| test.c:618:7:618:8 | ss | -32768 |
|
||||
| test.c:619:9:619:10 | ss | 0 |
|
||||
| test.c:622:7:622:8 | ss | -32768 |
|
||||
| test.c:623:9:623:10 | ss | -32768 |
|
||||
| test.c:626:14:626:15 | us | 0 |
|
||||
| test.c:627:9:627:10 | us | 0 |
|
||||
| test.c:630:14:630:15 | us | 0 |
|
||||
| test.c:631:9:631:10 | us | 0 |
|
||||
| test.c:634:7:634:8 | ss | -32768 |
|
||||
| test.c:635:9:635:10 | ss | -32768 |
|
||||
| test.c:638:7:638:8 | ss | -32768 |
|
||||
| test.c:639:9:639:10 | ss | -1 |
|
||||
| test.cpp:10:7:10:7 | b | -2147483648 |
|
||||
| test.cpp:11:5:11:5 | x | -2147483648 |
|
||||
| test.cpp:13:10:13:10 | x | -2147483648 |
|
||||
@@ -616,3 +635,16 @@
|
||||
| test.cpp:97:10:97:10 | i | -2147483648 |
|
||||
| test.cpp:97:22:97:22 | i | -2147483648 |
|
||||
| test.cpp:98:5:98:5 | i | -2147483648 |
|
||||
| test.cpp:105:7:105:7 | n | -32768 |
|
||||
| test.cpp:108:7:108:7 | n | 0 |
|
||||
| test.cpp:109:5:109:5 | n | 1 |
|
||||
| test.cpp:111:5:111:5 | n | 0 |
|
||||
| test.cpp:114:8:114:8 | n | 0 |
|
||||
| test.cpp:115:5:115:5 | n | 0 |
|
||||
| test.cpp:117:5:117:5 | n | 1 |
|
||||
| test.cpp:120:3:120:3 | n | 0 |
|
||||
| test.cpp:120:8:120:8 | n | 1 |
|
||||
| test.cpp:120:12:120:12 | n | 0 |
|
||||
| test.cpp:121:4:121:4 | n | 0 |
|
||||
| test.cpp:121:8:121:8 | n | 0 |
|
||||
| test.cpp:121:12:121:12 | n | 1 |
|
||||
|
||||
@@ -13,3 +13,7 @@
|
||||
| test.c:386:10:386:21 | ... ? ... : ... | 100.0 | 100.0 | 5.0 |
|
||||
| test.c:387:10:387:38 | ... ? ... : ... | 0.0 | 100.0 | 5.0 |
|
||||
| test.c:394:20:394:36 | ... ? ... : ... | 0.0 | 0.0 | 100.0 |
|
||||
| test.c:606:5:606:14 | ... ? ... : ... | 0.0 | 1.0 | 0.0 |
|
||||
| test.c:607:5:607:14 | ... ? ... : ... | 0.0 | 0.0 | 1.0 |
|
||||
| test.cpp:120:3:120:12 | ... ? ... : ... | 0.0 | 1.0 | 0.0 |
|
||||
| test.cpp:121:3:121:12 | ... ? ... : ... | 0.0 | 0.0 | 1.0 |
|
||||
|
||||
@@ -13,3 +13,7 @@
|
||||
| test.c:386:10:386:21 | ... ? ... : ... | 4.294967295E9 | 4.294967295E9 | 5.0 |
|
||||
| test.c:387:10:387:38 | ... ? ... : ... | 255.0 | 4.294967295E9 | 5.0 |
|
||||
| test.c:394:20:394:36 | ... ? ... : ... | 100.0 | 99.0 | 100.0 |
|
||||
| test.c:606:5:606:14 | ... ? ... : ... | 32767.0 | 32767.0 | 0.0 |
|
||||
| test.c:607:5:607:14 | ... ? ... : ... | 32767.0 | 0.0 | 32767.0 |
|
||||
| test.cpp:120:3:120:12 | ... ? ... : ... | 32767.0 | 32767.0 | 0.0 |
|
||||
| test.cpp:121:3:121:12 | ... ? ... : ... | 32767.0 | 0.0 | 32767.0 |
|
||||
|
||||
@@ -551,7 +551,7 @@ int notequal_type_endpoint(unsigned n) {
|
||||
if (!n) {
|
||||
out(n); // 0 .. 0
|
||||
} else {
|
||||
out(n); // 1 .. [BUG: lower bound is deduced to be 0]
|
||||
out(n); // 1 ..
|
||||
}
|
||||
|
||||
while (n != 0) {
|
||||
@@ -572,7 +572,7 @@ void notequal_refinement(short n) {
|
||||
}
|
||||
|
||||
if (n) {
|
||||
out(n); // 1 .. [BUG: lower bound is deduced to be 0]
|
||||
out(n); // 1 ..
|
||||
} else {
|
||||
out(n); // 0 .. 0
|
||||
}
|
||||
@@ -601,4 +601,41 @@ void notequal_variations(short n, float f) {
|
||||
if (n != -32768 && n != -32767) {
|
||||
out(n); // -32766 ..
|
||||
}
|
||||
|
||||
if (n >= 0) {
|
||||
n ? n : n; // ? 1.. : 0..0
|
||||
!n ? n : n; // ? 0..0 : 1..
|
||||
}
|
||||
}
|
||||
|
||||
void two_bounds_from_one_test(short ss, unsigned short us) {
|
||||
// These tests demonstrate how the range analysis is often able to deduce
|
||||
// both an upper bound and a lower bound even when there is only one
|
||||
// inequality in the source. For example `signedInt < 4U` establishes that
|
||||
// `signedInt >= 0` since if `signedInt` were negative then it would be
|
||||
// greater than 4 in the unsigned comparison.
|
||||
|
||||
if (ss < sizeof(int)) { // Lower bound added in `linearBoundFromGuard`
|
||||
out(ss); // 0 .. 3
|
||||
}
|
||||
|
||||
if (ss < 0x8001) { // Lower bound removed in `getDefLowerBounds`
|
||||
out(ss); // -32768 .. 32767
|
||||
}
|
||||
|
||||
if ((short)us >= 0) {
|
||||
out(us); // 0 .. 32767
|
||||
}
|
||||
|
||||
if ((short)us >= -1) {
|
||||
out(us); // 0 .. 65535
|
||||
}
|
||||
|
||||
if (ss >= sizeof(int)) { // test is true for negative numbers
|
||||
out(ss); // -32768 .. 32767
|
||||
}
|
||||
|
||||
if (ss + 1 < sizeof(int)) {
|
||||
out(ss); // -1 .. 2
|
||||
}
|
||||
}
|
||||
@@ -100,3 +100,23 @@ int ref_to_number(int &i, const int &ci, int &aliased) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void notequal_refinement(short n) {
|
||||
if (n < 0)
|
||||
return;
|
||||
|
||||
if (n) {
|
||||
n; // 1 ..
|
||||
} else {
|
||||
n; // 0 .. 0
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
n; // 0 .. 0
|
||||
} else {
|
||||
n; // 1 ..
|
||||
}
|
||||
|
||||
n ? n : n; // ? 1.. : 0..0
|
||||
!n ? n : n; // ? 0..0 : 1..
|
||||
}
|
||||
|
||||
@@ -539,7 +539,7 @@
|
||||
| test.c:546:9:546:9 | n | 4294967295 |
|
||||
| test.c:548:9:548:9 | n | 0 |
|
||||
| test.c:551:8:551:8 | n | 4294967295 |
|
||||
| test.c:552:9:552:9 | n | 4294967295 |
|
||||
| test.c:552:9:552:9 | n | 0 |
|
||||
| test.c:554:9:554:9 | n | 4294967295 |
|
||||
| test.c:557:10:557:10 | n | 4294967295 |
|
||||
| test.c:558:5:558:5 | n | 4294967295 |
|
||||
@@ -550,7 +550,7 @@
|
||||
| test.c:571:9:571:9 | n | 32767 |
|
||||
| test.c:574:7:574:7 | n | 32767 |
|
||||
| test.c:575:9:575:9 | n | 32767 |
|
||||
| test.c:577:9:577:9 | n | 32767 |
|
||||
| test.c:577:9:577:9 | n | 0 |
|
||||
| test.c:580:10:580:10 | n | 32767 |
|
||||
| test.c:581:5:581:5 | n | 32767 |
|
||||
| test.c:584:7:584:7 | n | 0 |
|
||||
@@ -563,6 +563,25 @@
|
||||
| test.c:601:7:601:7 | n | 32767 |
|
||||
| test.c:601:22:601:22 | n | 32767 |
|
||||
| test.c:602:9:602:9 | n | 32767 |
|
||||
| test.c:605:7:605:7 | n | 32767 |
|
||||
| test.c:606:5:606:5 | n | 32767 |
|
||||
| test.c:606:10:606:10 | n | 32767 |
|
||||
| test.c:606:14:606:14 | n | 0 |
|
||||
| test.c:607:6:607:6 | n | 32767 |
|
||||
| test.c:607:10:607:10 | n | 0 |
|
||||
| test.c:607:14:607:14 | n | 32767 |
|
||||
| test.c:618:7:618:8 | ss | 32767 |
|
||||
| test.c:619:9:619:10 | ss | 3 |
|
||||
| test.c:622:7:622:8 | ss | 32767 |
|
||||
| test.c:623:9:623:10 | ss | 32767 |
|
||||
| test.c:626:14:626:15 | us | 65535 |
|
||||
| test.c:627:9:627:10 | us | 32767 |
|
||||
| test.c:630:14:630:15 | us | 65535 |
|
||||
| test.c:631:9:631:10 | us | 65535 |
|
||||
| test.c:634:7:634:8 | ss | 32767 |
|
||||
| test.c:635:9:635:10 | ss | 32767 |
|
||||
| test.c:638:7:638:8 | ss | 32767 |
|
||||
| test.c:639:9:639:10 | ss | 2 |
|
||||
| test.cpp:10:7:10:7 | b | 2147483647 |
|
||||
| test.cpp:11:5:11:5 | x | 2147483647 |
|
||||
| test.cpp:13:10:13:10 | x | 2147483647 |
|
||||
@@ -616,3 +635,16 @@
|
||||
| test.cpp:97:10:97:10 | i | 65535 |
|
||||
| test.cpp:97:22:97:22 | i | 32767 |
|
||||
| test.cpp:98:5:98:5 | i | 32767 |
|
||||
| test.cpp:105:7:105:7 | n | 32767 |
|
||||
| test.cpp:108:7:108:7 | n | 32767 |
|
||||
| test.cpp:109:5:109:5 | n | 32767 |
|
||||
| test.cpp:111:5:111:5 | n | 0 |
|
||||
| test.cpp:114:8:114:8 | n | 32767 |
|
||||
| test.cpp:115:5:115:5 | n | 0 |
|
||||
| test.cpp:117:5:117:5 | n | 32767 |
|
||||
| test.cpp:120:3:120:3 | n | 32767 |
|
||||
| test.cpp:120:8:120:8 | n | 32767 |
|
||||
| test.cpp:120:12:120:12 | n | 0 |
|
||||
| test.cpp:121:4:121:4 | n | 32767 |
|
||||
| test.cpp:121:8:121:8 | n | 0 |
|
||||
| test.cpp:121:12:121:12 | n | 32767 |
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:76:24:76:26 | p#0 | int p#0 |
|
||||
| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | p#0 | int p#0 |
|
||||
| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:76:24:76:26 | p#0 | int p#0 |
|
||||
| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | p#0 | int p#0 |
|
||||
| test.c:40:3:40:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:40:31:40:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:77:38:77:38 | x | int x |
|
||||
| test.c:44:3:44:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:80:6:80:30 | not_declared_defined_with | not_declared_defined_with | test.c:44:29:44:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:80:36:80:36 | x | int x |
|
||||
|
||||
Reference in New Issue
Block a user