mirror of
https://github.com/github/codeql.git
synced 2026-05-02 20:25:13 +02:00
Merge master into next.
master as of dc3c5a684c
Version numbers resolved in favour of `next`.
C++ expected output file updated to accept test output.
This commit is contained in:
@@ -29,6 +29,10 @@ class AffectedFile extends File {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A block, or an element we might find textually within a block that is
|
||||
* not a child of it in the AST.
|
||||
*/
|
||||
class BlockOrNonChild extends Element {
|
||||
BlockOrNonChild() {
|
||||
( this instanceof Block
|
||||
@@ -68,6 +72,9 @@ class BlockOrNonChild extends Element {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A block that contains a non-child element.
|
||||
*/
|
||||
predicate emptyBlockContainsNonchild(Block b) {
|
||||
emptyBlock(_, b) and
|
||||
exists(BlockOrNonChild c, AffectedFile file |
|
||||
@@ -78,7 +85,27 @@ predicate emptyBlockContainsNonchild(Block b) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A block that is entirely on one line, which also contains a comment. Chances
|
||||
* are the comment is intended to refer to the block.
|
||||
*/
|
||||
predicate lineComment(Block b) {
|
||||
emptyBlock(_, b) and
|
||||
exists(Location bLocation, File f, int line |
|
||||
bLocation = b.getLocation() and
|
||||
f = bLocation.getFile() and
|
||||
line = bLocation.getStartLine() and
|
||||
line = bLocation.getEndLine() and
|
||||
exists(Comment c, Location cLocation |
|
||||
cLocation = c.getLocation() and
|
||||
cLocation.getFile() = f and
|
||||
cLocation.getStartLine() = line
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from ControlStructure s, Block eb
|
||||
where emptyBlock(s, eb)
|
||||
and not emptyBlockContainsNonchild(eb)
|
||||
and not lineComment(eb)
|
||||
select eb, "Empty block without comment"
|
||||
|
||||
@@ -48,6 +48,7 @@ where exists
|
||||
ctls.getControllingExpr() = e1
|
||||
and e1.getType().(TypedefType).hasName("HRESULT")
|
||||
and not isHresultBooleanConverted(e1)
|
||||
and not ctls instanceof SwitchStmt // not controlled by a boolean condition
|
||||
and msg = "Direct usage of a type " + e1.getType().toString() + " as a conditional expression"
|
||||
)
|
||||
or
|
||||
|
||||
@@ -25,7 +25,7 @@ predicate pointerThis(Expr e) {
|
||||
// `f(...)`
|
||||
// (includes `this = ...`, where `=` is overloaded so a `FunctionCall`)
|
||||
exists(FunctionCall fc | fc = e and callOnThis(fc) |
|
||||
exists(fc.getTarget().getBlock()) implies returnsPointerThis(fc.getTarget())
|
||||
returnsPointerThis(fc.getTarget())
|
||||
) or
|
||||
|
||||
// `this = ...` (where `=` is not overloaded, so an `AssignExpr`)
|
||||
@@ -38,22 +38,33 @@ predicate dereferenceThis(Expr e) {
|
||||
// `f(...)`
|
||||
// (includes `*this = ...`, where `=` is overloaded so a `FunctionCall`)
|
||||
exists(FunctionCall fc | fc = e and callOnThis(fc) |
|
||||
exists(fc.getTarget().getBlock()) implies returnsDereferenceThis(fc.getTarget())
|
||||
returnsDereferenceThis(fc.getTarget())
|
||||
) or
|
||||
|
||||
// `*this = ...` (where `=` is not overloaded, so an `AssignExpr`)
|
||||
dereferenceThis(e.(AssignExpr).getLValue())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all `return` statements in `f` return `this`, possibly indirectly.
|
||||
* This includes functions whose body is not in the database.
|
||||
*/
|
||||
predicate returnsPointerThis(Function f) {
|
||||
forex(ReturnStmt s | s.getEnclosingFunction() = f |
|
||||
f.getType().getUnspecifiedType() instanceof PointerType and
|
||||
forall(ReturnStmt s | s.getEnclosingFunction() = f and reachable(s) |
|
||||
// `return this`
|
||||
pointerThis(s.getExpr())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all `return` statements in `f` return a reference to `*this`,
|
||||
* possibly indirectly. This includes functions whose body is not in the
|
||||
* database.
|
||||
*/
|
||||
predicate returnsDereferenceThis(Function f) {
|
||||
forex(ReturnStmt s | s.getEnclosingFunction() = f |
|
||||
f.getType().getUnspecifiedType() instanceof ReferenceType and
|
||||
forall(ReturnStmt s | s.getEnclosingFunction() = f and reachable(s) |
|
||||
// `return *this`
|
||||
dereferenceThis(s.getExpr())
|
||||
)
|
||||
@@ -72,7 +83,6 @@ predicate assignOperatorWithWrongType(Operator op, string msg) {
|
||||
predicate assignOperatorWithWrongResult(Operator op, string msg) {
|
||||
op.hasName("operator=")
|
||||
and not returnsDereferenceThis(op)
|
||||
and exists(op.getBlock())
|
||||
and not op.getType() instanceof VoidType
|
||||
and not assignOperatorWithWrongType(op, _)
|
||||
and msg = "Assignment operator in class " + op.getDeclaringType().getName() + " does not return a reference to *this."
|
||||
|
||||
@@ -1,29 +1,6 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* Holds if `sizeof(s)` occurs as part of the parameter of a dynamic
|
||||
* memory allocation (`malloc`, `realloc`, etc.), except if `sizeof(s)`
|
||||
* only ever occurs as the immediate parameter to allocations.
|
||||
*
|
||||
* For example, holds for `s` if it occurs as
|
||||
* ```
|
||||
* malloc(sizeof(s) + 100 * sizeof(char))
|
||||
* ```
|
||||
* but not if it only ever occurs as
|
||||
* ```
|
||||
* malloc(sizeof(s))
|
||||
* ```
|
||||
*/
|
||||
private predicate isDynamicallyAllocatedWithDifferentSize(Class s) {
|
||||
exists(SizeofTypeOperator sof |
|
||||
sof.getTypeOperand().getUnspecifiedType() = s |
|
||||
// Check all ancestor nodes except the immediate parent for
|
||||
// allocations.
|
||||
isStdLibAllocationExpr(sof.getParent().(Expr).getParent+())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is a member variable of `c` that looks like it might be variable sized in practice. For
|
||||
* example:
|
||||
@@ -34,15 +11,40 @@ private predicate isDynamicallyAllocatedWithDifferentSize(Class s) {
|
||||
* };
|
||||
* ```
|
||||
* This requires that `v` is an array of size 0 or 1, and `v` is the last member of `c`. In addition,
|
||||
* there must be at least one instance where a `c` pointer is allocated with additional space.
|
||||
* there must be at least one instance where a `c` pointer is allocated with additional space. For
|
||||
* example, holds for `c` if it occurs as
|
||||
* ```
|
||||
* malloc(sizeof(c) + 100 * sizeof(char))
|
||||
* ```
|
||||
* but not if it only ever occurs as
|
||||
* ```
|
||||
* malloc(sizeof(c))
|
||||
* ```
|
||||
*/
|
||||
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
||||
exists(int i |
|
||||
// `v` is the last field in `c`
|
||||
i = max(int j | c.getCanonicalMember(j) instanceof Field | j) and
|
||||
v = c.getCanonicalMember(i) and
|
||||
v.getType().getUnspecifiedType().(ArrayType).getSize() <= 1
|
||||
) and
|
||||
isDynamicallyAllocatedWithDifferentSize(c)
|
||||
|
||||
// v is an array of size at most 1
|
||||
v.getType().getUnspecifiedType().(ArrayType).getArraySize() <= 1
|
||||
) and (
|
||||
exists(SizeofOperator so |
|
||||
// `sizeof(c)` is taken
|
||||
so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or
|
||||
so.(SizeofExprOperator).getExprOperand().getType().getUnspecifiedType() = c |
|
||||
|
||||
// arithmetic is performed on the result
|
||||
so.getParent*() instanceof AddExpr
|
||||
) or exists(AddressOfExpr aoe |
|
||||
// `&(c.v)` is taken
|
||||
aoe.getAddressable() = v
|
||||
) or exists(BuiltInOperationOffsetOf oo |
|
||||
// `offsetof(c, v)` using a builtin
|
||||
oo.getAChild().(VariableAccess).getTarget() = v
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,19 +83,21 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
// buffer is a fixed size dynamic allocation
|
||||
isFixedSizeAllocationExpr(bufferExpr, result) and
|
||||
why = bufferExpr
|
||||
) or (
|
||||
) or exists(DataFlow::ExprNode bufferExprNode |
|
||||
// dataflow (all sources must be the same size)
|
||||
bufferExprNode = DataFlow::exprNode(bufferExpr) and
|
||||
|
||||
result = min(Expr def |
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(def), DataFlow::exprNode(bufferExpr)) |
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(def), bufferExprNode) |
|
||||
getBufferSize(def, _)
|
||||
) and result = max(Expr def |
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(def), DataFlow::exprNode(bufferExpr)) |
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(def), bufferExprNode) |
|
||||
getBufferSize(def, _)
|
||||
) and
|
||||
|
||||
// find reason
|
||||
exists(Expr def |
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(def), DataFlow::exprNode(bufferExpr)) |
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(def), bufferExprNode) |
|
||||
why = def or
|
||||
exists(getBufferSize(def, why))
|
||||
)
|
||||
|
||||
@@ -124,11 +124,17 @@ cached library class SSAHelper extends int {
|
||||
* Modern Compiler Implementation by Andrew Appel.
|
||||
*/
|
||||
private predicate frontier_phi_node(LocalScopeVariable v, BasicBlock b) {
|
||||
exists(BasicBlock x | dominanceFrontier(x, b) and ssa_defn(v, _, x, _))
|
||||
exists(BasicBlock x | dominanceFrontier(x, b) and ssa_defn_rec(v, x))
|
||||
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
||||
and live_at_start_of_bb(v, b)
|
||||
}
|
||||
|
||||
private predicate ssa_defn_rec(LocalScopeVariable v, BasicBlock b) {
|
||||
phi_node(v, b)
|
||||
or
|
||||
variableUpdate(v, _, b, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is defined, for the purpose of SSA, at `node`, which is at
|
||||
* position `index` in block `b`. This includes definitions from phi nodes.
|
||||
|
||||
@@ -293,6 +293,61 @@ predicate analyzableDef(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
assignmentDef(def, v, _) or defDependsOnDef(def, v, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a normal form of `x` where -0.0 has changed to +0.0. This can be
|
||||
* needed on the lesser side of a floating-point comparison or on both sides of
|
||||
* a floating point equality because QL does not follow IEEE in floating-point
|
||||
* comparisons but instead defines -0.0 to be less than and distinct from 0.0.
|
||||
*/
|
||||
bindingset[x]
|
||||
private float normalizeFloatUp(float x) {
|
||||
result = x + 0.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes `x + y`, rounded towards +Inf. This is the general case where both
|
||||
* `x` and `y` may be large numbers.
|
||||
*/
|
||||
bindingset[x, y]
|
||||
private float addRoundingUp(float x, float y) {
|
||||
if normalizeFloatUp((x + y) - x) < y or normalizeFloatUp((x + y) - y) < x
|
||||
then result = (x + y).nextUp()
|
||||
else result = (x + y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes `x + y`, rounded towards -Inf. This is the general case where both
|
||||
* `x` and `y` may be large numbers.
|
||||
*/
|
||||
bindingset[x, y]
|
||||
private float addRoundingDown(float x, float y) {
|
||||
if (x + y) - x > normalizeFloatUp(y) or (x + y) - y > normalizeFloatUp(x)
|
||||
then result = (x + y).nextDown()
|
||||
else result = (x + y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes `x + small`, rounded towards +Inf, where `small` is a small
|
||||
* constant.
|
||||
*/
|
||||
bindingset[x, small]
|
||||
private float addRoundingUpSmall(float x, float small) {
|
||||
if (x + small) - x < small
|
||||
then result = (x + small).nextUp()
|
||||
else result = (x + small)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes `x + small`, rounded towards -Inf, where `small` is a small
|
||||
* constant.
|
||||
*/
|
||||
bindingset[x, small]
|
||||
private float addRoundingDownSmall(float x, float small) {
|
||||
if (x + small) - x > small
|
||||
then result = (x + small).nextDown()
|
||||
else result = (x + small)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the truncated lower bounds of the fully converted expression.
|
||||
*/
|
||||
@@ -470,13 +525,13 @@ float getLowerBoundsImpl(Expr expr) {
|
||||
| expr = addExpr and
|
||||
xLow = getFullyConvertedLowerBounds(addExpr.getLeftOperand()) and
|
||||
yLow = getFullyConvertedLowerBounds(addExpr.getRightOperand()) and
|
||||
result = xLow+yLow)
|
||||
result = addRoundingDown(xLow, yLow))
|
||||
or
|
||||
exists (SubExpr subExpr, float xLow, float yHigh
|
||||
| expr = subExpr and
|
||||
xLow = getFullyConvertedLowerBounds(subExpr.getLeftOperand()) and
|
||||
yHigh = getFullyConvertedUpperBounds(subExpr.getRightOperand()) and
|
||||
result = xLow-yHigh)
|
||||
result = addRoundingDown(xLow, -yHigh))
|
||||
or
|
||||
exists (PrefixIncrExpr incrExpr, float xLow
|
||||
| expr = incrExpr and
|
||||
@@ -486,7 +541,7 @@ float getLowerBoundsImpl(Expr expr) {
|
||||
exists (PrefixDecrExpr decrExpr, float xLow
|
||||
| expr = decrExpr and
|
||||
xLow = getFullyConvertedLowerBounds(decrExpr.getOperand()) and
|
||||
result = xLow-1)
|
||||
result = addRoundingDownSmall(xLow, -1))
|
||||
or
|
||||
// `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their
|
||||
// operand. The incrementing/decrementing behavior is handled in
|
||||
@@ -592,18 +647,18 @@ float getUpperBoundsImpl(Expr expr) {
|
||||
| expr = addExpr and
|
||||
xHigh = getFullyConvertedUpperBounds(addExpr.getLeftOperand()) and
|
||||
yHigh = getFullyConvertedUpperBounds(addExpr.getRightOperand()) and
|
||||
result = xHigh+yHigh)
|
||||
result = addRoundingUp(xHigh, yHigh))
|
||||
or
|
||||
exists (SubExpr subExpr, float xHigh, float yLow
|
||||
| expr = subExpr and
|
||||
xHigh = getFullyConvertedUpperBounds(subExpr.getLeftOperand()) and
|
||||
yLow = getFullyConvertedLowerBounds(subExpr.getRightOperand()) and
|
||||
result = xHigh-yLow)
|
||||
result = addRoundingUp(xHigh, -yLow))
|
||||
or
|
||||
exists (PrefixIncrExpr incrExpr, float xHigh
|
||||
| expr = incrExpr and
|
||||
xHigh = getFullyConvertedUpperBounds(incrExpr.getOperand()) and
|
||||
result = xHigh+1)
|
||||
result = addRoundingUpSmall(xHigh, 1))
|
||||
or
|
||||
exists (PrefixDecrExpr decrExpr, float xHigh
|
||||
| expr = decrExpr and
|
||||
@@ -796,7 +851,7 @@ float getDefLowerBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
assignAdd.getLValue() = nextDef.getAUse(v) and
|
||||
lhsLB = getDefLowerBounds(nextDef, v) and
|
||||
rhsLB = getFullyConvertedLowerBounds(assignAdd.getRValue()) and
|
||||
result = lhsLB + rhsLB)
|
||||
result = addRoundingDown(lhsLB, rhsLB))
|
||||
or
|
||||
exists (
|
||||
AssignSubExpr assignSub, RangeSsaDefinition nextDef, float lhsLB, float rhsUB
|
||||
@@ -804,7 +859,7 @@ float getDefLowerBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
assignSub.getLValue() = nextDef.getAUse(v) and
|
||||
lhsLB = getDefLowerBounds(nextDef, v) and
|
||||
rhsUB = getFullyConvertedUpperBounds(assignSub.getRValue()) and
|
||||
result = lhsLB - rhsUB)
|
||||
result = addRoundingDown(lhsLB, -rhsUB))
|
||||
or
|
||||
exists (IncrementOperation incr, float newLB
|
||||
| def = incr and
|
||||
@@ -816,7 +871,7 @@ float getDefLowerBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
| def = decr and
|
||||
decr.getOperand() = v.getAnAccess() and
|
||||
newLB = getFullyConvertedLowerBounds(decr.getOperand()) and
|
||||
result = newLB-1)
|
||||
result = addRoundingDownSmall(newLB, -1))
|
||||
or
|
||||
// Phi nodes.
|
||||
result = getPhiLowerBounds(v, def)
|
||||
@@ -839,7 +894,7 @@ float getDefUpperBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
assignAdd.getLValue() = nextDef.getAUse(v) and
|
||||
lhsUB = getDefUpperBounds(nextDef, v) and
|
||||
rhsUB = getFullyConvertedUpperBounds(assignAdd.getRValue()) and
|
||||
result = lhsUB + rhsUB)
|
||||
result = addRoundingUp(lhsUB, rhsUB))
|
||||
or
|
||||
exists (
|
||||
AssignSubExpr assignSub, RangeSsaDefinition nextDef, float lhsUB, float rhsLB
|
||||
@@ -847,13 +902,13 @@ float getDefUpperBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
assignSub.getLValue() = nextDef.getAUse(v) and
|
||||
lhsUB = getDefUpperBounds(nextDef, v) and
|
||||
rhsLB = getFullyConvertedLowerBounds(assignSub.getRValue()) and
|
||||
result = lhsUB - rhsLB)
|
||||
result = addRoundingUp(lhsUB, -rhsLB))
|
||||
or
|
||||
exists (IncrementOperation incr, float newUB
|
||||
| def = incr and
|
||||
incr.getOperand() = v.getAnAccess() and
|
||||
newUB = getFullyConvertedUpperBounds(incr.getOperand()) and
|
||||
result = newUB+1)
|
||||
result = addRoundingUpSmall(newUB, 1))
|
||||
or
|
||||
exists (DecrementOperation decr, float newUB
|
||||
| def = decr and
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
| copy_from_prototype.cpp:3:7:3:7 | a | a<int>::a(a<int> &&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:3:7:3:7 | a | a<int>::a(const a<int> &) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>::operator=(a<int> &&) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>::operator=(const a<int> &) | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:4:26:4:26 | a | a<<unnamed>>::a<(unnamed)>() | copy_from_prototype.cpp:3:7:3:7 | a<<unnamed>> | 123 |
|
||||
| copy_from_prototype.cpp:4:26:4:26 | a | a<int>::a<(unnamed)>() | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | b | b::b() | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | b | b::b(b &&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | b | b::b(const b &) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | operator= | b::operator=(b &&) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | operator= | b::operator=(const b &) | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:13:7:13:7 | c | c<int>::c(c<int> &&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:13:7:13:7 | c | c<int>::c(const c<int> &) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(c<int> &&) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(const c<int> &) | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:14:26:14:26 | c | c<T>::c<(unnamed)>() | copy_from_prototype.cpp:13:7:13:7 | c<T> | Unknown literal |
|
||||
| copy_from_prototype.cpp:14:26:14:26 | c | c<int>::c<(unnamed)>() | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | d | d::d() | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | d | d::d(const d &) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | d | d::d(d &&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | operator= | d::operator=(const d &) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | operator= | d::operator=(d &&) | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:22:8:22:8 | e | e<int>::e(const e<int> &) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:22:8:22:8 | e | e<int>::e(e<int> &&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>::operator=(const e<int> &) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>::operator=(e<int> &&) | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:23:26:23:26 | e | e<T>::e<(unnamed)>() | copy_from_prototype.cpp:22:8:22:8 | e<T> | 456 |
|
||||
| copy_from_prototype.cpp:26:35:26:43 | e | e<int>::e<(unnamed)>() | copy_from_prototype.cpp:22:8:22:8 | e<int> | 456 |
|
||||
| file://:0:0:0:0 | operator= | __va_list_tag::operator=(__va_list_tag &&) | file://:0:0:0:0 | __va_list_tag | <none> |
|
||||
| file://:0:0:0:0 | operator= | __va_list_tag::operator=(const __va_list_tag &) | file://:0:0:0:0 | __va_list_tag | <none> |
|
||||
| copy_from_prototype.cpp:3:7:3:7 | a | a<int>::a(a<int> &&) -> void | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:3:7:3:7 | a | a<int>::a(const a<int> &) -> void | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>::operator=(a<int> &&) -> a<int> & | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:3:7:3:7 | operator= | a<int>::operator=(const a<int> &) -> a<int> & | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:4:26:4:26 | a | a<<unnamed>>::a<(unnamed)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a<<unnamed>> | 123 |
|
||||
| copy_from_prototype.cpp:4:26:4:26 | a | a<int>::a<(unnamed)>() -> void | copy_from_prototype.cpp:3:7:3:7 | a<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | b | b::b() -> void | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | b | b::b(b &&) -> void | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | b | b::b(const b &) -> void | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | operator= | b::operator=(b &&) -> b & | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:7:7:7:7 | operator= | b::operator=(const b &) -> b & | copy_from_prototype.cpp:7:7:7:7 | b | <no expr> |
|
||||
| copy_from_prototype.cpp:13:7:13:7 | c | c<int>::c(c<int> &&) -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:13:7:13:7 | c | c<int>::c(const c<int> &) -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(c<int> &&) -> c<int> & | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:13:7:13:7 | operator= | c<int>::operator=(const c<int> &) -> c<int> & | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:14:26:14:26 | c | c<T>::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c<T> | Unknown literal |
|
||||
| copy_from_prototype.cpp:14:26:14:26 | c | c<int>::c<(unnamed)>() -> void | copy_from_prototype.cpp:13:7:13:7 | c<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | d | d::d() -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | d | d::d(const d &) -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | d | d::d(d &&) -> void | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | operator= | d::operator=(const d &) -> d & | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:17:7:17:7 | operator= | d::operator=(d &&) -> d & | copy_from_prototype.cpp:17:7:17:7 | d | <no expr> |
|
||||
| copy_from_prototype.cpp:22:8:22:8 | e | e<int>::e(const e<int> &) -> void | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:22:8:22:8 | e | e<int>::e(e<int> &&) -> void | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>::operator=(const e<int> &) -> e<int> & | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:22:8:22:8 | operator= | e<int>::operator=(e<int> &&) -> e<int> & | copy_from_prototype.cpp:22:8:22:8 | e<int> | <no expr> |
|
||||
| copy_from_prototype.cpp:23:26:23:26 | e | e<T>::e<(unnamed)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e<T> | 456 |
|
||||
| copy_from_prototype.cpp:26:35:26:43 | e | e<int>::e<(unnamed)>() -> void | copy_from_prototype.cpp:22:8:22:8 | e<int> | 456 |
|
||||
| file://:0:0:0:0 | operator= | __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & | file://:0:0:0:0 | __va_list_tag | <none> |
|
||||
| file://:0:0:0:0 | operator= | __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & | file://:0:0:0:0 | __va_list_tag | <none> |
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
import cpp
|
||||
|
||||
string functionName(Function f) {
|
||||
exists(string name, string templateArgs, string args |
|
||||
result = name + templateArgs + args
|
||||
and name = f.getQualifiedName()
|
||||
and if exists(f.getATemplateArgument())
|
||||
then templateArgs = "<" + concat(int i | exists(f.getTemplateArgument(i)) | f.getTemplateArgument(i).toString(), "," order by i) + ">"
|
||||
else templateArgs = ""
|
||||
and args = "(" + concat(int i | exists(f.getParameter(i)) | f.getParameter(i).getType().toString(), "," order by i) + ")")
|
||||
}
|
||||
|
||||
from Function f, string e
|
||||
where if f.hasExceptionSpecification()
|
||||
then if exists(f.getADeclarationEntry().getNoExceptExpr())
|
||||
then e = f.getADeclarationEntry().getNoExceptExpr().toString()
|
||||
else e = "<no expr>"
|
||||
else e = "<none>"
|
||||
select f, functionName(f), f.getDeclaringType(), e
|
||||
select f, f.getFullSignature(), f.getDeclaringType(), e
|
||||
|
||||
@@ -48,4 +48,10 @@ int f(int x) {
|
||||
|
||||
// GOOD (no block)
|
||||
for (;;) ;
|
||||
|
||||
// GOOD (has comment): [FALSE POSITIVE]
|
||||
if (x) {} // comment
|
||||
|
||||
// GOOD (has comment): [FALSE POSITIVE]
|
||||
if (x) {} // comment
|
||||
}
|
||||
|
||||
@@ -57,3 +57,12 @@ static int foo(size_t *size)
|
||||
if (*size <= MAX_VAL) // BAD (pointless comparison) [NO LONGER REPORTED]
|
||||
*size = MAX_VAL;
|
||||
}
|
||||
|
||||
// ODASA-7205
|
||||
int regression_test_01(unsigned long bb) {
|
||||
if (bb + 1 == 0) { // GOOD [NO LONGER REPORTED]
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,4 +97,26 @@ void IncorrectTypeConversionTest() {
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
if (HresultFunction() == S_FALSE) // Correct Usage
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
while (!HresultFunction()) {}; // BUG
|
||||
while (FAILED(HresultFunction())) {}; // Correct Usage
|
||||
|
||||
switch(hr) // Correct Usage
|
||||
{
|
||||
case S_OK:
|
||||
case S_FALSE:
|
||||
{
|
||||
// ...
|
||||
} break;
|
||||
|
||||
default:
|
||||
{
|
||||
// ...
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -94,4 +94,26 @@ void IncorrectTypeConversionTest() {
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
if (HresultFunction() == S_FALSE) // Correct Usage
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
while (!HresultFunction()) {}; // BUG
|
||||
while (FAILED(HresultFunction())) {}; // Correct Usage
|
||||
|
||||
switch(hr) // Correct Usage
|
||||
{
|
||||
case S_OK:
|
||||
case S_FALSE:
|
||||
{
|
||||
// ...
|
||||
} break;
|
||||
|
||||
default:
|
||||
{
|
||||
// ...
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
| HResultBooleanConversion.c:79:15:79:38 | call to IncorrectHresultFunction | Implicit conversion from HRESULT to bool |
|
||||
| HResultBooleanConversion.c:82:10:82:11 | hr | Usage of a type HRESULT as an argument of a unary logical operation |
|
||||
| HResultBooleanConversion.c:92:9:92:10 | hr | Direct usage of a type HRESULT as a conditional expression |
|
||||
| HResultBooleanConversion.c:106:13:106:27 | call to HresultFunction | Usage of a type HRESULT as an argument of a unary logical operation |
|
||||
| HResultBooleanConversion.cpp:39:12:39:23 | call to BoolFunction | Implicit conversion from BOOL to HRESULT |
|
||||
| HResultBooleanConversion.cpp:44:12:44:24 | call to BoolFunction2 | Implicit conversion from bool to HRESULT |
|
||||
| HResultBooleanConversion.cpp:50:15:50:16 | hr | Explicit conversion from HRESULT to BOOL |
|
||||
@@ -18,3 +19,4 @@
|
||||
| HResultBooleanConversion.cpp:76:15:76:38 | call to IncorrectHresultFunction | Implicit conversion from HRESULT to bool |
|
||||
| HResultBooleanConversion.cpp:79:10:79:11 | hr | Implicit conversion from HRESULT to bool |
|
||||
| HResultBooleanConversion.cpp:89:9:89:10 | hr | Implicit conversion from HRESULT to bool |
|
||||
| HResultBooleanConversion.cpp:103:13:103:27 | call to HresultFunction | Implicit conversion from HRESULT to bool |
|
||||
|
||||
@@ -112,6 +112,65 @@ private:
|
||||
int val;
|
||||
};
|
||||
|
||||
struct Exception {
|
||||
virtual ~Exception();
|
||||
};
|
||||
|
||||
class AlwaysThrows {
|
||||
public:
|
||||
AlwaysThrows &operator=(int _val) { // GOOD (always throws)
|
||||
throw Exception();
|
||||
// No `return` statement is generated by the C++ front end because it can
|
||||
// statically see that the end of the function is unreachable.
|
||||
}
|
||||
|
||||
AlwaysThrows &operator=(int *_val) { // GOOD (always throws)
|
||||
int one = 1;
|
||||
if (one)
|
||||
throw Exception();
|
||||
// A `return` statement is generated by the C++ front end, but the
|
||||
// control-flow pruning in QL will establish that this is unreachable.
|
||||
}
|
||||
};
|
||||
|
||||
class Reachability {
|
||||
Reachability &operator=(Reachability &that) { // GOOD
|
||||
int one = 1;
|
||||
if (one)
|
||||
return *this;
|
||||
else
|
||||
return that; // unreachable
|
||||
}
|
||||
|
||||
// helper function that always returns a reference to `*this`.
|
||||
Reachability &returnThisReference() {
|
||||
int one = 1;
|
||||
if (one)
|
||||
return *this;
|
||||
else
|
||||
return staticInstance; // unreachable
|
||||
}
|
||||
|
||||
// helper function that always returns `this`.
|
||||
Reachability *const returnThisPointer() {
|
||||
int one = 1;
|
||||
if (one)
|
||||
return this;
|
||||
else
|
||||
return &staticInstance; // unreachable
|
||||
}
|
||||
|
||||
Reachability &operator=(int _val) { // GOOD
|
||||
return returnThisReference();
|
||||
}
|
||||
|
||||
Reachability &operator=(short _val) { // GOOD
|
||||
return *returnThisPointer();
|
||||
}
|
||||
|
||||
static Reachability staticInstance;
|
||||
};
|
||||
|
||||
int main() {
|
||||
Container c;
|
||||
c = c;
|
||||
|
||||
Reference in New Issue
Block a user