Merge branch 'master' into zlaski/cpp370

This commit is contained in:
zlaski-semmle
2019-06-04 09:47:30 -07:00
committed by GitHub
543 changed files with 25015 additions and 6631 deletions

View File

@@ -13,6 +13,6 @@
import cpp
from CatchBlock cb, Class caughtType
where caughtType = cb.getParameter().getType().getUnderlyingType().getUnspecifiedType()
where caughtType = cb.getParameter().getUnspecifiedType()
select cb,
"This should catch a " + caughtType.getName() + " by (const) reference rather than by value."

View File

@@ -40,7 +40,7 @@ class TemplateDependentType extends Type {
* A variable whose declaration has, or may have, side effects.
*/
predicate declarationHasSideEffects(Variable v) {
exists(Class c | c = v.getType().getUnderlyingType().getUnspecifiedType() |
exists(Class c | c = v.getUnspecifiedType() |
c.hasConstructor() or
c.hasDestructor()
)

View File

@@ -14,7 +14,7 @@
import cpp
predicate declarationHasSideEffects(Variable v) {
exists(Class c | c = v.getType().getUnderlyingType().getUnspecifiedType() |
exists(Class c | c = v.getUnspecifiedType() |
c.hasConstructor() or c.hasDestructor()
)
}

View File

@@ -17,10 +17,10 @@
import cpp
from BitField bf
where not bf.getType().getUnspecifiedType().(IntegralType).isExplicitlySigned()
and not bf.getType().getUnspecifiedType().(IntegralType).isExplicitlyUnsigned()
and not bf.getType().getUnspecifiedType() instanceof Enum
and not bf.getType().getUnspecifiedType() instanceof BoolType
where not bf.getUnspecifiedType().(IntegralType).isExplicitlySigned()
and not bf.getUnspecifiedType().(IntegralType).isExplicitlyUnsigned()
and not bf.getUnspecifiedType() instanceof Enum
and not bf.getUnspecifiedType() instanceof BoolType
// At least for C programs on Windows, BOOL is a common typedef for a type
// representing BoolType.
and not bf.getType().hasName("BOOL")

View File

@@ -15,7 +15,7 @@ import cpp
from EqualityOperation t, RemExpr lhs, Literal rhs
where t.getLeftOperand() = lhs and
t.getRightOperand() = rhs and
lhs.getLeftOperand().getType().getUnspecifiedType().(IntegralType).isSigned() and
lhs.getLeftOperand().getUnspecifiedType().(IntegralType).isSigned() and
lhs.getRightOperand().getValue() = "2" and
rhs.getValue() = "1"
select t, "Possibly invalid test for oddness. This will fail for negative numbers."

View File

@@ -45,7 +45,7 @@ predicate pointlessSelfComparison(ComparisonOperation cmp) {
predicate nanTest(EqualityOperation cmp) {
pointlessSelfComparison(cmp) and
exists (Type t
| t = cmp.getLeftOperand().getType().getUnspecifiedType()
| t = cmp.getLeftOperand().getUnspecifiedType()
| t instanceof FloatingPointType or
t instanceof TemplateParameter)
}

View File

@@ -55,5 +55,5 @@ predicate introducesNewField(Class derived, Class base) {
from DataFlow::PathNode source, DataFlow::PathNode sink, CastToPointerArithFlow cfg
where cfg.hasFlowPath(source, sink)
and source.getNode().asExpr().getFullyConverted().getType().getUnspecifiedType() = sink.getNode().asExpr().getFullyConverted().getType().getUnspecifiedType()
and source.getNode().asExpr().getFullyConverted().getUnspecifiedType() = sink.getNode().asExpr().getFullyConverted().getUnspecifiedType()
select sink, source, sink, "Pointer arithmetic here may be done with the wrong type because of the cast $@.", source, "here"

View File

@@ -75,7 +75,7 @@ class LoopWithAlloca extends Stmt {
conditionRequires(eq, truth) and
eq.getAnOperand().getValue().toInt() = 1 and
e = eq.getAnOperand() and
e.getType().getUnspecifiedType() instanceof BoolType and
e.getUnspecifiedType() instanceof BoolType and
not exists(e.getValue())
)
or
@@ -84,7 +84,7 @@ class LoopWithAlloca extends Stmt {
conditionRequires(eq, truth.booleanNot()) and
eq.getAnOperand().getValue().toInt() = 1 and
e = eq.getAnOperand() and
e.getType().getUnspecifiedType() instanceof BoolType and
e.getUnspecifiedType() instanceof BoolType and
not exists(e.getValue())
)
or

View File

@@ -45,7 +45,7 @@ predicate hasNontrivialConversion(Expr e) {
from LocalScopeVariable var, VariableAccess va, ReturnStmt r
where
not var.isStatic() and
not var.getType().getUnspecifiedType() instanceof ReferenceType and
not var.getUnspecifiedType() instanceof ReferenceType and
not r.isFromUninstantiatedTemplate(_) and
va = var.getAnAccess() and
(

View File

@@ -84,12 +84,12 @@ string nthString (int num) {
* with a fixed size array.
*/
int arrayExprFixedSize(Expr e) {
result = e.getType().getUnspecifiedType().(ArrayType).getSize()
result = e.getUnspecifiedType().(ArrayType).getSize()
or
result = e.(NewArrayExpr).getAllocatedType().(ArrayType).getSize()
or
exists (SsaDefinition def, LocalVariable v
| not (e.getType().getUnspecifiedType() instanceof ArrayType) and
| not (e.getUnspecifiedType() instanceof ArrayType) and
e = def.getAUse(v) and
result = arrayExprFixedSize(def.getDefiningValue(v)))
}
@@ -103,7 +103,7 @@ where
copySource = fc.getArgument(argSrc) and
// Some of the functions operate on a larger char type, like `wchar_t`, so we
// need to take this into account in the fixed size case.
charSize = f.getParameter(argDest).getType().getUnspecifiedType().(PointerType).getBaseType().getSize() and
charSize = f.getParameter(argDest).getUnspecifiedType().(PointerType).getBaseType().getSize() and
if exists(fc.getArgument(argLimit).getValue().toInt()) then (
// Fixed sized case
exists(int size |

View File

@@ -17,11 +17,11 @@ import cpp
class CandidateParameter extends Parameter {
CandidateParameter() {
// an array parameter
getType().getUnspecifiedType() instanceof ArrayType
getUnspecifiedType() instanceof ArrayType
or
(
// a pointer parameter
getType().getUnspecifiedType() instanceof PointerType and
getUnspecifiedType() instanceof PointerType and
// whose address is never taken (rules out common
// false positive patterns)

View File

@@ -34,7 +34,7 @@ predicate bindThrownType(ThrowExpr te, Type thrown)
// For rethrows, we use the unqualified version of the type caught by the enclosing catch block.
// Note that this is not precise, but is a reasonable first approximation.
or exists(CatchBlock cb | bindEnclosingCatch(te, cb) and bindStrippedReferenceType(cb.getParameter().getType().getUnspecifiedType(), thrown))
or exists(CatchBlock cb | bindEnclosingCatch(te, cb) and bindStrippedReferenceType(cb.getParameter().getUnspecifiedType(), thrown))
}
// This predicate determines the catch blocks that can catch the exceptions thrown by each throw expression.
@@ -43,7 +43,7 @@ predicate canCatch(ThrowExpr te, CatchBlock cb)
{
exists(Type thrown, Type caught |
bindThrownType(te, thrown)
and caught = cb.getParameter().getType().getUnspecifiedType()
and caught = cb.getParameter().getUnspecifiedType()
and not bindEnclosingCatch(te, cb)
and

View File

@@ -13,10 +13,11 @@
/*
* Note: this query is not assigned a precision yet because we don't want it on
* LGTM until its performance is well understood. It's also lacking qhelp.
* LGTM until its performance is well understood.
*/
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.ValueNumbering
class NullInstruction extends ConstantValueInstruction {
NullInstruction() {
@@ -25,17 +26,6 @@ class NullInstruction extends ConstantValueInstruction {
}
}
/**
* An instruction that will never have slicing on its result.
*/
class SingleValuedInstruction extends Instruction {
SingleValuedInstruction() {
this.getResultMemoryAccess() instanceof IndirectMemoryAccess
or
not this.hasMemoryResult()
}
}
predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
bool = any(CompareInstruction cmp |
exists(NullInstruction null |
@@ -56,22 +46,24 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
)
}
predicate candidateResult(LoadInstruction checked, SingleValuedInstruction sourceValue)
pragma[noinline]
predicate candidateResult(LoadInstruction checked, ValueNumber value, IRBlock dominator)
{
explicitNullTestOfInstruction(checked, _) and
not checked.getAST().isInMacroExpansion() and
sourceValue = checked.getSourceValue()
value.getAnInstruction() = checked and
dominator.dominates(checked.getBlock())
}
from LoadInstruction checked, LoadInstruction deref, SingleValuedInstruction sourceValue
from LoadInstruction checked, LoadInstruction deref, ValueNumber sourceValue, IRBlock dominator
where
candidateResult(checked, sourceValue) and
sourceValue = deref.getSourceAddress().(LoadInstruction).getSourceValue() and
candidateResult(checked, sourceValue, dominator) and
sourceValue.getAnInstruction() = deref.getSourceAddress() and
// This also holds if the blocks are equal, meaning that the check could come
// before the deref. That's still not okay because when they're in the same
// basic block then the deref is unavoidable even if the check concluded that
// the pointer was null. To follow this idea to its full generality, we
// should also give an alert when `check` post-dominates `deref`.
deref.getBlock().dominates(checked.getBlock())
deref.getBlock() = dominator
select checked, "This null check is redundant because the value is $@ in any case", deref,
"dereferenced here"

View File

@@ -73,8 +73,8 @@ predicate argTypeMayBeUsed(Type arg, Type parm) {
// function parameter `parm` without need for run-time conversion.
pragma[inline]
predicate argMayBeUsed(Expr arg, Parameter parm) {
argTypeMayBeUsed(arg.getFullyConverted().getType().getUnspecifiedType(),
parm.getType().getUnspecifiedType())
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(),
parm.getUnspecifiedType())
}
// True if function was ()-declared, but not (void)-declared or K&R-defined
@@ -104,5 +104,5 @@ where
not argMayBeUsed(fc.getArgument(p.getIndex()), p)
select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(),
fc.getArgument(p.getIndex()) as arg, arg.toString(),
arg.getExplicitlyConverted().getType().getUnspecifiedType() as atype, atype.toString(), p,
arg.getExplicitlyConverted().getUnspecifiedType() as atype, atype.toString(), p,
p.getTypedName()

View File

@@ -21,7 +21,7 @@ predicate taintedAllocSize(Expr e, Expr source, string taintCause) {
) and
exists(Expr tainted |
tainted = e.getAChild() and
tainted.getType().getUnspecifiedType() instanceof IntegralType and
tainted.getUnspecifiedType() instanceof IntegralType and
isUserInput(source, taintCause) and
tainted(source, tainted)
)

View File

@@ -43,7 +43,7 @@ where exists(pointerArithmeticParent(dest))
// ```
and forall(Expr parent |
parent = pointerArithmeticParent+(dest) |
parent.getFullyConverted().getType().getUnspecifiedType() instanceof PointerType)
parent.getFullyConverted().getUnspecifiedType() instanceof PointerType)
select
dest,
"This pointer might have type $@ (size " + sourceBase.getSize() +

View File

@@ -47,7 +47,7 @@ where exists(pointerArithmeticParent(dest))
// ```
and forall(Expr parent |
parent = pointerArithmeticParent+(dest) |
parent.getFullyConverted().getType().getUnspecifiedType() instanceof PointerType)
parent.getFullyConverted().getUnspecifiedType() instanceof PointerType)
// Only produce alerts that are not produced by `IncorrectPointerScaling.ql`.
and (destBase instanceof CharType)

View File

@@ -117,7 +117,7 @@ predicate exprSourceType(Expr use, Type sourceType, Location sourceLoc) {
// Source expressions
else
(sourceType = use.getType().getUnspecifiedType() and
(sourceType = use.getUnspecifiedType() and
isPointerType(sourceType) and
sourceLoc = use.getLocation())
}
@@ -135,7 +135,7 @@ predicate defSourceType(SsaDefinition def, LocalScopeVariable v,
exists (Parameter p
| p = v and
def.definedByParameter(p) and
sourceType = p.getType().getUnspecifiedType() and
sourceType = p.getUnspecifiedType() and
strictcount(p.getType()) = 1 and
isPointerType(sourceType) and
sourceLoc = p.getLocation())

View File

@@ -15,7 +15,7 @@ import IncorrectPointerScalingCommon
private predicate isCharSzPtrExpr(Expr e) {
exists (PointerType pt
| pt = e.getFullyConverted().getType().getUnspecifiedType()
| pt = e.getFullyConverted().getUnspecifiedType()
| pt.getBaseType() instanceof CharType
or pt.getBaseType() instanceof VoidType)
}

View File

@@ -0,0 +1,15 @@
#define BUFFERSIZE (1024)
// BAD: using gets
void echo_bad() {
char buffer[BUFFERSIZE];
gets(buffer);
printf("Input was: '%s'\n", buffer);
}
// GOOD: using fgets
void echo_good() {
char buffer[BUFFERSIZE];
fgets(buffer, BUFFERSIZE, stdin);
printf("Input was: '%s'\n", buffer);
}

View File

@@ -0,0 +1,42 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>This rule finds calls to the <code>gets</code> function, which is dangerous and
should not be used. See <strong>Related
rules</strong> below for rules that identify other dangerous functions.</p>
<p>The <code>gets</code> function is one of the vulnerabilities exploited by the Internet Worm of 1988, one of the first computer worms to spread through the Internet. The <code>gets</code> function provides no way to limit the amount of data that is read and stored, so without prior knowledge of the input it is impossible to use it safely with any size of buffer.</p>
</overview>
<recommendation>
<p>Replace calls to <code>gets</code> with <code>fgets</code>, specifying the maximum length to copy. This will prevent the buffer overflow.</p>
</recommendation>
<example>
<p>The following example gets a string from standard input in two ways:</p>
<sample src="DangerousFunctionOverflow.c" />
<p>The first version uses <code>gets</code> and will overflow if the input
is longer than the buffer. The second version of the code
uses <code>fgets</code> and will not overflow, because the amount of data
written is limited by the length parameter.</p>
</example>
<section title="Related rules">
<p>Other dangerous functions identified by CWE-676 ("Use of
Potentially Dangerous Function") include <code>strcpy</code>
and <code>strcat</code>. Use of these functions is highlighted by
rules for the following CWEs:</p>
<ul>
<li><a href="https://cwe.mitre.org/data/definitions/120.html">CWE-120 Classic Buffer Overflow</a>.
</li><li><a href="https://cwe.mitre.org/data/definitions/131.html">CWE-131 Incorrect Calculation of Buffer Size</a>.
</li></ul>
</section>
<references>
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Morris_worm">Morris worm</a>.</li>
<li>E. Spafford. <i>The Internet Worm Program: An Analysis</i>. Purdue Technical Report CSD-TR-823, <a href="http://www.textfiles.com/100/tr823.txt">(online)</a>, 1988.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,18 @@
/**
* @name Use of dangerous function
* @description Use of a standard library function that does not guard against buffer overflow.
* @kind problem
* @problem.severity error
* @precision very-high
* @id cpp/dangerous-function-overflow
* @tags reliability
* security
* external/cwe/cwe-242
*/
import cpp
from FunctionCall call, Function target
where
call.getTarget() = target and
target.hasGlobalName("gets")
select call, "gets does not guard against buffer overflow"

View File

@@ -5,11 +5,8 @@
<overview>
<p>This rule finds calls to functions that are dangerous to
use. Currently, it checks for calls
to <code>gets</code>, <code>gmtime</code>, <code>localtime</code>,
<code>ctime</code> and <code>asctime</code>. See <strong>Related
rules</strong> below for rules that identify other dangerous functions.</p>
<p>The <code>gets</code> function is one of the vulnerabilities exploited by the Internet Worm of 1988, one of the first computer worms to spread through the Internet. The <code>gets</code> function provides no way to limit the amount of data that is read and stored, so without prior knowledge of the input it is impossible to use it safely with any size of buffer.</p>
to <code>gmtime</code>, <code>localtime</code>,
<code>ctime</code> and <code>asctime</code>.</p>
<p>The time related functions such as <code>gmtime</code>
fill data into a <code>tm</code> struct or <code>char</code> array in
@@ -21,8 +18,6 @@ then the calls will overwrite each other's data.</p>
</overview>
<recommendation>
<p>Replace calls to <code>gets</code> with <code>fgets</code>, specifying the maximum length to copy. This will prevent the buffer overflow.</p>
<p>Replace calls to <code>gmtime</code> with <code>gmtime_r</code>.
With <code>gmtime_r</code>, the application code manages allocation of
the <code>tm</code> struct. That way, separate calls to the function
@@ -47,20 +42,7 @@ struct on every call, it is immune to other calls to <code>gmtime</code>
or <code>gmtime_r</code>.</p>
</example>
<section title="Related rules">
<p>Other dangerous functions identified by CWE-676 ("Use of
Potentially Dangerous Function") include <code>strcpy</code>
and <code>strcat</code>. Use of these functions is highlighted by
rules for the following CWEs:</p>
<ul>
<li>CWE-120 Classic Buffer Overflow
</li><li>CWE-131 Incorrect Calculation of Buffer Size
</li></ul>
</section>
<references>
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Morris_worm">Morris worm</a>.</li>
<li>E. Spafford. <i>The Internet Worm Program: An Analysis</i>. Purdue Technical Report CSD-TR-823, <a href="http://www.textfiles.com/100/tr823.txt">(online)</a>, 1988.</li>
<li>SEI CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/CON33-C.+Avoid+race+conditions+when+using+library+functions">CON33-C. Avoid race conditions when using library functions</a>.</li>
</references>
</qhelp>

View File

@@ -1,13 +1,13 @@
/**
* @name Use of potentially dangerous function
* @description Certain standard library functions are dangerous to call.
* @description Use of a standard library function that is not thread-safe.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @precision high
* @id cpp/potentially-dangerous-function
* @tags reliability
* security
* external/cwe/cwe-242
* external/cwe/cwe-676
*/
import cpp
@@ -20,9 +20,6 @@ predicate potentiallyDangerousFunction(Function f, string message) {
name = "asctime"
) and
message = "Call to " + name + " is potentially dangerous"
) or (
f.hasGlobalName("gets") and
message = "gets does not guard against buffer overflow"
)
}

View File

@@ -23,7 +23,7 @@ from Expr e1, Cast e2
where
e2 = e1.getConversion() and
exists(WideCharPointerType w, CharPointerType c |
w = e2.getType().getUnspecifiedType().(PointerType) and
c = e1.getType().getUnspecifiedType().(PointerType)
w = e2.getUnspecifiedType().(PointerType) and
c = e1.getUnspecifiedType().(PointerType)
)
select e1, "Conversion from " + e1.getType().toString() + " to " + e2.getType().toString() + ". Use of invalid string can lead to undefined behavior."

View File

@@ -25,40 +25,37 @@ class Top extends Element {
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
pragma[noopt]
final
predicate hasLocationInfo(string filepath,
int startline, int startcolumn,
int endline, int endcolumn) {
exists(Location l | l = this.getLocation()
and filepath = l.getFile().getAbsolutePath()
and startline = l.getStartLine()
and startcolumn = l.getStartColumn()
and endline = l.getEndLine()
and endcolumn = l.getEndColumn())
}
}
/**
* A `MacroAccess` with a `hasLocationInfo` predicate.
*
* This has a location that covers only the name of the accessed
* macro, not its arguments (which are included by `MacroAccess`'s
* `getLocation()`).
*/
class MacroAccessWithHasLocationInfo extends Top {
MacroAccessWithHasLocationInfo() {
this instanceof MacroAccess
}
override
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
exists(MacroAccess ma, Location l |
ma = this
and l = ma.getLocation()
and path = l.getFile().getAbsolutePath()
and sl = l.getStartLine()
and sc = l.getStartColumn()
and el = sl
and ec = sc + ma.getMacroName().length() - 1)
interestingElement(this) and
not this instanceof MacroAccess and
not this instanceof Include and
exists(Location l |
l = this.getLocation() and
l.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
or
// This has a location that covers only the name of the accessed
// macro, not its arguments (which are included by `MacroAccess`'s
// `getLocation()`).
exists(Location l, MacroAccess ma |
ma instanceof MacroAccess and
ma = this and
l = ma.getLocation() and
l.hasLocationInfo(filepath, startline, startcolumn, _, _) and
endline = startline and
exists(string macroName, int nameLength, int nameLengthMinusOne |
macroName = ma.getMacroName() and
nameLength = macroName.length() and
nameLengthMinusOne = nameLength - 1 and
endcolumn = startcolumn + nameLengthMinusOne
)
)
or
hasLocationInfo_Include(this, filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -68,23 +65,22 @@ class MacroAccessWithHasLocationInfo extends Top {
* This has a location that covers only the name of the included
* file, not the `#include` text or whitespace before it.
*/
class IncludeWithHasLocationInfo extends Top {
IncludeWithHasLocationInfo() {
this instanceof Include
}
predicate hasLocationInfo_Include(Include i, string path, int sl, int sc, int el, int ec) {
exists(Location l |
l = i.getLocation() and
path = l.getFile().getAbsolutePath() and
sl = l.getEndLine() and
sc = l.getEndColumn() + 1 - i.getIncludeText().length() and
el = l.getEndLine() and
ec = l.getEndColumn()
)
}
override
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
exists(Include i, Location l |
i = this and
l = i.getLocation() and
path = l.getFile().getAbsolutePath() and
sl = l.getEndLine() and
sc = l.getEndColumn() + 1 - i.getIncludeText().length() and
el = l.getEndLine() and
ec = l.getEndColumn()
)
}
/** Holds if `e` is a source or a target of jump-to-definition. */
predicate interestingElement(Element e) {
exists(definitionOf(e, _))
or
e = definitionOf(_, _)
}
/**

View File

@@ -11,8 +11,7 @@ when their default arguments are taken into account. An example would be a const
of the form <code>X(const X&amp; rhs, int i = 0)</code>. A compiler will use such a constructor as a copy
constructor in preference to the default member-wise copy constructor that it would otherwise generate.
Since this is usually not what was intended, constructors of the form often do not provide the right
semantics for copying objects of the class, making them potentially dangerous. Even when this sort of
thing has been done intentionally, it is confusing and in bad taste, and should be avoided.
semantics for copying objects of the class, making them potentially dangerous.
</p>
</overview>

View File

@@ -2,8 +2,8 @@
* @name Constructor with default arguments will be used as a copy constructor
* @description Constructors with default arguments should not be signature-compatible with a copy constructor when their default arguments are taken into account.
* @kind problem
* @problem.severity error
* @precision high
* @problem.severity warning
* @precision low
* @id cpp/constructor-used-as-copy-constructor
* @tags reliability
* readability

View File

@@ -74,7 +74,7 @@ predicate assignOperatorWithWrongType(Operator op, string msg) {
and exists(op.getBlock())
and exists(Class c |
c = op.getDeclaringType()
and op.getType().getUnspecifiedType() = c
and op.getUnspecifiedType() = c
and msg = "Assignment operator in class " + c.getName() + " should have return type " + c.getName() + "&. Otherwise a copy is created at each call."
)
}

View File

@@ -30,5 +30,5 @@ where e.getType() instanceof ArrayType
and
baseElement(e.getType(), cl) // only interested in arrays with classes
and
not compatible(f.getParameter(i).getType().getUnspecifiedType(), e.getType().getUnspecifiedType()))
not compatible(f.getParameter(i).getUnspecifiedType(), e.getUnspecifiedType()))
select e, "AV Rule 96: Arrays shall not be teated polymorphically"

View File

@@ -21,7 +21,7 @@ import cpp
predicate functionsMissingReturnStmt(Function f, ControlFlowNode blame) {
f.fromSource() and
exists(Type returnType |
returnType = f.getType().getUnderlyingType().getUnspecifiedType() and
returnType = f.getUnspecifiedType() and
not returnType instanceof VoidType and
not returnType instanceof TemplateParameter
) and

View File

@@ -24,8 +24,8 @@ class InvalidFloatCastExpr extends Expr {
InvalidFloatCastExpr() {
exists(Type src, Type dst |
src = this.getUnderlyingType().getUnspecifiedType() and
dst = this.getActualType().getUnderlyingType().getUnspecifiedType() and
src = this.getUnspecifiedType() and
dst = this.getFullyConverted().getUnspecifiedType() and
src.(GeneralPointerType).getBaseType() instanceof FloatingPointType and
src.(GeneralPointerType).getBaseType() != dst.(GeneralPointerType).getBaseType()
)

View File

@@ -17,5 +17,5 @@ from SwitchStmt s
where forex(SwitchCase sc | sc = s.getASwitchCase() and not sc instanceof DefaultCase |
sc.getExpr().(VariableAccess).getTarget().isConst())
// Allow switch on character types
and not (s.getExpr().getUnderlyingType().getUnspecifiedType() instanceof CharType)
and not (s.getExpr().getUnspecifiedType() instanceof CharType)
select s, "Enumeration types should be used instead of integers to select from a limited series of choices."

View File

@@ -16,9 +16,9 @@
import cpp
from BitField bf
where not bf.getType().getUnspecifiedType().(IntegralType).isUnsigned()
where not bf.getUnspecifiedType().(IntegralType).isUnsigned()
and not bf.getUnderlyingType() instanceof Enum
and not bf.getUnderlyingType().getUnspecifiedType() instanceof BoolType
and not bf.getUnspecifiedType() instanceof BoolType
and not bf.getType().hasName("BOOL") // At least for C programs on Windows, BOOL is a common typedef for a type representing BoolType.
and not bf.getDeclaredNumBits() = bf.getType().getSize() * 8 // If this is true, then there cannot be unsigned sign extension or overflow.
and not bf.isAnonymous()

View File

@@ -23,7 +23,7 @@ predicate possibleValue(Variable v, Expr value) {
}
predicate constantValue(Expr e, int value) {
e.getType().getUnderlyingType().getUnspecifiedType() instanceof IntegralType and
e.getUnspecifiedType() instanceof IntegralType and
(
// Either the expr has a constant value
value = e.getValue().toInt() or

View File

@@ -19,8 +19,8 @@ class NullPointer extends Expr {
}
from Expr e, Type t1, Type t2
where t1 = e.getUnderlyingType().getUnspecifiedType() and
t2 = e.getActualType().getUnderlyingType().getUnspecifiedType() and
where t1 = e.getUnspecifiedType() and
t2 = e.getFullyConverted().getUnspecifiedType() and
t1 != t2 and
(t1 instanceof PointerType or t2 instanceof PointerType) and
not (t2 instanceof VoidPointerType and t1 instanceof PointerType) and

View File

@@ -116,7 +116,7 @@ abstract class Declaration extends Locatable, @declaration {
* To test whether this declaration has a particular name in the global
* namespace, use `hasGlobalName`.
*/
string getName() { result = underlyingElement(this).(Q::Declaration).getName() }
abstract string getName();
/** Holds if this declaration has the given name. */
predicate hasName(string name) { name = this.getName() }
@@ -270,6 +270,16 @@ abstract class DeclarationEntry extends Locatable {
*/
abstract Type getType();
/**
* Gets the type associated with this declaration entry after specifiers
* have been deeply stripped and typedefs have been resolved.
*
* For variable declarations, get the type of the variable.
* For function declarations, get the return type of the function.
* For type declarations, get the type being declared.
*/
Type getUnspecifiedType() { result = this.getType().getUnspecifiedType() }
/**
* Holds if this declaration entry has a specifier with the given name.
*/

View File

@@ -100,6 +100,11 @@ class EnumConstant extends Declaration, @enumconstant {
result = this.getDeclaringEnum().getDeclaringType()
}
/**
* Gets the name of this enumerator.
*/
override string getName() { enumconstants(underlyingElement(this),_,_,_,result,_) }
/**
* Gets the value that this enumerator is initialized to, as a
* string. This can be a value explicitly given to the enumerator, or an

View File

@@ -35,6 +35,11 @@ class FriendDecl extends Declaration, @frienddecl {
/** Gets the location of this friend declaration. */
override Location getLocation() { frienddecls(underlyingElement(this),_,_,result) }
/** Gets a descriptive string for this friend declaration. */
override string getName() {
result = this.getDeclaringClass().getName() + "'s friend"
}
/**
* Friend declarations do not have specifiers. It makes no difference
* whether they are declared in a public, protected or private section of

View File

@@ -17,6 +17,8 @@ private import semmle.code.cpp.internal.ResolveClass
* in more detail in `Declaration.qll`.
*/
class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
override string getName() { functions(underlyingElement(this),result,_) }
/**
* DEPRECATED: Use `getIdentityString(Declaration)` from `semmle.code.cpp.Print` instead.
* Gets the full signature of this function, including return type, parameter
@@ -133,6 +135,12 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
/** Gets the return type of this function. */
Type getType() { function_return_type(underlyingElement(this),unresolveElement(result)) }
/**
* Gets the return type of this function after specifiers have been deeply
* stripped and typedefs have been resolved.
*/
Type getUnspecifiedType() { result = getType().getUnspecifiedType() }
/** Gets the nth parameter of this function. */
Parameter getParameter(int n) { params(unresolveElement(result),underlyingElement(this),n,_) }
@@ -1032,7 +1040,7 @@ class CopyAssignmentOperator extends Operator {
(hasCopySignature(this) or
// Unlike CopyConstructor, this member allows a non-reference
// parameter.
getParameter(0).getType().getUnspecifiedType() = getDeclaringType()
getParameter(0).getUnspecifiedType() = getDeclaringType()
) and
not exists(this.getParameter(1)) and
not exists(getATemplateArgument())

View File

@@ -148,6 +148,9 @@ deprecated class FinallyBlock extends Block {
deprecated class Property extends Declaration {
Property() { none() }
/** Gets the name of this property. */
override string getName() { none() }
/**
* Gets nothing (provided for compatibility with Declaration).
*

View File

@@ -1,7 +1,6 @@
import semmle.code.cpp.Location
import semmle.code.cpp.Declaration
private import semmle.code.cpp.internal.ResolveClass
private import semmle.code.cpp.internal.QualifiedName as Q
/**
* A C/C++ function parameter or catch block parameter.
@@ -14,6 +13,26 @@ private import semmle.code.cpp.internal.QualifiedName as Q
* have multiple declarations.
*/
class Parameter extends LocalScopeVariable, @parameter {
/**
* Gets the canonical name, or names, of this parameter.
*
* The canonical names are the first non-empty category from the
* following list:
* 1. The name given to the parameter at the function's definition or
* (for catch block parameters) at the catch block.
* 2. A name given to the parameter at a function declaration.
* 3. The name "p#i" where i is the index of the parameter.
*/
override string getName() {
exists (VariableDeclarationEntry vde
| vde = getANamedDeclarationEntry() and result = vde.getName()
| vde.isDefinition() or not getANamedDeclarationEntry().isDefinition())
or
(not exists(getANamedDeclarationEntry()) and
result = "p#" + this.getIndex().toString())
}
/**
* Gets the name of this parameter, including it's type.
*
@@ -34,6 +53,27 @@ class Parameter extends LocalScopeVariable, @parameter {
else result = typeString + nameString))
}
private VariableDeclarationEntry getANamedDeclarationEntry() {
result = getAnEffectiveDeclarationEntry() and result.getName() != ""
}
/**
* Gets a declaration entry corresponding to this declaration.
*
* This predicate is the same as getADeclarationEntry(), except that for
* parameters of instantiated function templates, gives the declaration
* entry of the prototype instantiation of the parameter (as
* non-prototype instantiations don't have declaration entries of their
* own).
*/
private VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
if getFunction().isConstructedFrom(_)
then exists (Function prototypeInstantiation
| prototypeInstantiation.getParameter(getIndex()) = result.getVariable() and
getFunction().isConstructedFrom(prototypeInstantiation))
else result = getADeclarationEntry()
}
/**
* Gets the name of this parameter in the given block (which should be
* the body of a function with which the parameter is associated).
@@ -55,9 +95,7 @@ class Parameter extends LocalScopeVariable, @parameter {
* In other words, this predicate holds precisely when the result of
* `getName()` is not "p#i" (where `i` is the index of the parameter).
*/
predicate isNamed() {
exists(underlyingElement(this).(Q::Parameter).getANamedDeclarationEntry())
}
predicate isNamed() { exists(getANamedDeclarationEntry()) }
/**
* Gets the function to which this parameter belongs, if it is a function
@@ -97,13 +135,8 @@ class Parameter extends LocalScopeVariable, @parameter {
* of the declaration locations.
*/
override Location getLocation() {
exists(VariableDeclarationEntry vde |
vde = underlyingElement(this).(Q::Parameter).getAnEffectiveDeclarationEntry() and
result = vde.getLocation()
|
vde.isDefinition()
or
not underlyingElement(this).(Q::Parameter).getAnEffectiveDeclarationEntry().isDefinition()
exists(VariableDeclarationEntry vde | vde = getAnEffectiveDeclarationEntry() and result = vde.getLocation() |
vde.isDefinition() or not getAnEffectiveDeclarationEntry().isDefinition()
)
}
}

View File

@@ -9,9 +9,10 @@ private import semmle.code.cpp.internal.ResolveClass
* `Enum`, and `TypedefType`.
*/
class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @usertype {
override string getName() {
result = Declaration.super.getName()
}
/**
* Gets the name of this type.
*/
override string getName() { usertypes(underlyingElement(this),result,_) }
/**
* Gets the simple name of this type, without any template parameters. For example

View File

@@ -41,12 +41,21 @@ class Variable extends Declaration, @variable {
/** Holds if this variable is `volatile`. */
predicate isVolatile() { this.getType().isVolatile() }
/** Gets the name of this variable. */
override string getName() { none() }
/** Gets the type of this variable. */
Type getType() { none() }
/** Gets the type of this variable, after typedefs have been resolved. */
Type getUnderlyingType() { result = this.getType().getUnderlyingType() }
/**
* Gets the type of this variable, after specifiers have been deeply
* stripped and typedefs have been resolved.
*/
Type getUnspecifiedType() { result = this.getType().getUnspecifiedType() }
/**
* Gets the type of this variable prior to deduction caused by the C++11
* `auto` keyword.
@@ -288,6 +297,8 @@ deprecated class StackVariable extends Variable {
* A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`.
*/
class LocalVariable extends LocalScopeVariable, @localvariable {
override string getName() { localvariables(underlyingElement(this),_,result) }
override Type getType() { localvariables(underlyingElement(this),unresolveElement(result),_) }
override Function getFunction() {
@@ -300,6 +311,8 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
* A C/C++ variable which has global scope or namespace scope.
*/
class GlobalOrNamespaceVariable extends Variable, @globalvariable {
override string getName() { globalvariables(underlyingElement(this),_,result) }
override Type getType() { globalvariables(underlyingElement(this),unresolveElement(result),_) }
override Element getEnclosingElement() { none() }
@@ -347,6 +360,8 @@ class MemberVariable extends Variable, @membervariable {
/** Holds if this member is public. */
predicate isPublic() { this.hasSpecifier("public") }
override string getName() { membervariables(underlyingElement(this),_,result) }
override Type getType() {
if (strictcount(this.getAType()) = 1) then (
result = this.getAType()

View File

@@ -66,7 +66,7 @@ class RecoverableAssert extends MacroInvocation, Assertion {
not result.getParent() = this.getAnAssertedExpr() and
// Remove spurious "string literals" that arise when the macro
// uses #stringification
not result.(Literal).getType().getUnspecifiedType().(ArrayType).getBaseType() instanceof CharType
not result.(Literal).getUnspecifiedType().(ArrayType).getBaseType() instanceof CharType
}
}

View File

@@ -28,12 +28,12 @@ predicate memberMayBeVarSize(Class c, MemberVariable v) {
v = c.getCanonicalMember(i) and
// v is an array of size at most 1
v.getType().getUnspecifiedType().(ArrayType).getArraySize() <= 1
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1
) and (
exists(SizeofOperator so |
// `sizeof(c)` is taken
so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or
so.(SizeofExprOperator).getExprOperand().getType().getUnspecifiedType() = c |
so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c |
// arithmetic is performed on the result
so.getParent*() instanceof AddExpr
@@ -55,7 +55,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
exists(Variable bufferVar | bufferVar = bufferExpr.(VariableAccess).getTarget() |
(
// buffer is a fixed size array
result = bufferVar.getType().getUnspecifiedType().(ArrayType).getSize() and
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
why = bufferVar and
not memberMayBeVarSize(_, bufferVar) and
not result = 0 // zero sized arrays are likely to have special usage, for example
@@ -69,13 +69,13 @@ int getBufferSize(Expr bufferExpr, Element why) {
why instanceof StringLiteral
) and
result = why.(Expr).getType().(ArrayType).getSize() and
not exists(bufferVar.getType().getUnspecifiedType().(ArrayType).getSize())
not exists(bufferVar.getUnspecifiedType().(ArrayType).getSize())
) or exists(Class parentClass, VariableAccess parentPtr |
// buffer is the parentPtr->bufferVar of a 'variable size struct'
memberMayBeVarSize(parentClass, bufferVar) and
why = bufferVar and
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
parentPtr.getTarget().getType().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
result =
getBufferSize(parentPtr, _) +
bufferVar.getType().getSize() -

View File

@@ -33,8 +33,8 @@ class AnalysedString extends Expr
{
AnalysedString()
{
this.getType().getUnspecifiedType() instanceof ArrayType or
this.getType().getUnspecifiedType() instanceof PointerType
this.getUnspecifiedType() instanceof ArrayType or
this.getUnspecifiedType() instanceof PointerType
}
/**

View File

@@ -88,7 +88,7 @@ predicate getter(MemberVariable v, MemberFunction f, Class c) {
*/
predicate sameBaseType(Type t1, Type t2) {
exists (Type base1, Type base2 |
base1 = t1.getUnderlyingType().getUnspecifiedType() and
base1 = t1.getUnspecifiedType() and
base2 = t2.getUnspecifiedType().getUnspecifiedType() and
(
base1 = base2 or

View File

@@ -69,7 +69,7 @@ private predicate addressTakenVariable(LocalScopeVariable var) {
}
private predicate isReferenceVar(LocalScopeVariable v) {
v.getType().getUnspecifiedType() instanceof ReferenceType
v.getUnspecifiedType() instanceof ReferenceType
}
/**

View File

@@ -435,7 +435,7 @@ library class ExprEvaluator extends int {
interestingInternal(e, fc, _) |
f = fc.getTarget()
and not obviouslyNonConstant(f)
and not f.getType().getUnspecifiedType() instanceof VoidType
and not f.getUnspecifiedType() instanceof VoidType
)
}

View File

@@ -68,7 +68,7 @@ private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) {
pointerOut instanceof PointerSubExpr
) and
pointerIn = pointerOut.getAChild().getFullyConverted() and
pointerIn.getType().getUnspecifiedType() instanceof PointerType
pointerIn.getUnspecifiedType() instanceof PointerType
or
pointerIn = pointerOut.(UnaryPlusExpr).getOperand().getFullyConverted()
or

View File

@@ -92,7 +92,7 @@ predicate stackPointerFlowsToUse(
* expression.
*/
cached private PointerType getExprPtrType(Expr use) {
result = use.getType().getUnspecifiedType()
result = use.getUnspecifiedType()
}
predicate stackReferenceFlowsToUse(
@@ -122,11 +122,11 @@ predicate stackReferenceFlowsToUse(
// a PointerType for `p`. Luckily, this conversion happens
// automatically when the variable is used. So we get the correct type
// provided that we get it from `use` rather than from `var`.
useType = use.getType().getUnspecifiedType())
useType = use.getUnspecifiedType())
or
// Accessing the field of a class, struct, or union.
exists (FieldAccess access, Class classType
| use = access and useType = access.getType().getUnspecifiedType()
| use = access and useType = access.getUnspecifiedType()
| // Handle both x.f and x->f:
stackReferenceFlowsToUse(access.getQualifier(), classType, source, isLocal) or
stackPointerFlowsToUse(access.getQualifier(), classType, source, isLocal))
@@ -216,7 +216,7 @@ predicate stackReferenceFlowsToDef_Impl(
/** The type of the variable is a reference type, such as int&. */
predicate isReferenceVariable(LocalScopeVariable var) {
var.getType().getUnspecifiedType() instanceof ReferenceType
var.getUnspecifiedType() instanceof ReferenceType
}
/**

View File

@@ -118,7 +118,7 @@ module FlowVar_internal {
// The SSA library has a theoretically accurate treatment of reference types,
// treating them as immutable, but for data flow it gives better results in
// practice to make the variable synonymous with its contents.
not v.getType().getUnspecifiedType() instanceof ReferenceType
not v.getUnspecifiedType() instanceof ReferenceType
}
/**

View File

@@ -146,7 +146,7 @@ class FieldAccess extends VariableAccess {
class PointerFieldAccess extends FieldAccess {
PointerFieldAccess() {
exists (PointerType t
| t = getQualifier().getFullyConverted().getType().getUnspecifiedType() and
| t = getQualifier().getFullyConverted().getUnspecifiedType() and
t.getBaseType() instanceof Class)
}
}
@@ -160,7 +160,7 @@ class PointerFieldAccess extends FieldAccess {
class DotFieldAccess extends FieldAccess {
DotFieldAccess() {
exists (Class c
| c = getQualifier().getFullyConverted().getType().getUnspecifiedType())
| c = getQualifier().getFullyConverted().getUnspecifiedType())
}
}

View File

@@ -58,19 +58,19 @@ module CastSanity {
// Every cast should have exactly one semantic conversion kind
count(cast.getSemanticConversionString()) > 1 and
kind = cast.getSemanticConversionString() and
fromType = cast.getExpr().getType().getUnspecifiedType()
fromType = cast.getExpr().getUnspecifiedType()
}
query predicate missingSemanticConversionString(Cast cast, Type fromType) {
// Every cast should have exactly one semantic conversion kind
not exists(cast.getSemanticConversionString()) and
fromType = cast.getExpr().getType().getUnspecifiedType()
fromType = cast.getExpr().getUnspecifiedType()
}
query predicate unknownSemanticConversionString(Cast cast, Type fromType) {
// Every cast should have a known semantic conversion kind
cast.getSemanticConversionString() = "unknown conversion" and
fromType = cast.getExpr().getType().getUnspecifiedType()
fromType = cast.getExpr().getUnspecifiedType()
}
}
@@ -137,8 +137,8 @@ private predicate isPointerToMemberOrNullPointer(Type type) {
class ArithmeticConversion extends Cast {
ArithmeticConversion() {
conversionkinds(underlyingElement(this), 0) and
isArithmeticOrEnum(getType().getUnspecifiedType()) and
isArithmeticOrEnum(getExpr().getType().getUnspecifiedType())
isArithmeticOrEnum(getUnspecifiedType()) and
isArithmeticOrEnum(getExpr().getUnspecifiedType())
}
override string getSemanticConversionString() {
@@ -151,8 +151,8 @@ class ArithmeticConversion extends Cast {
*/
class IntegralConversion extends ArithmeticConversion {
IntegralConversion() {
isIntegralOrEnum(getType().getUnspecifiedType()) and
isIntegralOrEnum(getExpr().getType().getUnspecifiedType())
isIntegralOrEnum(getUnspecifiedType()) and
isIntegralOrEnum(getExpr().getUnspecifiedType())
}
override string getSemanticConversionString() {
@@ -165,8 +165,8 @@ class IntegralConversion extends ArithmeticConversion {
*/
class FloatingPointConversion extends ArithmeticConversion {
FloatingPointConversion() {
getType().getUnspecifiedType() instanceof FloatingPointType and
getExpr().getType().getUnspecifiedType() instanceof FloatingPointType
getUnspecifiedType() instanceof FloatingPointType and
getExpr().getUnspecifiedType() instanceof FloatingPointType
}
override string getSemanticConversionString() {
@@ -179,8 +179,8 @@ class FloatingPointConversion extends ArithmeticConversion {
*/
class FloatingPointToIntegralConversion extends ArithmeticConversion {
FloatingPointToIntegralConversion() {
isIntegralOrEnum(getType().getUnspecifiedType()) and
getExpr().getType().getUnspecifiedType() instanceof FloatingPointType
isIntegralOrEnum(getUnspecifiedType()) and
getExpr().getUnspecifiedType() instanceof FloatingPointType
}
override string getSemanticConversionString() {
@@ -193,8 +193,8 @@ class FloatingPointToIntegralConversion extends ArithmeticConversion {
*/
class IntegralToFloatingPointConversion extends ArithmeticConversion {
IntegralToFloatingPointConversion() {
getType().getUnspecifiedType() instanceof FloatingPointType and
isIntegralOrEnum(getExpr().getType().getUnspecifiedType())
getUnspecifiedType() instanceof FloatingPointType and
isIntegralOrEnum(getExpr().getUnspecifiedType())
}
override string getSemanticConversionString() {
@@ -211,8 +211,8 @@ class IntegralToFloatingPointConversion extends ArithmeticConversion {
class PointerConversion extends Cast {
PointerConversion() {
conversionkinds(underlyingElement(this), 0) and
isPointerOrNullPointer(getType().getUnspecifiedType()) and
isPointerOrNullPointer(getExpr().getType().getUnspecifiedType())
isPointerOrNullPointer(getUnspecifiedType()) and
isPointerOrNullPointer(getExpr().getUnspecifiedType())
}
override string getSemanticConversionString() {
@@ -230,8 +230,8 @@ class PointerToMemberConversion extends Cast {
PointerToMemberConversion() {
conversionkinds(underlyingElement(this), 0) and
exists(Type fromType, Type toType |
fromType = getExpr().getType().getUnspecifiedType() and
toType = getType().getUnspecifiedType() and
fromType = getExpr().getUnspecifiedType() and
toType = getUnspecifiedType() and
isPointerToMemberOrNullPointer(fromType) and
isPointerToMemberOrNullPointer(toType) and
// A conversion from nullptr to nullptr is a `PointerConversion`, not a
@@ -254,8 +254,8 @@ class PointerToMemberConversion extends Cast {
class PointerToIntegralConversion extends Cast {
PointerToIntegralConversion() {
conversionkinds(underlyingElement(this), 0) and
isIntegralOrEnum(getType().getUnspecifiedType()) and
isPointerOrNullPointer(getExpr().getType().getUnspecifiedType())
isIntegralOrEnum(getUnspecifiedType()) and
isPointerOrNullPointer(getExpr().getUnspecifiedType())
}
override string getSemanticConversionString() {
@@ -269,8 +269,8 @@ class PointerToIntegralConversion extends Cast {
class IntegralToPointerConversion extends Cast {
IntegralToPointerConversion() {
conversionkinds(underlyingElement(this), 0) and
isPointerOrNullPointer(getType().getUnspecifiedType()) and
isIntegralOrEnum(getExpr().getType().getUnspecifiedType())
isPointerOrNullPointer(getUnspecifiedType()) and
isIntegralOrEnum(getExpr().getUnspecifiedType())
}
override string getSemanticConversionString() {
@@ -298,7 +298,7 @@ class BoolConversion extends Cast {
class VoidConversion extends Cast {
VoidConversion() {
conversionkinds(underlyingElement(this), 0) and
getType().getUnspecifiedType() instanceof VoidType
getUnspecifiedType() instanceof VoidType
}
override string getSemanticConversionString() {
@@ -353,7 +353,7 @@ class InheritanceConversion extends Cast {
*/
private Class getConversionClass(Expr expr) {
exists(Type operandType |
operandType = expr.getType().getUnspecifiedType() and
operandType = expr.getUnspecifiedType() and
(
result = operandType or
result = operandType.(PointerType).getBaseType()

View File

@@ -57,7 +57,7 @@ class Expr extends StmtParent, @expr {
* As the type of an expression can sometimes be a TypedefType, calling getUnderlyingType()
* is often more useful than calling this predicate.
*/
pragma[nomagic] Type getType() { expr_types(underlyingElement(this),unresolveElement(result),_) }
pragma[nomagic] cached Type getType() { expr_types(underlyingElement(this),unresolveElement(result),_) }
/**
* Gets the type of this expression after typedefs have been resolved.
@@ -68,6 +68,12 @@ class Expr extends StmtParent, @expr {
*/
Type getUnderlyingType() { result = this.getType().getUnderlyingType() }
/**
* Gets the type of this expression after specifiers have been deeply
* stripped and typedefs have been resolved.
*/
Type getUnspecifiedType() { result = this.getType().getUnspecifiedType() }
/**
* Gets an integer indicating the type of expression that this represents.
*
@@ -215,7 +221,7 @@ class Expr extends StmtParent, @expr {
exists ( Expr e2 |
e.(TypeidOperator).getExpr() = e2 and
(
not e2.getActualType().getUnspecifiedType().(Class).isPolymorphic() or
not e2.getFullyConverted().getUnspecifiedType().(Class).isPolymorphic() or
not e2.isGLValueCategory()
)
) or

View File

@@ -164,7 +164,7 @@ class ClassAggregateLiteral extends AggregateLiteral {
Class classType;
ClassAggregateLiteral() {
classType = this.getType().getUnspecifiedType()
classType = this.getUnspecifiedType()
}
/**
@@ -223,7 +223,7 @@ class ArrayAggregateLiteral extends AggregateLiteral {
ArrayType arrayType;
ArrayAggregateLiteral() {
arrayType = this.getType().getUnspecifiedType()
arrayType = this.getUnspecifiedType()
}
/**

View File

@@ -132,7 +132,7 @@ private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) {
pointerOut instanceof PointerSubExpr
) and
pointerIn = pointerOut.getAChild().getFullyConverted() and
pointerIn.getType().getUnspecifiedType() instanceof PointerType and
pointerIn.getUnspecifiedType() instanceof PointerType and
// The pointer arg won't be constant in the sense of `hasConstantValue`, so
// this will have to match the integer argument.
hasConstantValue(pointerOut.getAChild().getFullyConverted())

View File

@@ -1,3 +1,4 @@
private import semmle.code.cpp.Declaration as D
/**
* INTERNAL: Do not use. Provides classes and predicates for getting names of
* declarations, especially qualified names. Import this library `private` and
@@ -26,6 +27,32 @@ class Namespace extends @namespace {
else result = this.getName()
}
/**
* Gets a namespace qualifier, like `"namespace1::namespace2"`, through which
* the members of this namespace can be named. When `inline namespace` is
* used, this predicate may have multiple results.
*
* This predicate does not take namespace aliases into account. Unlike inline
* namespaces, specialization of templates cannot happen through an alias.
* Aliases are also local to the compilation unit, while inline namespaces
* affect the whole program.
*/
string getAQualifierForMembers() {
if namespacembrs(_, this)
then
exists(Namespace ns |
namespacembrs(ns, this)
|
result = ns.getAQualifierForMembers() + "::" + this.getName()
or
// If this is an inline namespace, its members are also visible in any
// namespace where the members of the parent are visible.
namespace_inline(this) and
result = ns.getAQualifierForMembers()
)
else result = this.getName()
}
Declaration getADeclaration() {
if this.getName() = ""
then result.isTopLevel() and not namespacembrs(_, result)
@@ -37,8 +64,7 @@ abstract class Declaration extends @declaration {
string toString() { result = "QualifiedName Declaration" }
/** Gets the name of this declaration. */
cached
abstract string getName();
final string getName() { result = this.(D::Declaration).getName() }
string getTypeQualifierWithoutArgs() {
exists(UserType declaringType |
@@ -133,8 +159,6 @@ abstract class Declaration extends @declaration {
}
class Variable extends Declaration, @variable {
override string getName() { none() }
VariableDeclarationEntry getADeclarationEntry() { result.getDeclaration() = this }
}
@@ -147,7 +171,6 @@ class TemplateVariable extends Variable {
class LocalScopeVariable extends Variable, @localscopevariable { }
class LocalVariable extends LocalScopeVariable, @localvariable {
override string getName() { localvariables(this, _, result) }
}
/**
@@ -174,60 +197,9 @@ class Parameter extends LocalScopeVariable, @parameter {
int index;
Parameter() { params(this, function, index, _) }
/**
* Gets the canonical name, or names, of this parameter.
*
* The canonical names are the first non-empty category from the
* following list:
* 1. The name given to the parameter at the function's definition or
* (for catch block parameters) at the catch block.
* 2. A name given to the parameter at a function declaration.
* 3. The name "p#i" where i is the index of the parameter.
*/
override string getName() {
exists(VariableDeclarationEntry vde |
vde = getANamedDeclarationEntry() and result = vde.getName()
|
vde.isDefinition() or not getANamedDeclarationEntry().isDefinition()
)
or
not exists(getANamedDeclarationEntry()) and
result = "p#" + index.toString()
}
VariableDeclarationEntry getANamedDeclarationEntry() {
result = getAnEffectiveDeclarationEntry() and exists(result.getName())
}
/**
* Gets a declaration entry corresponding to this declaration.
*
* This predicate is the same as getADeclarationEntry(), except that for
* parameters of instantiated function templates, gives the declaration
* entry of the prototype instantiation of the parameter (as
* non-prototype instantiations don't have declaration entries of their
* own).
*/
VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
if function.(Function).isConstructedFrom(_)
then
exists(Function prototypeInstantiation |
prototypeInstantiation.getParameter(index) = result.getVariable() and
function.(Function).isConstructedFrom(prototypeInstantiation)
)
else result = getADeclarationEntry()
}
}
class GlobalOrNamespaceVariable extends Variable, @globalvariable {
override string getName() { globalvariables(this, _, result) }
}
class MemberVariable extends Variable, @membervariable {
MemberVariable() { this.isMember() }
override string getName() { membervariables(this, _, result) }
}
// Unlike the usual `EnumConstant`, this one doesn't have a
@@ -235,14 +207,10 @@ class MemberVariable extends Variable, @membervariable {
// qualifier names since it can assume that any declaration with a
// `getDeclaringType()` should use that type in its type qualifier name.
class EnumConstant extends Declaration, @enumconstant {
override string getName() { enumconstants(this, _, _, _, result, _) }
UserType getDeclaringEnum() { enumconstants(this, result, _, _, _, _) }
}
class Function extends Declaration, @function {
override string getName() { functions(this, result, _) }
predicate isConstructedFrom(Function f) { function_instantiation(this, f) }
Parameter getParameter(int n) { params(result, this, n, _) }
@@ -258,8 +226,6 @@ class TemplateFunction extends Function {
}
class UserType extends Declaration, @usertype {
override string getName() { result = getUserTypeNameWithArgs(this) }
predicate isLocal() { enclosingfunction(this, _) }
// Gets a member of this class, if it's a class.
@@ -291,10 +257,6 @@ class TemplateClass extends UserType {
}
class FriendDecl extends Declaration, @frienddecl {
override string getName() {
result = getUserTypeNameWithArgs(this.getDeclaringClass()) + "'s friend"
}
UserType getDeclaringClass() { frienddecls(this, result, _, _) }
}
@@ -331,7 +293,7 @@ cached
private predicate declarationHasQualifiedName(
string baseName, string typeQualifier, string namespaceQualifier, Declaration d
) {
namespaceQualifier = d.getNamespace().getQualifiedName() and
namespaceQualifier = d.getNamespace().getAQualifierForMembers() and
(
if hasTypeQualifier(d)
then typeQualifier = d.getTypeQualifierWithoutArgs()

View File

@@ -69,6 +69,7 @@ private newtype TOpcode =
TBufferWriteSideEffect() or
TBufferMayWriteSideEffect() or
TChi() or
TInlineAsm() or
TUnreached()
class Opcode extends TOpcode {
@@ -214,5 +215,6 @@ module Opcode {
class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode, TBufferWriteSideEffect { override final string toString() { result = "BufferWriteSideEffect" } }
class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode, TBufferMayWriteSideEffect { override final string toString() { result = "BufferMayWriteSideEffect" } }
class Chi extends Opcode, TChi { override final string toString() { result = "Chi" } }
class InlineAsm extends Opcode, TInlineAsm { override final string toString() { result = "InlineAsm" } }
class Unreached extends Opcode, TUnreached { override final string toString() { result = "Unreached" } }
}

View File

@@ -40,7 +40,7 @@ module InstructionSanity {
opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or
opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or
(
(opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode) and
(opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or opcode instanceof Opcode::InlineAsm) and
tag instanceof SideEffectOperandTag
)
)
@@ -73,7 +73,8 @@ module InstructionSanity {
operand.getOperandTag() = tag) and
not expectsOperand(instr, tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
@@ -1474,6 +1475,19 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
}
}
/**
* An instruction representing a GNU or MSVC inline assembly statement.
*/
class InlineAsmInstruction extends Instruction {
InlineAsmInstruction() {
getOpcode() instanceof Opcode::InlineAsm
}
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof EscapedMayMemoryAccess
}
}
/**
* An instruction that throws an exception.
*/

View File

@@ -105,19 +105,10 @@ class ValueNumber extends TValueNumber {
* definition because it accesses the exact same memory.
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
*
* This concept should probably be exposed in the public IR API.
*/
private class CongruentCopyInstruction extends CopyInstruction {
CongruentCopyInstruction() {
exists(Instruction def |
def = this.getSourceValue() and
(
def.getResultMemoryAccess() instanceof IndirectMemoryAccess or
def.getResultMemoryAccess() instanceof PhiMemoryAccess or
not def.hasMemoryResult()
)
)
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
}
}

View File

@@ -40,7 +40,7 @@ module InstructionSanity {
opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or
opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or
(
(opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode) and
(opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or opcode instanceof Opcode::InlineAsm) and
tag instanceof SideEffectOperandTag
)
)
@@ -73,7 +73,8 @@ module InstructionSanity {
operand.getOperandTag() = tag) and
not expectsOperand(instr, tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
@@ -1474,6 +1475,19 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
}
}
/**
* An instruction representing a GNU or MSVC inline assembly statement.
*/
class InlineAsmInstruction extends Instruction {
InlineAsmInstruction() {
getOpcode() instanceof Opcode::InlineAsm
}
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof EscapedMayMemoryAccess
}
}
/**
* An instruction that throws an exception.
*/

View File

@@ -105,19 +105,10 @@ class ValueNumber extends TValueNumber {
* definition because it accesses the exact same memory.
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
*
* This concept should probably be exposed in the public IR API.
*/
private class CongruentCopyInstruction extends CopyInstruction {
CongruentCopyInstruction() {
exists(Instruction def |
def = this.getSourceValue() and
(
def.getResultMemoryAccess() instanceof IndirectMemoryAccess or
def.getResultMemoryAccess() instanceof PhiMemoryAccess or
not def.hasMemoryResult()
)
)
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
}
}

View File

@@ -3,6 +3,7 @@ import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.internal.OperandTag
private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag
private import TranslatedCondition
private import TranslatedElement
private import TranslatedExpr
private import TranslatedStmt
@@ -159,6 +160,23 @@ cached private module Cached {
)
)
or
// Range-based for loop:
// Any edge from within the update of the loop to the condition of
// the loop is a back edge.
exists(TranslatedRangeBasedForStmt s, TranslatedCondition condition |
s instanceof TranslatedRangeBasedForStmt and
condition = s.getCondition() and
result = condition.getFirstInstruction() and
exists(TranslatedElement inUpdate, InstructionTag tag |
result = inUpdate.getInstructionSuccessor(tag, kind) and
exists(TranslatedElement update |
update = s.getUpdate() |
inUpdate = update.getAChild*()
) and
instruction = inUpdate.getInstruction(tag)
)
)
or
// Goto statement:
// As a conservative approximation, any edge out of `goto` is a back edge
// unless it goes strictly forward in the program text. A `goto` whose

View File

@@ -84,7 +84,13 @@ newtype TInstructionTag =
} or
InitializerElementDefaultValueStoreTag(int elementIndex) {
elementIsInitialized(elementIndex)
}
} or
AsmTag() or
AsmInputTag(int elementIndex) {
exists(AsmStmt asm |
exists(asm.getChild(elementIndex))
)
}
class InstructionTag extends TInstructionTag {
final string toString() {
@@ -161,5 +167,9 @@ string getInstructionTagId(TInstructionTag tag) {
tag = InitializerElementDefaultValueStoreTag(index) and tagName = "InitElemDefValStore"
) and
result = tagName + "(" + index + ")"
) or
tag = AsmTag() and result = "Asm" or
exists(int index |
tag = AsmInputTag(index) and result = "AsmInputTag(" + index + ")"
)
}

View File

@@ -39,7 +39,7 @@ abstract class TranslatedCondition extends TranslatedElement {
}
final Type getResultType() {
result = expr.getType().getUnspecifiedType()
result = expr.getUnspecifiedType()
}
}

View File

@@ -191,6 +191,44 @@ class TranslatedVariableDeclarationEntry extends TranslatedVariableDeclaration,
}
}
/**
* Gets the `TranslatedRangeBasedForVariableDeclaration` that represents the declaration of
* `var`.
*/
TranslatedRangeBasedForVariableDeclaration getTranslatedRangeBasedForVariableDeclaration(
LocalVariable var) {
result.getVariable() = var
}
/**
* Represents the IR translation of a compiler-generated variable in a range-based `for` loop.
*/
class TranslatedRangeBasedForVariableDeclaration extends TranslatedVariableDeclaration,
TTranslatedRangeBasedForVariableDeclaration {
RangeBasedForStmt forStmt;
LocalVariable var;
TranslatedRangeBasedForVariableDeclaration() {
this = TTranslatedRangeBasedForVariableDeclaration(forStmt, var)
}
override string toString() {
result = var.toString()
}
override Locatable getAST() {
result = var
}
override Function getFunction() {
result = forStmt.getEnclosingFunction()
}
override LocalVariable getVariable() {
result = var
}
}
TranslatedConditionDecl getTranslatedConditionDecl(ConditionDeclExpr expr) {
result.getAST() = expr
}

View File

@@ -64,6 +64,8 @@ private predicate ignoreExprAndDescendants(Expr expr) {
// represent them.
newExpr.getInitializer().getFullyConverted() = expr
) or
// Do not translate input/output variables in GNU asm statements
getRealParent(expr) instanceof AsmStmt or
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
}
@@ -359,6 +361,16 @@ newtype TTranslatedElement =
declStmt.getADeclarationEntry() = entry
)
} or
// A compiler-generated variable to implement a range-based for loop. These don't have a
// `DeclarationEntry` in the database, so we have to go by the `Variable` itself.
TTranslatedRangeBasedForVariableDeclaration(RangeBasedForStmt forStmt, LocalVariable var) {
translateStmt(forStmt) and
(
var = forStmt.getRangeVariable() or
var = forStmt.getBeginEndDeclaration().getADeclaration() or
var = forStmt.getVariable()
)
} or
// An allocator call in a `new` or `new[]` expression
TTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
not ignoreExpr(newExpr)
@@ -385,7 +397,7 @@ private int getEndOfValueInitializedRange(ArrayAggregateLiteral initList, int af
or
isFirstValueInitializedElementInRange(initList, afterElementIndex) and
not exists(getNextExplicitlyInitializedElementAfter(initList, afterElementIndex)) and
result = initList.getType().getUnspecifiedType().(ArrayType).getArraySize()
result = initList.getUnspecifiedType().(ArrayType).getArraySize()
}
/**

View File

@@ -55,7 +55,7 @@ abstract class TranslatedExpr extends TranslatedElement {
* Gets the type of the result produced by this expression.
*/
final Type getResultType() {
result = expr.getType().getUnspecifiedType()
result = expr.getUnspecifiedType()
}
override final Locatable getAST() {
@@ -323,7 +323,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
Type resultType, boolean isGLValue) {
tag = LoadTag() and
opcode instanceof Opcode::Load and
resultType = expr.getType().getUnspecifiedType() and
resultType = expr.getUnspecifiedType() and
if expr.isGLValueCategory() then
isGLValue = true
else
@@ -763,7 +763,7 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
Type resultType, boolean isGLValue) {
tag = OnlyInstructionTag() and
opcode instanceof Opcode::CopyValue and
resultType = expr.getType().getUnspecifiedType() and
resultType = expr.getUnspecifiedType() and
isGLValue = false
}
@@ -911,7 +911,7 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
Type resultType, boolean isGLValue) {
tag = OnlyInstructionTag() and
opcode instanceof Opcode::FunctionAddress and
resultType = expr.getType().getUnspecifiedType() and
resultType = expr.getUnspecifiedType() and
isGLValue = true
}
@@ -1405,7 +1405,7 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
// left-to-right.
exists(PointerAddExpr ptrAdd, Type rightType |
ptrAdd = expr and
rightType = ptrAdd.getRightOperand().getType().getUnspecifiedType() and
rightType = ptrAdd.getRightOperand().getUnspecifiedType() and
rightType instanceof PointerType
)
}
@@ -1767,7 +1767,7 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
Type resultType, boolean isGLValue) {
tag = AllocationSizeTag() and
opcode instanceof Opcode::Constant and
resultType = expr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and
isGLValue = false
}
@@ -1813,7 +1813,7 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
isGLValue = false and
resultType = expr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and
(
// Convert the extent to `size_t`, because the AST doesn't do this already.
tag = AllocationExtentConvertTag() and opcode instanceof Opcode::Convert or
@@ -1901,7 +1901,7 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
}
override final Type getCallResultType() {
result = expr.getAllocator().getType().getUnspecifiedType()
result = expr.getAllocator().getUnspecifiedType()
}
override final TranslatedExpr getQualifier() {
@@ -1961,7 +1961,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
Type resultType, boolean isGLValue) {
tag = OnlyInstructionTag() and
opcode instanceof Opcode::FieldAddress and
resultType = expr.getTarget().getType().getUnspecifiedType() and
resultType = expr.getTarget().getUnspecifiedType() and
isGLValue = true
}
@@ -2341,7 +2341,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
}
private Type getExceptionType() {
result = expr.getType().getUnspecifiedType()
result = expr.getUnspecifiedType()
}
}

View File

@@ -311,7 +311,7 @@ class TranslatedFunction extends TranslatedElement,
}
private final Type getReturnType() {
result = func.getType().getUnspecifiedType()
result = func.getUnspecifiedType()
}
}

View File

@@ -403,7 +403,7 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
*/
private predicate zeroInitRange(int startIndex, int elementCount) {
exists(int targetCount |
startIndex = expr.getType().getUnspecifiedType().(ArrayType).getArraySize() and
startIndex = expr.getUnspecifiedType().(ArrayType).getArraySize() and
targetCount = getContext().getTargetType().(ArrayType).getArraySize() and
elementCount = targetCount - startIndex and
elementCount > 0
@@ -482,7 +482,7 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue) {
tag = getFieldAddressTag() and
opcode instanceof Opcode::FieldAddress and
resultType = field.getType().getUnspecifiedType() and
resultType = field.getUnspecifiedType() and
isGLValue = true
}
@@ -522,7 +522,7 @@ class TranslatedExplicitFieldInitialization extends TranslatedFieldInitializatio
}
override Type getTargetType() {
result = field.getType().getUnspecifiedType()
result = field.getUnspecifiedType()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -565,13 +565,13 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
(
tag = getFieldDefaultValueTag() and
opcode instanceof Opcode::Constant and
resultType = field.getType().getUnspecifiedType() and
resultType = field.getUnspecifiedType() and
isGLValue = false
) or
(
tag = getFieldDefaultValueStoreTag() and
opcode instanceof Opcode::Store and
resultType = field.getType().getUnspecifiedType() and
resultType = field.getUnspecifiedType() and
isGLValue = false
)
}
@@ -596,7 +596,7 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
override string getInstructionConstantValue(InstructionTag tag) {
tag = getFieldDefaultValueTag() and
result = getZeroValue(field.getType().getUnspecifiedType())
result = getZeroValue(field.getUnspecifiedType())
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -711,7 +711,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
}
final Type getElementType() {
result = initList.getType().getUnspecifiedType().(ArrayType).
result = initList.getUnspecifiedType().(ArrayType).
getBaseType().getUnspecifiedType()
}
}

View File

@@ -630,6 +630,105 @@ class TranslatedForStmt extends TranslatedLoop {
}
}
/**
* The IR translation of a range-based `for` loop.
* Note that this class does not extend `TranslatedLoop`. This is because the "body" of the
* range-based `for` loop consists of the per-iteration variable declaration followed by the
* user-written body statement. It is easier to handle the control flow of the loop separately,
* rather than synthesizing a single body or complicating the interface of `TranslatedLoop`.
*/
class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
override RangeBasedForStmt stmt;
override TranslatedElement getChild(int id) {
id = 0 and result = getRangeVariableDeclaration() or
id = 1 and result = getBeginVariableDeclaration() or
id = 2 and result = getEndVariableDeclaration() or
id = 3 and result = getCondition() or
id = 4 and result = getUpdate() or
id = 5 and result = getVariableDeclaration() or
id = 6 and result = getBody()
}
override Instruction getFirstInstruction() {
result = getRangeVariableDeclaration().getFirstInstruction()
}
override Instruction getChildSuccessor(TranslatedElement child) {
(
child = getRangeVariableDeclaration() and
result = getBeginVariableDeclaration().getFirstInstruction()
) or
(
child = getBeginVariableDeclaration() and
result = getEndVariableDeclaration().getFirstInstruction()
) or
(
child = getEndVariableDeclaration() and
result = getCondition().getFirstInstruction()
) or
(
child = getVariableDeclaration() and
result = getBody().getFirstInstruction()
) or
(
child = getBody() and
result = getUpdate().getFirstInstruction()
) or
(
child = getUpdate() and
result = getCondition().getFirstInstruction()
)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type resultType,
boolean isGLValue) {
none()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
none()
}
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
child = getCondition() and result = getVariableDeclaration().getFirstInstruction()
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
child = getCondition() and result = getParent().getChildSuccessor(this)
}
private TranslatedRangeBasedForVariableDeclaration getRangeVariableDeclaration() {
result = getTranslatedRangeBasedForVariableDeclaration(stmt.getRangeVariable())
}
private TranslatedRangeBasedForVariableDeclaration getBeginVariableDeclaration() {
result = getTranslatedRangeBasedForVariableDeclaration(stmt.getBeginVariable())
}
private TranslatedRangeBasedForVariableDeclaration getEndVariableDeclaration() {
result = getTranslatedRangeBasedForVariableDeclaration(stmt.getEndVariable())
}
// Public for getInstructionBackEdgeSuccessor
final TranslatedCondition getCondition() {
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
}
// Public for getInstructionBackEdgeSuccessor
final TranslatedExpr getUpdate() {
result = getTranslatedExpr(stmt.getUpdate().getFullyConverted())
}
private TranslatedRangeBasedForVariableDeclaration getVariableDeclaration() {
result = getTranslatedRangeBasedForVariableDeclaration(stmt.getVariable())
}
private TranslatedStmt getBody() {
result = getTranslatedStmt(stmt.getStmt())
}
}
class TranslatedJumpStmt extends TranslatedStmt {
override JumpStmt stmt;
@@ -711,3 +810,81 @@ class TranslatedSwitchStmt extends TranslatedStmt {
child = getBody() and result = getParent().getChildSuccessor(this)
}
}
class TranslatedAsmStmt extends TranslatedStmt {
override AsmStmt stmt;
override TranslatedElement getChild(int id) {
none()
}
override Instruction getFirstInstruction() {
if exists(stmt.getChild(0))
then result = getInstruction(AsmInputTag(0))
else result = getInstruction(AsmTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
tag = AsmTag() and
opcode instanceof Opcode::InlineAsm and
resultType instanceof UnknownType and
isGLValue = false
or
exists(int index, VariableAccess va |
tag = AsmInputTag(index) and
stmt.getChild(index) = va and
opcode instanceof Opcode::VariableAddress and
resultType = va.getType().getUnspecifiedType() and
isGLValue = true
)
}
override IRVariable getInstructionVariable(InstructionTag tag) {
exists(int index |
tag = AsmInputTag(index) and
result = getIRUserVariable(stmt.getEnclosingFunction(), stmt.getChild(index).(VariableAccess).getTarget())
)
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
tag = AsmTag() and
operandTag instanceof SideEffectOperandTag and
result = getTranslatedFunction(stmt.getEnclosingFunction()).getUnmodeledDefinitionInstruction()
or
exists(int index |
tag = AsmTag() and
operandTag = asmOperand(index) and
result = getInstruction(AsmInputTag(index))
)
}
override final Type getInstructionOperandType(InstructionTag tag,
TypedOperandTag operandTag) {
tag = AsmTag() and
operandTag instanceof SideEffectOperandTag and
result instanceof UnknownType
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
tag = AsmTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
or
exists(int index |
tag = AsmInputTag(index) and
kind instanceof GotoEdge and
if exists(stmt.getChild(index + 1))
then
result = getInstruction(AsmInputTag(index + 1))
else
result = getInstruction(AsmTag())
)
}
override Instruction getChildSuccessor(TranslatedElement child) {
none()
}
}

View File

@@ -40,7 +40,7 @@ module InstructionSanity {
opcode instanceof Opcode::Chi and tag instanceof ChiTotalOperandTag or
opcode instanceof Opcode::Chi and tag instanceof ChiPartialOperandTag or
(
(opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode) and
(opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode or opcode instanceof Opcode::InlineAsm) and
tag instanceof SideEffectOperandTag
)
)
@@ -73,7 +73,8 @@ module InstructionSanity {
operand.getOperandTag() = tag) and
not expectsOperand(instr, tag) and
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag) and
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
}
/**
@@ -1474,6 +1475,19 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
}
}
/**
* An instruction representing a GNU or MSVC inline assembly statement.
*/
class InlineAsmInstruction extends Instruction {
InlineAsmInstruction() {
getOpcode() instanceof Opcode::InlineAsm
}
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof EscapedMayMemoryAccess
}
}
/**
* An instruction that throws an exception.
*/

View File

@@ -105,19 +105,10 @@ class ValueNumber extends TValueNumber {
* definition because it accesses the exact same memory.
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
*
* This concept should probably be exposed in the public IR API.
*/
private class CongruentCopyInstruction extends CopyInstruction {
CongruentCopyInstruction() {
exists(Instruction def |
def = this.getSourceValue() and
(
def.getResultMemoryAccess() instanceof IndirectMemoryAccess or
def.getResultMemoryAccess() instanceof PhiMemoryAccess or
not def.hasMemoryResult()
)
)
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
}
}

View File

@@ -18,13 +18,13 @@ private Type getDecayedType(Type type) {
*/
Type getVariableType(Variable v) {
exists(Type declaredType |
declaredType = v.getType().getUnspecifiedType() and
declaredType = v.getUnspecifiedType() and
if v instanceof Parameter then (
result = getDecayedType(declaredType) or
not exists(getDecayedType(declaredType)) and result = declaredType
)
else if declaredType instanceof ArrayType and not declaredType.(ArrayType).hasArraySize() then (
result = v.getInitializer().getExpr().getType().getUnspecifiedType() or
result = v.getInitializer().getExpr().getUnspecifiedType() or
not exists(v.getInitializer()) and result = declaredType
)
else (

View File

@@ -28,7 +28,12 @@ private newtype TOperandTag =
)
} or
TChiTotalOperand() or
TChiPartialOperand()
TChiPartialOperand() or
TAsmOperand(int index) {
exists(AsmStmt asm |
exists(asm.getChild(index))
)
}
/**
* Identifies the kind of operand on an instruction. Each `Instruction` has at
@@ -362,3 +367,27 @@ class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
ChiPartialOperandTag chiPartialOperand() {
result = TChiPartialOperand()
}
class AsmOperandTag extends RegisterOperandTag, TAsmOperand {
int index;
AsmOperandTag() {
this = TAsmOperand(index)
}
override final string toString() {
result = "AsmOperand(" + index + ")"
}
override final int getSortOrder() {
result = 15 + index
}
override final string getLabel() {
result = index.toString() + ":"
}
}
AsmOperandTag asmOperand(int index) {
result = TAsmOperand(index)
}

View File

@@ -35,7 +35,7 @@ class PureFunction extends ArrayFunction, TaintFunction {
}
override predicate hasArrayInput(int bufParam) {
getParameter(bufParam).getType().getUnspecifiedType() instanceof PointerType
getParameter(bufParam).getUnspecifiedType() instanceof PointerType
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -43,13 +43,13 @@ class PureFunction extends ArrayFunction, TaintFunction {
input.isInParameter(i) or
(
input.isInParameterPointer(i) and
getParameter(i).getType().getUnspecifiedType() instanceof PointerType
getParameter(i).getUnspecifiedType() instanceof PointerType
)
) and
(
(
output.isOutReturnPointer() and
getType().getUnspecifiedType() instanceof PointerType
getUnspecifiedType() instanceof PointerType
) or
output.isOutReturnValue()
)

View File

@@ -184,7 +184,7 @@ Field getAnInitialField(PaddedType t) {
result = t.getAField() or
// Initial field of the type of a field of the union
result = getAnInitialField(
t.getAField().getType().getUnspecifiedType().(PaddedType))
t.getAField().getUnspecifiedType().(PaddedType))
)
else (
exists(Field firstField |
@@ -193,7 +193,7 @@ Field getAnInitialField(PaddedType t) {
result = firstField or
// Initial field of the first field of `t`
result = getAnInitialField(
firstField.getType().getUnspecifiedType().(PaddedType))
firstField.getUnspecifiedType().(PaddedType))
)
)
}
@@ -212,7 +212,7 @@ abstract class UnixArchitecture extends Architecture {
if(not exists(cd.getBaseClass().getABaseClass*().getAField()) and
not exists(PaddedType fieldType |
fieldType = getAnInitialField(cd.getDerivedClass()).
getType().getUnspecifiedType() and (
getUnspecifiedType() and (
// Check if the type of the field is a base type of the class, or
// vice versa. This is an approximation of the actual rule, which is
// that the field type and the class must not share a common

View File

@@ -207,8 +207,8 @@ predicate linearAccessImpl(Expr expr, VariableAccess v, float p, float q) {
// (larger_type)(p*v+q) == p*v + q
exists (Cast cast, ArithmeticType sourceType, ArithmeticType targetType
| linearAccess(cast.getExpr(), v, p, q) and
sourceType = cast.getExpr().getType().getUnspecifiedType() and
targetType = cast.getType().getUnspecifiedType() and
sourceType = cast.getExpr().getUnspecifiedType() and
targetType = cast.getUnspecifiedType() and
// This allows conversion between signed and unsigned, which is technically
// lossy but common enough that we'll just have to assume the user knows
// what they're doing.
@@ -338,7 +338,7 @@ float typeUpperBound(ArithmeticType t) {
* `exprMinVal(expr.getFullyConverted())`.
*/
float exprMinVal(Expr expr) {
result = typeLowerBound(expr.getType().getUnspecifiedType())
result = typeLowerBound(expr.getUnspecifiedType())
}
/**
@@ -353,7 +353,7 @@ float exprMinVal(Expr expr) {
* `exprMaxVal(expr.getFullyConverted())`.
*/
float exprMaxVal(Expr expr) {
result = typeUpperBound(expr.getType().getUnspecifiedType())
result = typeUpperBound(expr.getUnspecifiedType())
}
/**
@@ -364,7 +364,7 @@ float exprMaxVal(Expr expr) {
* `-2^31`.
*/
float varMinVal(Variable v) {
result = typeLowerBound(v.getType().getUnspecifiedType())
result = typeLowerBound(v.getUnspecifiedType())
}
/**
@@ -375,5 +375,5 @@ float varMinVal(Variable v) {
* `2^31 - 1`.
*/
float varMaxVal(Variable v) {
result = typeUpperBound(v.getType().getUnspecifiedType())
result = typeUpperBound(v.getUnspecifiedType())
}

View File

@@ -106,6 +106,9 @@ predicate analyzableExpr(Expr e) {
(e instanceof ConditionalExpr) or
(e instanceof AddExpr) or
(e instanceof SubExpr) or
(e instanceof AssignExpr) or
(e instanceof AssignAddExpr) or
(e instanceof AssignSubExpr) or
(e instanceof CrementOperation) or
(e instanceof RemExpr) or
(e instanceof CommaExpr) or
@@ -203,6 +206,18 @@ predicate exprDependsOnDef(
| e = subExpr
| exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar))
or
exists (AssignExpr addExpr
| e = addExpr
| exprDependsOnDef(addExpr.getRValue(), srcDef, srcVar))
or
exists (AssignAddExpr addExpr
| e = addExpr
| exprDependsOnDef(addExpr.getAnOperand(), srcDef, srcVar))
or
exists (AssignSubExpr subExpr
| e = subExpr
| exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar))
or
exists (CrementOperation crementExpr
| e = crementExpr
| exprDependsOnDef(crementExpr.getOperand(), srcDef, srcVar))
@@ -278,7 +293,7 @@ predicate isRecursiveDef(RangeSsaDefinition def, LocalScopeVariable v) {
*/
private
predicate assignmentDef(RangeSsaDefinition def, LocalScopeVariable v, Expr expr) {
v.getType().getUnspecifiedType() instanceof ArithmeticType
v.getUnspecifiedType() instanceof ArithmeticType
and
((def = v.getInitializer().getExpr() and def = expr)
or
@@ -534,6 +549,22 @@ float getLowerBoundsImpl(Expr expr) {
yHigh = getFullyConvertedUpperBounds(subExpr.getRightOperand()) and
result = addRoundingDown(xLow, -yHigh))
or
exists (AssignExpr assign
| expr = assign and
result = getFullyConvertedLowerBounds(assign.getRValue()))
or
exists (AssignAddExpr addExpr, float xLow, float yLow
| expr = addExpr and
xLow = getFullyConvertedLowerBounds(addExpr.getLValue()) and
yLow = getFullyConvertedLowerBounds(addExpr.getRValue()) and
result = addRoundingDown(xLow, yLow))
or
exists (AssignSubExpr subExpr, float xLow, float yHigh
| expr = subExpr and
xLow = getFullyConvertedLowerBounds(subExpr.getLValue()) and
yHigh = getFullyConvertedUpperBounds(subExpr.getRValue()) and
result = addRoundingDown(xLow, -yHigh))
or
exists (PrefixIncrExpr incrExpr, float xLow
| expr = incrExpr and
xLow = getFullyConvertedLowerBounds(incrExpr.getOperand()) and
@@ -587,7 +618,7 @@ float getLowerBoundsImpl(Expr expr) {
// whether the value of the expression is equal to 0.
exists (Conversion convExpr
| expr = convExpr
| if convExpr.getType().getUnspecifiedType() instanceof BoolType
| if convExpr.getUnspecifiedType() instanceof BoolType
then result = boolConversionLowerBound(convExpr.getExpr())
else result = getTruncatedLowerBounds(convExpr.getExpr()))
or
@@ -656,6 +687,22 @@ float getUpperBoundsImpl(Expr expr) {
yLow = getFullyConvertedLowerBounds(subExpr.getRightOperand()) and
result = addRoundingUp(xHigh, -yLow))
or
exists (AssignExpr assign
| expr = assign and
result = getFullyConvertedUpperBounds(assign.getRValue()))
or
exists (AssignAddExpr addExpr, float xHigh, float yHigh
| expr = addExpr and
xHigh = getFullyConvertedUpperBounds(addExpr.getLValue()) and
yHigh = getFullyConvertedUpperBounds(addExpr.getRValue()) and
result = addRoundingUp(xHigh, yHigh))
or
exists (AssignSubExpr subExpr, float xHigh, float yLow
| expr = subExpr and
xHigh = getFullyConvertedUpperBounds(subExpr.getLValue()) and
yLow = getFullyConvertedLowerBounds(subExpr.getRValue()) and
result = addRoundingUp(xHigh, -yLow))
or
exists (PrefixIncrExpr incrExpr, float xHigh
| expr = incrExpr and
xHigh = getFullyConvertedUpperBounds(incrExpr.getOperand()) and
@@ -705,7 +752,7 @@ float getUpperBoundsImpl(Expr expr) {
// whether the value of the expression is equal to 0.
exists (Conversion convExpr
| expr = convExpr
| if convExpr.getType().getUnspecifiedType() instanceof BoolType
| if convExpr.getUnspecifiedType() instanceof BoolType
then result = boolConversionUpperBound(convExpr.getExpr())
else result = getTruncatedUpperBounds(convExpr.getExpr()))
or
@@ -730,7 +777,7 @@ private predicate exprIsUsedAsBool(Expr expr) {
expr = any(UnaryLogicalOperation op).getOperand().getFullyConverted() or
expr = any(ConditionalExpr c).getCondition().getFullyConverted() or
exists (Conversion cast
| cast.getType().getUnspecifiedType() instanceof BoolType
| cast.getUnspecifiedType() instanceof BoolType
| expr = cast.getExpr())
}
@@ -944,7 +991,7 @@ float getDefLowerBounds(RangeSsaDefinition def, LocalScopeVariable v) {
// recursion from exploding.
result =
max (float widenLB
| widenLB = wideningLowerBounds(v.getType().getUnspecifiedType()) and
| widenLB = wideningLowerBounds(v.getUnspecifiedType()) and
not (widenLB > truncatedLB)
| widenLB)
else result = truncatedLB)
@@ -970,7 +1017,7 @@ float getDefUpperBounds(RangeSsaDefinition def, LocalScopeVariable v) {
// from exploding.
result =
min (float widenUB
| widenUB = wideningUpperBounds(v.getType().getUnspecifiedType()) and
| widenUB = wideningUpperBounds(v.getUnspecifiedType()) and
not (widenUB < truncatedUB)
| widenUB)
else result = truncatedUB)
@@ -1001,9 +1048,9 @@ predicate unanalyzableDefBounds(
*/
bindingset[guard, v, branch]
predicate nonNanGuardedVariable(ComparisonOperation guard, VariableAccess v, boolean branch) {
v.getType().getUnspecifiedType() instanceof IntegralType
v.getUnspecifiedType() instanceof IntegralType
or
v.getType().getUnspecifiedType() instanceof FloatingPointType and v instanceof NonNanVariableAccess
v.getUnspecifiedType() instanceof FloatingPointType and v instanceof NonNanVariableAccess
or
// The reason the following case is here is to ensure that when we say
// `if (x > 5) { ...then... } else { ...else... }`
@@ -1026,7 +1073,7 @@ predicate lowerBoundFromGuard(
| boundFromGuard(guard, v, childLB, true, strictness, branch)
| if nonNanGuardedVariable(guard, v, branch)
then (if (strictness = Nonstrict() or
not (v.getType().getUnspecifiedType() instanceof IntegralType))
not (v.getUnspecifiedType() instanceof IntegralType))
then lb = childLB
else lb = childLB+1)
else lb = varMinVal(v.getTarget()))
@@ -1045,7 +1092,7 @@ predicate upperBoundFromGuard(
| boundFromGuard(guard, v, childUB, false, strictness, branch)
| if nonNanGuardedVariable(guard, v, branch)
then (if (strictness = Nonstrict() or
not (v.getType().getUnspecifiedType() instanceof IntegralType))
not (v.getUnspecifiedType() instanceof IntegralType))
then ub = childUB
else ub = childUB-1)
else ub = varMaxVal(v.getTarget()))
@@ -1088,7 +1135,7 @@ predicate linearBoundFromGuard(
// For the comparison x < RHS, we create two bounds:
//
// 1. x < upperbound(RHS)
// 2. x >= typeLowerBound(RHS.getType().getUnspecifiedType())
// 2. x >= typeLowerBound(RHS.getUnspecifiedType())
//
exists (Expr lhs, Expr rhs, RelationDirection dir, RelationStrictness st
| linearAccess(lhs, v, p, q) and
@@ -1108,8 +1155,8 @@ predicate linearBoundFromGuard(
//
// For x != RHS, we create trivial bounds:
//
// 1. x <= typeUpperBound(RHS.getType().getUnspecifiedType())
// 2. x >= typeLowerBound(RHS.getType().getUnspecifiedType())
// 1. x <= typeUpperBound(RHS.getUnspecifiedType())
// 2. x >= typeLowerBound(RHS.getUnspecifiedType())
//
or
exists (Expr lhs, Expr rhs, boolean isEQ
@@ -1156,7 +1203,7 @@ private cached module SimpleRangeAnalysisCached {
// single minimum value.
result = min(float lb | lb = getTruncatedLowerBounds(expr) | lb)
}
/**
* Gets the upper bound of the expression.
*
@@ -1175,7 +1222,7 @@ private cached module SimpleRangeAnalysisCached {
// single maximum value.
result = max(float ub | ub = getTruncatedUpperBounds(expr) | ub)
}
/**
* Holds if `expr` has a provably empty range. For example:
*
@@ -1204,13 +1251,13 @@ private cached module SimpleRangeAnalysisCached {
predicate defMightOverflowNegatively(RangeSsaDefinition def, LocalScopeVariable v) {
getDefLowerBoundsImpl(def, v) < varMinVal(v)
}
/** Holds if the definition might overflow positively. */
cached
predicate defMightOverflowPositively(RangeSsaDefinition def, LocalScopeVariable v) {
getDefUpperBoundsImpl(def, v) > varMaxVal(v)
}
/**
* Holds if the definition might overflow (either positively or
* negatively).
@@ -1220,7 +1267,7 @@ private cached module SimpleRangeAnalysisCached {
defMightOverflowNegatively(def, v) or
defMightOverflowPositively(def, v)
}
/**
* Holds if the expression might overflow negatively. This predicate
* does not consider the possibility that the expression might overflow
@@ -1228,9 +1275,14 @@ private cached module SimpleRangeAnalysisCached {
*/
cached
predicate exprMightOverflowNegatively(Expr expr) {
getLowerBoundsImpl(expr) < exprMinVal(expr)
getLowerBoundsImpl(expr) < exprMinVal(expr) or
// The lower bound of the expression `x--` is the same as the lower
// bound of `x`, so the standard logic (above) does not work for
// detecting whether it might overflow.
getLowerBoundsImpl(expr.(PostfixDecrExpr)) = exprMinVal(expr)
}
/**
* Holds if the expression might overflow negatively. Conversions
* are also taken into account. For example the expression
@@ -1242,7 +1294,7 @@ private cached module SimpleRangeAnalysisCached {
exprMightOverflowNegatively(expr) or
convertedExprMightOverflowNegatively(expr.getConversion())
}
/**
* Holds if the expression might overflow positively. This predicate
* does not consider the possibility that the expression might overflow
@@ -1250,9 +1302,14 @@ private cached module SimpleRangeAnalysisCached {
*/
cached
predicate exprMightOverflowPositively(Expr expr) {
getUpperBoundsImpl(expr) > exprMaxVal(expr)
getUpperBoundsImpl(expr) > exprMaxVal(expr) or
// The upper bound of the expression `x++` is the same as the upper
// bound of `x`, so the standard logic (above) does not work for
// detecting whether it might overflow.
getUpperBoundsImpl(expr.(PostfixIncrExpr)) = exprMaxVal(expr)
}
/**
* Holds if the expression might overflow positively. Conversions
* are also taken into account. For example the expression
@@ -1264,7 +1321,7 @@ private cached module SimpleRangeAnalysisCached {
exprMightOverflowPositively(expr) or
convertedExprMightOverflowPositively(expr.getConversion())
}
/**
* Holds if the expression might overflow (either positively or
* negatively). The possibility that the expression might overflow

View File

@@ -157,7 +157,7 @@ class StrCopyBW extends BufferWriteCall
override Type getBufferType()
{
result = this.getTarget().getParameter(getParamSrc()).getType().getUnspecifiedType()
result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType()
}
override Expr getASource()
@@ -212,7 +212,7 @@ class StrCatBW extends BufferWriteCall
override Type getBufferType()
{
result = this.getTarget().getParameter(getParamSrc()).getType().getUnspecifiedType()
result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType()
}
override Expr getASource()
@@ -267,7 +267,7 @@ class SprintfBW extends BufferWriteCall
{
exists(FormattingFunction f |
f = this.getTarget() and
result = f.getParameter(f.getFormatParameterIndex()).getType().getUnspecifiedType()
result = f.getParameter(f.getFormatParameterIndex()).getUnspecifiedType()
)
}
@@ -355,7 +355,7 @@ class SnprintfBW extends BufferWriteCall
{
exists(FormattingFunction f |
f = this.getTarget() and
result = f.getParameter(f.getFormatParameterIndex()).getType().getUnspecifiedType()
result = f.getParameter(f.getFormatParameterIndex()).getUnspecifiedType()
)
}
@@ -423,7 +423,7 @@ class GetsBW extends BufferWriteCall
override Type getBufferType()
{
result = this.getTarget().getParameter(0).getType().getUnspecifiedType()
result = this.getTarget().getParameter(0).getUnspecifiedType()
}
override Expr getASource()
@@ -479,7 +479,7 @@ class ScanfBW extends BufferWrite
exists(ScanfFunction f, ScanfFunctionCall fc |
this = fc.getArgument(_) and
f = fc.getTarget() and
result = f.getParameter(f.getFormatParameterIndex()).getType().getUnspecifiedType()
result = f.getParameter(f.getFormatParameterIndex()).getUnspecifiedType()
)
}
@@ -537,7 +537,7 @@ class RealpathBW extends BufferWriteCall {
override Type getBufferType()
{
result = this.getTarget().getParameter(0).getType().getUnspecifiedType()
result = this.getTarget().getParameter(0).getUnspecifiedType()
}
override Expr getDest() { result = getArgument(1) }

View File

@@ -66,7 +66,7 @@ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) {
// overflow possible if large
(e instanceof AddExpr and not guardedLesser(e, varUse(v))) or
(e instanceof AssignAddExpr and not guardedLesser(e, varUse(v))) or
(e instanceof IncrementOperation and not guardedLesser(e, varUse(v)) and v.getType().getUnspecifiedType() instanceof IntegralType) or
(e instanceof IncrementOperation and not guardedLesser(e, varUse(v)) and v.getUnspecifiedType() instanceof IntegralType) or
// overflow possible if large or small
(e instanceof MulExpr and
not (guardedLesser(e, varUse(v)) and guardedGreater(e, varUse(v))))
@@ -81,7 +81,7 @@ predicate missingGuardAgainstUnderflow(Operation e, VariableAccess use) {
(use = e.(SubExpr).getLeftOperand() and not guardedGreater(e, varUse(v))) or
(use = e.(AssignSubExpr).getLValue() and not guardedGreater(e, varUse(v))) or
// underflow possible if small
(e instanceof DecrementOperation and not guardedGreater(e, varUse(v)) and v.getType().getUnspecifiedType() instanceof IntegralType) or
(e instanceof DecrementOperation and not guardedGreater(e, varUse(v)) and v.getUnspecifiedType() instanceof IntegralType) or
// underflow possible if large or small
(e instanceof MulExpr and
not (guardedLesser(e, varUse(v)) and guardedGreater(e, varUse(v))))

View File

@@ -675,7 +675,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
* ```
* the result is `int x`.
*/
Variable getVariable() { result = getChild(4).(DeclStmt).getADeclaration() }
LocalVariable getVariable() { result = getChild(4).(DeclStmt).getADeclaration() }
/**
* Gets the expression giving the range to iterate over.
@@ -689,7 +689,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
Expr getRange() { result = getRangeVariable().getInitializer().getExpr() }
/** Gets the compiler-generated `__range` variable after desugaring. */
Variable getRangeVariable() {
LocalVariable getRangeVariable() {
result = getChild(0).(DeclStmt).getADeclaration()
}
@@ -709,6 +709,16 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
*/
DeclStmt getBeginEndDeclaration() { result = this.getChild(1) }
/** Gets the compiler-generated `__begin` variable after desugaring. */
LocalVariable getBeginVariable() {
result = getBeginEndDeclaration().getDeclaration(0)
}
/** Gets the compiler-generated `__end` variable after desugaring. */
LocalVariable getEndVariable() {
result = getBeginEndDeclaration().getDeclaration(1)
}
/**
* Gets the compiler-generated `++__begin` which is the update
* expression of this for statement after desugaring. It will
@@ -718,8 +728,8 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for {
Expr getUpdate() { result = this.getChild(3) }
/** Gets the compiler-generated `__begin` variable after desugaring. */
Variable getAnIterationVariable() {
result = getUpdate().getAChild().(VariableAccess).getTarget()
LocalVariable getAnIterationVariable() {
result = getBeginVariable()
}
}

View File

@@ -285,25 +285,25 @@ class GVN extends GVNBase {
private predicate analyzableIntConst(Expr e) {
strictcount (e.getValue().toInt()) = 1 and
strictcount (e.getType().getUnspecifiedType()) = 1
strictcount (e.getUnspecifiedType()) = 1
}
private predicate mk_IntConst(int val, Type t, Expr e) {
analyzableIntConst(e) and
val = e.getValue().toInt() and
t = e.getType().getUnspecifiedType()
t = e.getUnspecifiedType()
}
private predicate analyzableFloatConst(Expr e) {
strictcount (e.getValue().toFloat()) = 1 and
strictcount (e.getType().getUnspecifiedType()) = 1 and
strictcount (e.getUnspecifiedType()) = 1 and
not analyzableIntConst(e)
}
private predicate mk_FloatConst(float val, Type t, Expr e) {
analyzableFloatConst(e) and
val = e.getValue().toFloat() and
t = e.getType().getUnspecifiedType()
t = e.getUnspecifiedType()
}
@@ -421,14 +421,14 @@ private predicate mk_OtherVariable(
}
private predicate analyzableConversion(Conversion conv) {
strictcount (conv.getType().getUnspecifiedType()) = 1 and
strictcount (conv.getUnspecifiedType()) = 1 and
strictcount (conv.getExpr()) = 1 and
not analyzableConst(conv)
}
private predicate mk_Conversion(Type t, GVN child, Conversion conv) {
analyzableConversion(conv) and
t = conv.getType().getUnspecifiedType() and
t = conv.getUnspecifiedType() and
child = globalValueNumber(conv.getExpr())
}

View File

@@ -189,7 +189,7 @@ private newtype HC_Args =
private newtype HC_Fields =
HC_EmptyFields(Class c) {
exists(ClassAggregateLiteral cal |
c = cal.getType().getUnspecifiedType()
c = cal.getUnspecifiedType()
)
}
or
@@ -200,7 +200,7 @@ private newtype HC_Fields =
private newtype HC_Array =
HC_EmptyArray(Type t) {
exists(ArrayAggregateLiteral aal |
aal.getType().getUnspecifiedType() = t
aal.getUnspecifiedType() = t
)
}
or
@@ -305,42 +305,42 @@ private string exampleLocationString(Location l) {
private predicate analyzableIntLiteral(Literal e) {
strictcount (e.getValue().toInt()) = 1 and
strictcount (e.getType().getUnspecifiedType()) = 1 and
e.getType().getUnspecifiedType() instanceof IntegralType
strictcount (e.getUnspecifiedType()) = 1 and
e.getUnspecifiedType() instanceof IntegralType
}
private predicate mk_IntLiteral(int val, Type t, Expr e) {
analyzableIntLiteral(e) and
val = e.getValue().toInt() and
t = e.getType().getUnspecifiedType()
t = e.getUnspecifiedType()
}
private predicate analyzableEnumConstantAccess(EnumConstantAccess e) {
strictcount (e.getValue().toInt()) = 1 and
strictcount (e.getType().getUnspecifiedType()) = 1 and
e.getType().getUnspecifiedType() instanceof Enum
strictcount (e.getUnspecifiedType()) = 1 and
e.getUnspecifiedType() instanceof Enum
}
private predicate mk_EnumConstantAccess(EnumConstant val, Type t, Expr e) {
analyzableEnumConstantAccess(e) and
val = e.(EnumConstantAccess).getTarget() and
t = e.getType().getUnspecifiedType()
t = e.getUnspecifiedType()
}
private predicate analyzableFloatLiteral(Literal e) {
strictcount (e.getValue().toFloat()) = 1 and
strictcount (e.getType().getUnspecifiedType()) = 1 and
e.getType().getUnspecifiedType() instanceof FloatingPointType
strictcount (e.getUnspecifiedType()) = 1 and
e.getUnspecifiedType() instanceof FloatingPointType
}
private predicate mk_FloatLiteral(float val, Type t, Expr e) {
analyzableFloatLiteral(e) and
val = e.getValue().toFloat() and
t = e.getType().getUnspecifiedType()
t = e.getUnspecifiedType()
}
private predicate analyzableNullptr(NullValue e) {
strictcount (e.getType().getUnspecifiedType()) = 1 and
strictcount (e.getUnspecifiedType()) = 1 and
e.getType() instanceof NullPointerType
}
@@ -350,14 +350,14 @@ private predicate mk_Nullptr(Expr e) {
private predicate analyzableStringLiteral(Literal e) {
strictcount(e.getValue()) = 1 and
strictcount(e.getType().getUnspecifiedType()) = 1 and
e.getType().getUnspecifiedType().(ArrayType).getBaseType() instanceof CharType
strictcount(e.getUnspecifiedType()) = 1 and
e.getUnspecifiedType().(ArrayType).getBaseType() instanceof CharType
}
private predicate mk_StringLiteral(string val, Type t, Expr e) {
analyzableStringLiteral(e) and
val = e.getValue() and
t = e.getType().getUnspecifiedType() and
t = e.getUnspecifiedType() and
t.(ArrayType).getBaseType() instanceof CharType
}
@@ -410,13 +410,13 @@ private predicate mk_Variable(Variable x, VariableAccess access) {
}
private predicate analyzableConversion(Conversion conv) {
strictcount (conv.getType().getUnspecifiedType()) = 1 and
strictcount (conv.getUnspecifiedType()) = 1 and
strictcount (conv.getExpr()) = 1
}
private predicate mk_Conversion(Type t, HashCons child, Conversion conv) {
analyzableConversion(conv) and
t = conv.getType().getUnspecifiedType() and
t = conv.getUnspecifiedType() and
child = hashCons(conv.getExpr())
}
@@ -586,7 +586,7 @@ private predicate mk_ArgConsInner(HashCons head, HC_Args tail, int i, HC_Args li
private predicate analyzableAllocatorArgZero(ErrorExpr e) {
exists(NewOrNewArrayExpr new |
new.getAllocatorCall().getChild(0) = e and
strictcount(new.getType().getUnspecifiedType()) = 1
strictcount(new.getUnspecifiedType()) = 1
)
and
strictcount(NewOrNewArrayExpr new | new.getAllocatorCall().getChild(0) = e) = 1
@@ -596,7 +596,7 @@ private predicate mk_AllocatorArgZero(Type t, ErrorExpr e) {
analyzableAllocatorArgZero(e) and
exists(NewOrNewArrayExpr new |
new.getAllocatorCall().getChild(0) = e and
t = new.getType().getUnspecifiedType()
t = new.getUnspecifiedType()
)
}
@@ -691,7 +691,7 @@ private predicate mk_DeleteArrayExpr(HashCons hc, DeleteArrayExpr e) {
}
private predicate analyzableSizeofType(SizeofTypeOperator e) {
strictcount(e.getType().getUnspecifiedType()) = 1 and
strictcount(e.getUnspecifiedType()) = 1 and
strictcount(e.getTypeOperand()) = 1
}
@@ -740,7 +740,7 @@ private predicate mk_TypeidExpr(HashCons child, TypeidOperator e) {
}
private predicate analyzableAlignofType(AlignofTypeOperator e) {
strictcount(e.getType().getUnspecifiedType()) = 1 and
strictcount(e.getUnspecifiedType()) = 1 and
strictcount(e.getTypeOperand()) = 1
}
@@ -761,7 +761,7 @@ private predicate mk_AlignofExpr(HashCons child, AlignofExprOperator e) {
private predicate mk_FieldCons(Class c, int i, Field f, HashCons hc, HC_Fields hcf,
ClassAggregateLiteral cal) {
analyzableClassAggregateLiteral(cal) and
cal.getType().getUnspecifiedType() = c and
cal.getUnspecifiedType() = c and
exists(Expr e |
e = cal.getFieldExpr(f).getFullyConverted() and
f.getInitializationOrder() = i and
@@ -791,7 +791,7 @@ private predicate analyzableClassAggregateLiteral(ClassAggregateLiteral cal) {
private predicate mk_ClassAggregateLiteral(Class c, HC_Fields hcf, ClassAggregateLiteral cal) {
analyzableClassAggregateLiteral(cal) and
c = cal.getType().getUnspecifiedType() and
c = cal.getUnspecifiedType() and
(
exists(HC_Fields tail, Expr e, Field f |
f.getInitializationOrder() = cal.getNumChild() - 1 and
@@ -810,12 +810,12 @@ private predicate analyzableArrayAggregateLiteral(ArrayAggregateLiteral aal) {
exists(aal.getChild(i)) |
strictcount(aal.getChild(i).getFullyConverted()) = 1
) and
strictcount(aal.getType().getUnspecifiedType()) = 1
strictcount(aal.getUnspecifiedType()) = 1
}
private predicate mk_ArrayCons(Type t, int i, HashCons hc, HC_Array hca, ArrayAggregateLiteral aal) {
analyzableArrayAggregateLiteral(aal) and
t = aal.getType().getUnspecifiedType() and
t = aal.getUnspecifiedType() and
hc = hashCons(aal.getChild(i)) and
(
exists(HC_Array tail, HashCons head |
@@ -829,7 +829,7 @@ private predicate mk_ArrayCons(Type t, int i, HashCons hc, HC_Array hca, ArrayAg
}
private predicate mk_ArrayAggregateLiteral(Type t, HC_Array hca, ArrayAggregateLiteral aal) {
t = aal.getType().getUnspecifiedType() and
t = aal.getUnspecifiedType() and
(
exists(HashCons head, HC_Array tail |
hca = HC_ArrayCons(t, aal.getNumChild() - 1, head, tail) and