mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
Merge branch 'master' into zlaski/cpp370
This commit is contained in:
@@ -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."
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
(
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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() +
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
15
cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.c
Normal file
15
cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.c
Normal 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);
|
||||
}
|
||||
@@ -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>
|
||||
18
cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql
Normal file
18
cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql
Normal 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"
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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."
|
||||
@@ -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(_, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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& 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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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).
|
||||
*
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() -
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -69,7 +69,7 @@ private predicate addressTakenVariable(LocalScopeVariable var) {
|
||||
}
|
||||
|
||||
private predicate isReferenceVar(LocalScopeVariable v) {
|
||||
v.getType().getUnspecifiedType() instanceof ReferenceType
|
||||
v.getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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" } }
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 + ")"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ abstract class TranslatedCondition extends TranslatedElement {
|
||||
}
|
||||
|
||||
final Type getResultType() {
|
||||
result = expr.getType().getUnspecifiedType()
|
||||
result = expr.getUnspecifiedType()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ class TranslatedFunction extends TranslatedElement,
|
||||
}
|
||||
|
||||
private final Type getReturnType() {
|
||||
result = func.getType().getUnspecifiedType()
|
||||
result = func.getUnspecifiedType()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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))))
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user