Merge branch 'master' into master

This commit is contained in:
Raul Garcia
2018-09-25 10:58:51 -07:00
committed by GitHub
328 changed files with 8737 additions and 7968 deletions

View File

@@ -1,2 +1,2 @@
[*.{ql,qll,qlref,dbscheme,qhelp,html,js,mjs,ts,json,yml}]
[*]
end_of_line = lf

63
.gitattributes vendored
View File

@@ -1,23 +1,48 @@
# The following file types will be normalized to LF line endings in the Git
# database, and will keep those LF line endings in the working tree even on
# Windows. Any other files will have whatever line endings they had when they
# were committed. If you add new entries below, you should renormalize the
# affected files by running the following from the root of this repo (requires
# Git 2.16 or greater):
# Text files will be normalized to LF line endings in the Git database, and will keep those LF line
# endings in the working tree even on Windows. If you make changes below, you should renormalize the
# affected files by running the following from the root of this repo (requires Git 2.16 or greater):
#
# git add --renormalize .
# git status [just to show what files were renormalized]
# git commit -m "Normalize line endings"
#
# Also, please update .editorconfig to handle any new entries as well.
*.ql eol=lf
*.qll eol=lf
*.qlref eol=lf
*.dbscheme eol=lf
*.qhelp eol=lf
*.html eol=lf
*.js eol=lf
*.mjs eol=lf
*.ts eol=lf
*.json eol=lf
*.yml eol=lf
# Anything Git auto-detects as text gets normalized and checked out as LF
* text=auto eol=lf
# Explicitly set a bunch of known extensions to text, in case auto detection gets confused.
*.ql text
*.qll text
*.qlref text
*.dbscheme text
*.qhelp text
*.html text
*.htm text
*.xhtml text
*.xhtm text
*.js text
*.mjs text
*.ts text
*.json text
*.yml text
*.yaml text
*.c text
*.cpp text
*.h text
*.hpp text
*.md text
*.stats text
*.xml text
*.sh text
*.pl text
*.java text
*.cs text
*.py text
*.lua text
*.expected text
# Explicitly set a bunch of known extensions to binary, because Git < 2.10 will treat
# `* text=auto eol=lf` as `* text eol=lf`
*.png -text
*.jpg -text
*.jpeg -text
*.gif -text

4
.gitignore vendored
View File

@@ -12,6 +12,4 @@
/.vs/ql/v15/Browse.VC.opendb
/.vs/ql/v15/Browse.VC.db
/.vs/ProjectSettings.json
/.vs/ql5/v15/Browse.VC.opendb
/.vs/ql5/v15/Browse.VC.db
/.vs/ql5/v15/.suo

View File

@@ -12,7 +12,7 @@
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
| *@name of query (Query ID)*| *Impact on results* | *How/why the query has changed* |
| Resource not released in destructor | Fewer false positive results | Placement new is now excluded from the query. |
## Changes to QL libraries

View File

@@ -22,5 +22,6 @@
| Regular expression injection | Fewer false-positive results | This rule now identifies calls to `String.prototype.search` with more precision. |
| Unbound event handler receiver | Fewer false-positive results | This rule now recognizes additional ways class methods can be bound. |
| Remote property injection | Fewer results | The precision of this rule has been revised to "medium". Results are no longer shown on LGTM by default. |
| Missing CSRF middleware | Fewer false-positive results | This rule now recognizes additional CSRF protection middlewares. |
## Changes to QL libraries

View File

@@ -21,17 +21,19 @@ import semmle.code.cpp.controlflow.SSA
/**
* Holds if `e` is either:
* - a constant
* - a char-typed expression, meaning it's a small number
* - an array access to an array of constants
* - flows from one of the above
* In these cases the value of `e` is likely to be small and
* controlled, so we consider it less likely to cause an overflow.
*/
predicate effectivelyConstant(Expr e) {
predicate likelySmall(Expr e) {
e.isConstant() or
e.getType().getSize() <= 1 or
e.(ArrayExpr).getArrayBase().getType().(ArrayType).getBaseType().isConst() or
exists(SsaDefinition def, Variable v |
def.getAUse(v) = e and
effectivelyConstant(def.getDefiningValue(v))
likelySmall(def.getDefiningValue(v))
)
}
@@ -56,7 +58,7 @@ int getEffectiveMulOperands(MulExpr me) {
result = count(Expr op |
op = getMulOperand*(me) and
not op instanceof MulExpr and
not effectivelyConstant(op)
not likelySmall(op)
)
}

View File

@@ -0,0 +1,7 @@
LPMALLOC pMalloc;
HRESULT hr = CoGetMalloc(1, &pMalloc);
if (!hr)
{
// code ...
}

View File

@@ -0,0 +1,26 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>This query indicates that an <code>HRESULT</code> is being cast to a boolean type or vice versa.</p>
<p>The typical success value (<code>S_OK</code>) of an <code>HRESULT</code> equals 0. However, 0 indicates failure for a boolean type.</p>
<p>Casting an <code>HRESULT</code> to a boolean type and then using it in a test expression will yield an incorrect result.</p>
</overview>
<recommendation>
<p>To check if a call that returns an HRESULT succeeded use the <code>FAILED</code> macro.</p>
</recommendation>
<example>
<p>In the following example, <code>HRESULT</code> is used in a test expression incorrectly as it may yield an incorrect result.</p>
<sample src="HResultBooleanConversion.cpp" />
<p>To fix this issue, use the <code>FAILED</code> macro in the test expression.</p>
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,71 @@
/**
* @name Cast between semantically different integer types: HRESULT to/from a Boolean type
* @description Cast between semantically different integer types: HRESULT to/from a Boolean type.
* Boolean types indicate success by a non-zero value, whereas success (S_OK) in HRESULT is indicated by a value of 0.
* Casting an HRESULT to/from a Boolean type and then using it in a test expression will yield an incorrect result.
* @kind problem
* @id cpp/hresult-boolean-conversion
* @problem.severity error
* @precision high
* @tags security
* external/cwe/cwe-253
* external/microsoft/C6214
* external/microsoft/C6215
* external/microsoft/C6216
* external/microsoft/C6217
* external/microsoft/C6230
*/
import cpp
predicate isHresultBooleanConverted( Expr e1, Cast e2 )
{
exists ( Type t1, Type t2 |
t1 = e1.getType() and
t2 = e2.getType() and
((t1.hasName("bool") or t1.hasName("BOOL") or t1.hasName("_Bool")) and t2.hasName("HRESULT") or
(t2.hasName("bool") or t2.hasName("BOOL") or t2.hasName("_Bool")) and t1.hasName("HRESULT")
))
}
predicate isHresultBooleanConverted( Expr e1 )
{
exists( Cast e2 |
e2 = e1.getConversion() and
isHresultBooleanConverted(e1, e2)
)
}
from Expr e1, string msg
where exists
(
Cast e2 |
e2 = e1.getConversion() |
isHresultBooleanConverted( e1, e2 )
and if e2.isImplicit() then ( msg = "Implicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString())
else ( msg = "Explicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString())
)
or exists
(
ControlStructure ctls |
ctls.getControllingExpr() = e1
and e1.getType().(TypedefType).hasName("HRESULT")
and not isHresultBooleanConverted(e1)
and msg = "Direct usage of a type " + e1.getType().toString() + " as a conditional expression"
)
or
(
exists( BinaryLogicalOperation blop |
blop.getAnOperand() = e1 |
e1.getType().(TypedefType).hasName("HRESULT")
and msg = "Usage of a type " + e1.getType().toString() + " as an argument of a binary logical operation"
)
or exists
(
UnaryLogicalOperation ulop |
ulop.getAnOperand() = e1 |
e1.getType().(TypedefType).hasName("HRESULT")
and msg = "Usage of a type " + e1.getType().toString() + " as an argument of a unary logical operation"
)
and not isHresultBooleanConverted(e1)
)
select e1, msg

View File

@@ -10,33 +10,69 @@
* external/cwe/cwe-404
*/
import cpp
import Critical.NewDelete
// List pairs of functions that do resource acquisition/release
// Extend this to add custom function pairs. As written the query
// will only apply if the resource is the *return value* of the
// first call and a *parameter* to the second. Other cases should
// be handled differently.
predicate resourceManagementPair(string acquire, string release) {
(acquire = "fopen" and release = "fclose")
or
(acquire = "open" and release = "close")
or
(acquire = "socket" and release = "close")
/**
* An expression that acquires a resource, and the kind of resource that is acquired. The
* kind of a resource indicates which acquisition/release expressions can be paired.
*/
predicate acquireExpr(Expr acquire, string kind) {
exists(FunctionCall fc, Function f, string name |
fc = acquire and
f = fc.getTarget() and
name = f.getName() and
(
(
name = "fopen" and
kind = "file"
) or (
name = "open" and
kind = "file descriptor"
) or (
name = "socket" and
kind = "file descriptor"
)
)
) or (
allocExpr(acquire, kind)
)
}
// List functions that return malloc-allocated memory. Customize
// to list your own functions there
predicate mallocFunction(Function malloc) {
malloc.hasName("malloc") or malloc.hasName("calloc") or // Not realloc: doesn't acquire it, really
malloc.hasName("strdup")
}
private predicate isRelease(string release) {
resourceManagementPair(_, release) or
release = "free" or
release = "delete"
/**
* An expression that releases a resource, and the kind of resource that is released. The
* kind of a resource indicates which acquisition/release expressions can be paired.
*/
predicate releaseExpr(Expr release, Expr resource, string kind) {
exists(FunctionCall fc, Function f, string name |
fc = release and
f = fc.getTarget() and
name = f.getName() and
(
(
name = "fclose" and
resource = fc.getArgument(0) and
kind = "file"
) or (
name = "close" and
resource = fc.getArgument(0) and
kind = "file descriptor"
)
)
) or exists(string releaseKind |
freeExpr(release, resource, releaseKind) and
(
(
kind = "malloc" and
releaseKind = "free"
) or (
kind = "new" and
releaseKind = "delete"
) or (
kind = "new[]" and
releaseKind = "delete[]"
)
)
)
}
/**
@@ -52,35 +88,23 @@ Expr exprOrDereference(Expr e) {
* Holds if the expression `e` releases expression `released`, whether directly
* or via one or more function call(s).
*/
private predicate exprReleases(Expr e, Expr released, string releaseType) {
private predicate exprReleases(Expr e, Expr released, string kind) {
(
// `e` is a call to a release function and `released` is any argument
e.(FunctionCall).getTarget().getName() = releaseType and
isRelease(releaseType) and
e.(FunctionCall).getAnArgument() = released
) or (
// `e` is a call to `delete` and `released` is the target
e.(DeleteExpr).getExpr() = released and
releaseType = "delete"
) or (
// `e` is a call to `delete[]` and `released` is the target
e.(DeleteArrayExpr).getExpr() = released and
releaseType = "delete"
// `e` is a call to a release function and `released` is the released argument
releaseExpr(e, released, kind)
) or exists(Function f, int arg |
// `e` is a call to a function that releases one of it's parameters,
// and `released` is the corresponding argument
e.(FunctionCall).getTarget() = f and
e.(FunctionCall).getArgument(arg) = released and
exprReleases(_, exprOrDereference(f.getParameter(arg).getAnAccess()), releaseType)
) or exists(Function f, Expr innerThis |
exprReleases(_, exprOrDereference(f.getParameter(arg).getAnAccess()), kind)
) or exists(Function f, ThisExpr innerThis |
// `e` is a call to a method that releases `this`, and `released`
// is the object that is called
e.(FunctionCall).getTarget() = f and
e.(FunctionCall).getQualifier() = exprOrDereference(released) and
innerThis.getEnclosingFunction() = f and
exprReleases(_, innerThis, releaseType) and
innerThis instanceof ThisExpr and
releaseType = "delete"
exprReleases(_, innerThis, kind)
)
}
@@ -109,28 +133,17 @@ class Resource extends MemberVariable {
)
}
predicate acquisitionWithRequiredRelease(Expr acquire, string releaseName) {
acquire.(Assignment).getLValue() = this.getAnAccess() and
predicate acquisitionWithRequiredRelease(Assignment acquireAssign, string kind) {
// acquireAssign is an assignment to this resource
acquireAssign.(Assignment).getLValue() = this.getAnAccess() and
// Should be in this class, but *any* member method will do
this.inSameClass(acquire) and
this.inSameClass(acquireAssign) and
// Check that it is an acquisition function and return the corresponding free
(
exists(Function f | f = acquire.(Assignment).getRValue().(FunctionCall).getTarget() and
(resourceManagementPair(f.getName(), releaseName) or (mallocFunction(f) and (releaseName = "free" or releaseName = "delete")))
)
or
(acquire = this.getANew() and releaseName = "delete")
)
acquireExpr(acquireAssign.getRValue(), kind)
}
private Assignment getANew() {
result.getLValue() = this.getAnAccess() and
(result.getRValue() instanceof NewExpr or result.getRValue() instanceof NewArrayExpr) and
this.inSameClass(result)
}
Expr getAReleaseExpr(string releaseName) {
exprReleases(result, this.getAnAccess(), releaseName)
Expr getAReleaseExpr(string kind) {
exprReleases(result, this.getAnAccess(), kind)
}
}

View File

@@ -68,10 +68,9 @@ class Parameter extends LocalScopeVariable, @parameter {
*/
private VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
if getFunction().isConstructedFrom(_)
then exists (Parameter prototype
| prototype = result.getVariable() and
prototype.getIndex() = getIndex() and
getFunction().isConstructedFrom(prototype.getFunction()))
then exists (Function prototypeInstantiation
| prototypeInstantiation.getParameter(getIndex()) = result.getVariable() and
getFunction().isConstructedFrom(prototypeInstantiation))
else result = getADeclarationEntry()
}

View File

@@ -1,23 +1,31 @@
import semmle.code.cpp.Type
/** Holds if `d` is a complete class named `name`. */
pragma[noinline]
private string getTopLevelClassName(@usertype c) {
isClass(c) and
usertypes(c, result, _) and
not namespacembrs(_, c) and // not in a namespace
not member(_, _, c) and // not in some structure
not class_instantiation(c, _) // not a template instantiation
}
/** Holds if `d` is a unique complete class named `name`. */
pragma[noinline]
private predicate existsCompleteWithName(string name, @usertype d) {
isClass(d) and
is_complete(d) and
usertypes(d, name, _)
name = getTopLevelClassName(d) and
strictcount(@usertype other | is_complete(other) and getTopLevelClassName(other) = name) = 1
}
/** Holds if `c` is an incomplete class named `name`. */
pragma[noinline]
private predicate existsIncompleteWithName(string name, @usertype c) {
isClass(c) and
not is_complete(c) and
usertypes(c, name, _)
name = getTopLevelClassName(c)
}
/**
* Holds if `c` is an incomplete class, and there exists a complete class `d`
* Holds if `c` is an incomplete class, and there exists a unique complete class `d`
* with the same name.
*/
private predicate hasCompleteTwin(@usertype c, @usertype d) {
@@ -30,10 +38,8 @@ private predicate hasCompleteTwin(@usertype c, @usertype d) {
import Cached
cached private module Cached {
/**
* If `c` is incomplete, and there exists a complete class with the same name,
* then the result is that complete class. Otherwise, the result is `c`. If
* multiple complete classes have the same name, this predicate may have
* multiple results.
* If `c` is incomplete, and there exists a unique complete class with the same name,
* then the result is that complete class. Otherwise, the result is `c`.
*/
cached @usertype resolveClass(@usertype c) {
hasCompleteTwin(c, result)

View File

@@ -270,7 +270,7 @@ newtype TTranslatedElement =
not ignoreExpr(initList) and
isFirstValueInitializedElementInRange(initList, elementIndex) and
elementCount =
getNextExplicitlyInitializedElementAfter(initList, elementIndex) -
getEndOfValueInitializedRange(initList, elementIndex) -
elementIndex
} or
// The initialization of a base class from within a constructor.
@@ -322,23 +322,30 @@ newtype TTranslatedElement =
/**
* Gets the index of the first explicitly initialized element in `initList`
* whose index is greater than `afterElementIndex`. If there are no remaining
* explicitly initialized elements in `initList`, the result is the total number
* of elements in the array being initialized.
* whose index is greater than `afterElementIndex`, where `afterElementIndex`
* is a first value-initialized element in a value-initialized range in
* `initList`. If there are no remaining explicitly initialized elements in
* `initList`, the result is the total number of elements in the array being
* initialized.
*/
private int getNextExplicitlyInitializedElementAfter(
private int getEndOfValueInitializedRange(ArrayAggregateLiteral initList, int afterElementIndex) {
result = getNextExplicitlyInitializedElementAfter(initList, afterElementIndex)
or
isFirstValueInitializedElementInRange(initList, afterElementIndex) and
not exists(getNextExplicitlyInitializedElementAfter(initList, afterElementIndex)) and
result = initList.getType().getUnspecifiedType().(ArrayType).getArraySize()
}
/**
* Gets the index of the first explicitly initialized element in `initList`
* whose index is greater than `afterElementIndex`, where `afterElementIndex`
* is a first value-initialized element in a value-initialized range in
* `initList`.
*/
private int getNextExplicitlyInitializedElementAfter(
ArrayAggregateLiteral initList, int afterElementIndex) {
if exists(int x |
x > afterElementIndex and
exists(initList.getElementExpr(x)))
then (
if exists(initList.getElementExpr(afterElementIndex + 1))
then result = afterElementIndex + 1
else result = getNextExplicitlyInitializedElementAfter(initList, afterElementIndex+1))
else
result = initList.getType().getUnspecifiedType().(ArrayType).getArraySize() and
// required for binding
initList.isInitialized(afterElementIndex)
isFirstValueInitializedElementInRange(initList, afterElementIndex) and
result = min(int i | exists(initList.getElementExpr(i)) and i > afterElementIndex)
}
/**

View File

@@ -6303,3 +6303,35 @@ ir.cpp:
# 958| Type = int
# 958| ValueCategory = prvalue(load)
# 959| 8: return ...
# 961| designatedInit() -> int
# 961| params:
# 961| body: { ... }
# 962| 0: declaration
# 962| 0: definition of a1
# 962| Type = int[1000]
# 962| init: initializer for a1
# 962| expr: {...}
# 962| Type = int[1000]
# 962| ValueCategory = prvalue
# 962| 0: 10002
# 962| Type = int
# 962| Value = 10002
# 962| ValueCategory = prvalue
# 962| 1: 10900
# 962| Type = int
# 962| Value = 10900
# 962| ValueCategory = prvalue
# 963| 1: return ...
# 963| 0: access to array
# 963| Type = int
# 963| ValueCategory = prvalue(load)
# 963| 0: array to pointer conversion
# 963| Type = int *
# 963| ValueCategory = prvalue
# 963| expr: a1
# 963| Type = int[1000]
# 963| ValueCategory = lvalue
# 963| 1: 900
# 963| Type = int
# 963| Value = 900
# 963| ValueCategory = prvalue

View File

@@ -3906,3 +3906,49 @@ ir.cpp:
# 950| v0_65(void) = ReturnVoid :
# 950| v0_66(void) = UnmodeledUse : mu*
# 950| v0_67(void) = ExitFunction :
# 961| designatedInit() -> int
# 961| Block 0
# 961| v0_0(void) = EnterFunction :
# 961| mu0_1(unknown) = UnmodeledDefinition :
# 962| r0_2(glval<int[1000]>) = VariableAddress[a1] :
# 962| r0_3(int) = Constant[0] :
# 962| r0_4(glval<int>) = PointerAdd : r0_2, r0_3
# 962| r0_5(unknown[8]) = Constant[0] :
# 962| mu0_6(unknown[8]) = Store : r0_4, r0_5
#-----| Goto -> Block 2
# 962| Block 1
# 962| r1_0(int) = Constant[900] :
# 962| r1_1(glval<int>) = PointerAdd : r0_2, r1_0
# 962| r1_2(int) = Constant[10900] :
# 962| mu1_3(int) = Store : r1_1, r1_2
# 962| r1_4(int) = Constant[901] :
# 962| r1_5(glval<int>) = PointerAdd : r0_2, r1_4
# 962| r1_6(unknown[396]) = Constant[0] :
# 962| mu1_7(unknown[396]) = Store : r1_5, r1_6
#-----| Goto -> Block 2
# 963| Block 2
# 963| r2_0(glval<int>) = VariableAddress[#return] :
# 963| r2_1(glval<int[1000]>) = VariableAddress[a1] :
# 963| r2_2(int *) = Convert : r2_1
# 963| r2_3(int) = Constant[900] :
# 963| r2_4(int *) = PointerAdd[4] : r2_2, r2_3
# 963| r2_5(int) = Load : r2_4, mu0_1
# 963| m2_6(int) = Store : r2_0, r2_5
# 961| r2_7(glval<int>) = VariableAddress[#return] :
# 961| v2_8(void) = ReturnValue : r2_7, m2_6
# 961| v2_9(void) = UnmodeledUse : mu*
# 961| v2_10(void) = ExitFunction :
# 962| Block 3
# 962| r3_0(int) = Constant[2] :
# 962| r3_1(glval<int>) = PointerAdd : r0_2, r3_0
# 962| r3_2(int) = Constant[10002] :
# 962| mu3_3(int) = Store : r3_1, r3_2
# 962| r3_4(int) = Constant[3] :
# 962| r3_5(glval<int>) = PointerAdd : r0_2, r3_4
# 962| r3_6(unknown[3588]) = Constant[0] :
# 962| mu3_7(unknown[3588]) = Store : r3_5, r3_6
#-----| Goto -> Block 2

View File

@@ -958,6 +958,11 @@ void OperatorNewArray(int n) {
new int[n] { 0, 1, 2 };
}
int designatedInit() {
int a1[1000] = { [2] = 10002, [900] = 10900 };
return a1[900];
}
#if 0
void OperatorDelete() {
delete static_cast<int*>(nullptr); // No destructor

View File

@@ -3885,3 +3885,49 @@ ir.cpp:
# 950| v0_65(void) = ReturnVoid :
# 950| v0_66(void) = UnmodeledUse : mu*
# 950| v0_67(void) = ExitFunction :
# 961| designatedInit() -> int
# 961| Block 0
# 961| v0_0(void) = EnterFunction :
# 961| mu0_1(unknown) = UnmodeledDefinition :
# 962| r0_2(glval<int[1000]>) = VariableAddress[a1] :
# 962| r0_3(int) = Constant[0] :
# 962| r0_4(glval<int>) = PointerAdd : r0_2, r0_3
# 962| r0_5(unknown[8]) = Constant[0] :
# 962| mu0_6(unknown[8]) = Store : r0_4, r0_5
#-----| Goto -> Block 2
# 962| Block 1
# 962| r1_0(int) = Constant[900] :
# 962| r1_1(glval<int>) = PointerAdd : r0_2, r1_0
# 962| r1_2(int) = Constant[10900] :
# 962| mu1_3(int) = Store : r1_1, r1_2
# 962| r1_4(int) = Constant[901] :
# 962| r1_5(glval<int>) = PointerAdd : r0_2, r1_4
# 962| r1_6(unknown[396]) = Constant[0] :
# 962| mu1_7(unknown[396]) = Store : r1_5, r1_6
#-----| Goto -> Block 2
# 963| Block 2
# 963| r2_0(glval<int>) = VariableAddress[#return] :
# 963| r2_1(glval<int[1000]>) = VariableAddress[a1] :
# 963| r2_2(int *) = Convert : r2_1
# 963| r2_3(int) = Constant[900] :
# 963| r2_4(int *) = PointerAdd[4] : r2_2, r2_3
# 963| r2_5(int) = Load : r2_4, mu0_1
# 963| mu2_6(int) = Store : r2_0, r2_5
# 961| r2_7(glval<int>) = VariableAddress[#return] :
# 961| v2_8(void) = ReturnValue : r2_7, mu0_1
# 961| v2_9(void) = UnmodeledUse : mu*
# 961| v2_10(void) = ExitFunction :
# 962| Block 3
# 962| r3_0(int) = Constant[2] :
# 962| r3_1(glval<int>) = PointerAdd : r0_2, r3_0
# 962| r3_2(int) = Constant[10002] :
# 962| mu3_3(int) = Store : r3_1, r3_2
# 962| r3_4(int) = Constant[3] :
# 962| r3_5(glval<int>) = PointerAdd : r0_2, r3_4
# 962| r3_6(unknown[3588]) = Constant[0] :
# 962| mu3_7(unknown[3588]) = Store : r3_5, r3_6
#-----| Goto -> Block 2

View File

@@ -92,6 +92,7 @@
| IR: VarArgs | 1 |
| IR: VirtualMemberFunction | 1 |
| IR: WhileStatements | 4 |
| IR: designatedInit | 4 |
| IR: min | 4 |
| IR: operator= | 1 |
| IR: ~Base | 1 |

View File

@@ -3906,3 +3906,49 @@ ir.cpp:
# 950| v0_65(void) = ReturnVoid :
# 950| v0_66(void) = UnmodeledUse : mu*
# 950| v0_67(void) = ExitFunction :
# 961| designatedInit() -> int
# 961| Block 0
# 961| v0_0(void) = EnterFunction :
# 961| mu0_1(unknown) = UnmodeledDefinition :
# 962| r0_2(glval<int[1000]>) = VariableAddress[a1] :
# 962| r0_3(int) = Constant[0] :
# 962| r0_4(glval<int>) = PointerAdd : r0_2, r0_3
# 962| r0_5(unknown[8]) = Constant[0] :
# 962| mu0_6(unknown[8]) = Store : r0_4, r0_5
#-----| Goto -> Block 2
# 962| Block 1
# 962| r1_0(int) = Constant[900] :
# 962| r1_1(glval<int>) = PointerAdd : r0_2, r1_0
# 962| r1_2(int) = Constant[10900] :
# 962| mu1_3(int) = Store : r1_1, r1_2
# 962| r1_4(int) = Constant[901] :
# 962| r1_5(glval<int>) = PointerAdd : r0_2, r1_4
# 962| r1_6(unknown[396]) = Constant[0] :
# 962| mu1_7(unknown[396]) = Store : r1_5, r1_6
#-----| Goto -> Block 2
# 963| Block 2
# 963| r2_0(glval<int>) = VariableAddress[#return] :
# 963| r2_1(glval<int[1000]>) = VariableAddress[a1] :
# 963| r2_2(int *) = Convert : r2_1
# 963| r2_3(int) = Constant[900] :
# 963| r2_4(int *) = PointerAdd[4] : r2_2, r2_3
# 963| r2_5(int) = Load : r2_4, mu0_1
# 963| m2_6(int) = Store : r2_0, r2_5
# 961| r2_7(glval<int>) = VariableAddress[#return] :
# 961| v2_8(void) = ReturnValue : r2_7, m2_6
# 961| v2_9(void) = UnmodeledUse : mu*
# 961| v2_10(void) = ExitFunction :
# 962| Block 3
# 962| r3_0(int) = Constant[2] :
# 962| r3_1(glval<int>) = PointerAdd : r0_2, r3_0
# 962| r3_2(int) = Constant[10002] :
# 962| mu3_3(int) = Store : r3_1, r3_2
# 962| r3_4(int) = Constant[3] :
# 962| r3_5(glval<int>) = PointerAdd : r0_2, r3_4
# 962| r3_6(unknown[3588]) = Constant[0] :
# 962| mu3_7(unknown[3588]) = Store : r3_5, r3_6
#-----| Goto -> Block 2

View File

@@ -24,3 +24,9 @@ class Damson {
int damson_x;
void foo();
};
namespace unrelated {
class AppleCompatible {
long apple_x;
};
}

View File

@@ -32,6 +32,9 @@
| b1.cpp:23:7:23:12 | Damson | 5 members | 2 locations | 1 | foo |
| b1.cpp:23:7:23:12 | Damson | 5 members | 2 locations | 2 | operator= |
| b1.cpp:23:7:23:12 | Damson | 5 members | 2 locations | 3 | operator= |
| b1.cpp:29:9:29:23 | AppleCompatible | 3 members | 1 locations | 0 | apple_x |
| b1.cpp:29:9:29:23 | AppleCompatible | 3 members | 1 locations | 1 | operator= |
| b1.cpp:29:9:29:23 | AppleCompatible | 3 members | 1 locations | 2 | operator= |
| b2.cpp:2:7:2:21 | AppleCompatible | 3 members | 2 locations | 0 | apple_x |
| b2.cpp:2:7:2:21 | AppleCompatible | 3 members | 2 locations | 1 | operator= |
| b2.cpp:2:7:2:21 | AppleCompatible | 3 members | 2 locations | 2 | operator= |

View File

@@ -10,6 +10,7 @@
| b1.cpp:11:7:11:22 | BananaCompatible | 0 | file://:0:0:0:0 | int | 1 types |
| b1.cpp:16:7:16:12 | Cherry | 0 | file://:0:0:0:0 | int | 1 types |
| b1.cpp:23:7:23:12 | Damson | 0 | file://:0:0:0:0 | int | 1 types |
| b1.cpp:29:9:29:23 | AppleCompatible | 0 | file://:0:0:0:0 | long | 1 types |
| b2.cpp:2:7:2:21 | AppleCompatible | 0 | file://:0:0:0:0 | int | 1 types |
| b2.cpp:9:7:9:22 | BananaCompatible | 0 | file://:0:0:0:0 | int | 1 types |
| b2.cpp:14:7:14:12 | Cherry | 0 | file://:0:0:0:0 | short | 1 types |

View File

@@ -1,2 +1,6 @@
| a.h:5:8:5:13 | cheese | y.cpp:4:8:4:10 | Foo | 3 |
| x.cpp:3:6:3:10 | bar_x | a.h:4:8:4:10 | Bar | 3 |
| x.cpp:19:6:19:10 | foo_x | y.cpp:4:8:4:10 | Foo | 3 |
| x.cpp:23:5:23:17 | templateField | x.cpp:6:10:6:12 | Foo | 3 |
| x.cpp:23:5:23:17 | templateField | x.cpp:12:9:12:11 | Foo | 3 |
| x.cpp:26:18:26:29 | template_foo | x.cpp:22:7:22:14 | Template<Foo *> | 0 |

View File

@@ -1,3 +1,31 @@
#include "a.h"
Bar *bar_x;
namespace unrelated {
struct Foo {
short val;
};
}
struct ContainsAnotherFoo {
class Foo {
long val;
};
};
// The type of `foo_x` should not refer to any of the above classes, none of
// which are named `Foo` in the global scope.
Foo *foo_x;
template<typename T>
class Template {
T templateField;
};
Template<Foo *> *template_foo;
// Instantiation of the template with unrelated classes named `Foo` should not
// get mixed up with the instantiation above.
template class Template<unrelated::Foo *>;
template class Template<ContainsAnotherFoo::Foo *>;

View File

@@ -0,0 +1,9 @@
#include "header.h"
struct MultipleDefsButSameHeader {
int i;
};
struct OneDefInDifferentFile {
int i;
};

View File

@@ -0,0 +1,6 @@
#include "header.h"
struct MultipleDefsButSameHeader {
char char1;
char char2;
};

View File

@@ -0,0 +1,5 @@
namespace foo {
class C;
C *x;
}

View File

@@ -0,0 +1,29 @@
namespace foo {
class C {
};
}
namespace bar {
class C {
};
}
class DefinedAndDeclared {
};
// Despite this declaration being present, the variable below is associated
// with the definition above rather than this declaration.
class DefinedAndDeclared;
DefinedAndDeclared *definedAndDeclared;
#include "header.h"
// Because there are multiple definitions of `MultipleDefsButSameHeader`, the
// type of this variable will refer to the declaration in `header.h` rather
// than any of the definitions.
MultipleDefsButSameHeader *mdbsh;
// Because there is only one definition of `OneDefInDifferentFile`, the type of
// this variable will refer to that definition.
OneDefInDifferentFile *odidf;

View File

@@ -0,0 +1,3 @@
struct MultipleDefsButSameHeader;
struct OneDefInDifferentFile;

View File

@@ -0,0 +1,4 @@
| decls.cpp:4:6:4:6 | x | decls.cpp:2:9:2:9 | C |
| defs.cpp:18:21:18:38 | definedAndDeclared | defs.cpp:11:7:11:24 | DefinedAndDeclared |
| defs.cpp:25:28:25:32 | mdbsh | header.h:1:8:1:32 | MultipleDefsButSameHeader |
| defs.cpp:29:24:29:28 | odidf | c1.cpp:7:8:7:28 | OneDefInDifferentFile |

View File

@@ -0,0 +1,5 @@
import cpp
from Variable x
where exists(x.getFile().getRelativePath())
select x, x.getType().(PointerType).getBaseType()

View File

@@ -116,32 +116,13 @@
| isfromtemplateinstantiation.cpp:134:29:134:29 | Outer<int>::operator=(const Outer<int> &) | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:134:29:134:29 | declaration of operator= | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:134:29:134:29 | declaration of operator= | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | Outer<T>::Inner<long>::operator=(Inner<long> &&) | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | Outer<T>::Inner<long>::operator=(Inner<long> &&) | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | Outer<T>::Inner<long>::operator=(const Inner<long> &) | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | Outer<T>::Inner<long>::operator=(const Inner<long> &) | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | Outer<int>::Inner<long>::operator=(Inner<long> &&) | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | Outer<int>::Inner<long>::operator=(Inner<long> &&) | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | Outer<int>::Inner<long>::operator=(const Inner<long> &) | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | Outer<int>::Inner<long>::operator=(const Inner<long> &) | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | declaration of operator= | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | declaration of operator= | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | declaration of operator= | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| isfromtemplateinstantiation.cpp:135:31:135:31 | declaration of operator= | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<U> | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:135:31:135:35 | definition of Inner<U> | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:136:7:136:7 | definition of x | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:136:7:136:7 | definition of x | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:136:7:136:7 | definition of x | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| isfromtemplateinstantiation.cpp:136:7:136:7 | x | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:136:7:136:7 | x | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:136:7:136:7 | x | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| isfromtemplateinstantiation.cpp:137:7:137:7 | definition of y | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:137:7:137:7 | definition of y | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:137:7:137:7 | definition of y | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| isfromtemplateinstantiation.cpp:137:7:137:7 | y | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:137:7:137:7 | y | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<int> |
| isfromtemplateinstantiation.cpp:137:7:137:7 | y | isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> |
| load.cpp:13:7:13:7 | basic_text_iprimitive<std_istream_mockup>::basic_text_iprimitive(basic_text_iprimitive<std_istream_mockup> &&) | load.cpp:13:7:13:27 | basic_text_iprimitive<std_istream_mockup> |
| load.cpp:13:7:13:7 | basic_text_iprimitive<std_istream_mockup>::basic_text_iprimitive(const basic_text_iprimitive<std_istream_mockup> &) | load.cpp:13:7:13:27 | basic_text_iprimitive<std_istream_mockup> |

View File

@@ -3,6 +3,7 @@ isFromUninstantiatedTemplate
| file://:0:0:0:0 | 0 | isfromtemplateinstantiation.cpp:77:26:77:45 | AnotherTemplateClass<T> |
| file://:0:0:0:0 | (int)... | isfromtemplateinstantiation.cpp:77:26:77:45 | AnotherTemplateClass<T> |
| file://:0:0:0:0 | (int)... | isfromtemplateinstantiation.cpp:77:26:77:45 | AnotherTemplateClass<T> |
| file://:0:0:0:0 | Inner<U> | file://:0:0:0:0 | Inner<U> |
| file://:0:0:0:0 | declaration of 1st parameter | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<T> |
| file://:0:0:0:0 | declaration of 1st parameter | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer<T> |
| file://:0:0:0:0 | initializer for MyClassEnumConst | isfromtemplateinstantiation.cpp:77:26:77:45 | AnotherTemplateClass<T> |
@@ -433,15 +434,15 @@ isFromUninstantiatedTemplate
| isfromtemplateinstantiation.cpp:135:31:135:31 | declaration of operator= | I | T | DeclarationEntry | |
| isfromtemplateinstantiation.cpp:135:31:135:31 | operator= | I | T | Declaration | |
| isfromtemplateinstantiation.cpp:135:31:135:31 | operator= | I | T | Declaration | |
| isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<U> | I | T | Declaration | |
| isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<U> | | T | Declaration | |
| isfromtemplateinstantiation.cpp:135:31:135:35 | Inner<long> | I | T | Declaration | |
| isfromtemplateinstantiation.cpp:136:7:136:7 | definition of x | | T | Definition | |
| isfromtemplateinstantiation.cpp:136:7:136:7 | definition of x | I | T | Definition | |
| isfromtemplateinstantiation.cpp:136:7:136:7 | definition of x | I | T | Definition | |
| isfromtemplateinstantiation.cpp:136:7:136:7 | x | I | T | Declaration | |
| isfromtemplateinstantiation.cpp:136:7:136:7 | x | | T | Declaration | |
| isfromtemplateinstantiation.cpp:136:7:136:7 | x | I | T | Declaration | |
| isfromtemplateinstantiation.cpp:137:7:137:7 | definition of y | | T | Definition | |
| isfromtemplateinstantiation.cpp:137:7:137:7 | definition of y | I | T | Definition | |
| isfromtemplateinstantiation.cpp:137:7:137:7 | definition of y | I | T | Definition | |
| isfromtemplateinstantiation.cpp:137:7:137:7 | y | I | T | Declaration | |
| isfromtemplateinstantiation.cpp:137:7:137:7 | y | | T | Declaration | |
| isfromtemplateinstantiation.cpp:137:7:137:7 | y | I | T | Declaration | |
| isfromtemplateinstantiation.cpp:144:28:144:56 | incomplete_never_instantiated<T> | | T | Declaration | |
| isfromtemplateinstantiation.cpp:146:28:146:45 | never_instantiated<T> | | T | Declaration | |

View File

@@ -0,0 +1 @@
tstWindows.c eol=crlf

View File

@@ -88,3 +88,7 @@ void use_printf(float f, double d)
// ^ there's a float -> double varargs promotion here, but it's unlikely that the author anticipates requiring a double
printf("%f", d * d); // safe
}
size_t three_chars(unsigned char a, unsigned char b, unsigned char c) {
return a * b * c; // at most 16581375
}

View File

@@ -0,0 +1,100 @@
// semmle-extractor-options: --microsoft
// winnt.h
typedef long HRESULT;
#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
#define FAILED(hr) (((HRESULT)(hr)) < 0)
typedef _Bool bool;
#define FALSE 0
// minwindef.h
typedef int BOOL;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
// winerror.h
#define S_OK ((HRESULT)0L)
#define S_FALSE ((HRESULT)1L)
#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL)
HRESULT HresultFunction()
{
return S_OK;
}
BOOL BoolFunction()
{
return FALSE;
}
bool BoolFunction2()
{
return FALSE;
}
HRESULT IncorrectHresultFunction()
{
return BoolFunction(); // BUG
}
HRESULT IncorrectHresultFunction2()
{
return BoolFunction2(); // BUG
}
void IncorrectTypeConversionTest() {
HRESULT hr = HresultFunction();
if ((BOOL)hr) // BUG
{
// ...
}
if ((bool)hr) // BUG
{
// ...
}
if (SUCCEEDED(hr)) // Correct Usage
{
// ...
}
if (SUCCEEDED(BoolFunction())) // BUG
{
// ...
}
if (SUCCEEDED(BoolFunction2())) // BUG
{
// ...
}
if (BoolFunction()) // Correct Usage
{
// ...
}
BOOL b = IncorrectHresultFunction(); // BUG
bool b2 = IncorrectHresultFunction(); // BUG
hr = E_UNEXPECTED;
if (!hr) // BUG
{
// ...
}
if (!FAILED(hr)) // Correct Usage
{
// ...
}
hr = S_FALSE;
if (hr) // BUG
{
// ...
}
if (SUCCEEDED(hr)) // Correct Usage
{
// ...
}
}

View File

@@ -0,0 +1,97 @@
// semmle-extractor-options: --microsoft
// winnt.h
typedef long HRESULT;
#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
#define FAILED(hr) (((HRESULT)(hr)) < 0)
// minwindef.h
typedef int BOOL;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
// winerror.h
#define S_OK ((HRESULT)0L)
#define S_FALSE ((HRESULT)1L)
#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL)
HRESULT HresultFunction()
{
return S_OK;
}
BOOL BoolFunction()
{
return FALSE;
}
bool BoolFunction2()
{
return FALSE;
}
HRESULT IncorrectHresultFunction()
{
return BoolFunction(); // BUG
}
HRESULT IncorrectHresultFunction2()
{
return BoolFunction2(); // BUG
}
void IncorrectTypeConversionTest() {
HRESULT hr = HresultFunction();
if ((BOOL)hr) // BUG
{
// ...
}
if ((bool)hr) // BUG
{
// ...
}
if (SUCCEEDED(hr)) // Correct Usage
{
// ...
}
if (SUCCEEDED(BoolFunction())) // BUG
{
// ...
}
if (SUCCEEDED(BoolFunction2())) // BUG
{
// ...
}
if (BoolFunction()) // Correct Usage
{
// ...
}
BOOL b = IncorrectHresultFunction(); // BUG
bool b2 = IncorrectHresultFunction(); // BUG
hr = E_UNEXPECTED;
if (!hr) // BUG
{
// ...
}
if (!FAILED(hr)) // Correct Usage
{
// ...
}
hr = S_FALSE;
if (hr) // BUG
{
// ...
}
if (SUCCEEDED(hr)) // Correct Usage
{
// ...
}
}

View File

@@ -0,0 +1,20 @@
| HResultBooleanConversion.c:42:12:42:23 | call to BoolFunction | Implicit conversion from BOOL to HRESULT |
| HResultBooleanConversion.c:47:12:47:24 | call to BoolFunction2 | Implicit conversion from bool to HRESULT |
| HResultBooleanConversion.c:53:15:53:16 | hr | Explicit conversion from HRESULT to BOOL |
| HResultBooleanConversion.c:57:15:57:16 | hr | Explicit conversion from HRESULT to bool |
| HResultBooleanConversion.c:66:9:66:33 | (...) | Explicit conversion from BOOL to HRESULT |
| HResultBooleanConversion.c:70:9:70:34 | (...) | Explicit conversion from bool to HRESULT |
| HResultBooleanConversion.c:78:14:78:37 | call to IncorrectHresultFunction | Implicit conversion from HRESULT to BOOL |
| HResultBooleanConversion.c:79:15:79:38 | call to IncorrectHresultFunction | Implicit conversion from HRESULT to bool |
| HResultBooleanConversion.c:82:10:82:11 | hr | Usage of a type HRESULT as an argument of a unary logical operation |
| HResultBooleanConversion.c:92:9:92:10 | hr | Direct usage of a type HRESULT as a conditional expression |
| HResultBooleanConversion.cpp:39:12:39:23 | call to BoolFunction | Implicit conversion from BOOL to HRESULT |
| HResultBooleanConversion.cpp:44:12:44:24 | call to BoolFunction2 | Implicit conversion from bool to HRESULT |
| HResultBooleanConversion.cpp:50:15:50:16 | hr | Explicit conversion from HRESULT to BOOL |
| HResultBooleanConversion.cpp:54:15:54:16 | hr | Explicit conversion from HRESULT to bool |
| HResultBooleanConversion.cpp:63:9:63:33 | (...) | Explicit conversion from BOOL to HRESULT |
| HResultBooleanConversion.cpp:67:9:67:34 | (...) | Explicit conversion from bool to HRESULT |
| HResultBooleanConversion.cpp:75:14:75:37 | call to IncorrectHresultFunction | Implicit conversion from HRESULT to BOOL |
| HResultBooleanConversion.cpp:76:15:76:38 | call to IncorrectHresultFunction | Implicit conversion from HRESULT to bool |
| HResultBooleanConversion.cpp:79:10:79:11 | hr | Implicit conversion from HRESULT to bool |
| HResultBooleanConversion.cpp:89:9:89:10 | hr | Implicit conversion from HRESULT to bool |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-253/HResultBooleanConversion.ql

View File

@@ -11,5 +11,9 @@
| ExternalOwners.cpp:49:3:49:20 | ... = ... | Resource a is acquired by class MyScreen but not released anywhere in this class. |
| ListDelete.cpp:21:3:21:21 | ... = ... | Resource first is acquired by class MyThingColection but not released anywhere in this class. |
| NoDestructor.cpp:23:3:23:20 | ... = ... | Resource n is acquired by class MyClass5 but not released anywhere in this class. |
| PlacementNew.cpp:36:3:36:36 | ... = ... | Resource p1 is acquired by class MyTestForPlacementNew but not released anywhere in this class. |
| SelfRegistering.cpp:25:3:25:24 | ... = ... | Resource side is acquired by class MyOwner but not released anywhere in this class. |
| Variants.cpp:23:3:23:13 | ... = ... | Resource f is acquired by class MyClass4 but not released anywhere in this class. |
| Variants.cpp:25:3:25:13 | ... = ... | Resource f is acquired by class MyClass4 but not released anywhere in this class. |
| Variants.cpp:65:3:65:17 | ... = ... | Resource a is acquired by class MyClass6 but not released anywhere in this class. |
| Variants.cpp:66:3:66:36 | ... = ... | Resource b is acquired by class MyClass6 but not released anywhere in this class. |
| Variants.cpp:67:3:67:41 | ... = ... | Resource c is acquired by class MyClass6 but not released anywhere in this class. |

View File

@@ -0,0 +1,47 @@
typedef unsigned long size_t;
namespace std
{
using ::size_t;
struct nothrow_t {};
extern const nothrow_t nothrow;
}
// nothrow new
void* operator new(std::size_t size, const std::nothrow_t&) throw();
// placement new
void* operator new (std::size_t size, void* ptr) throw();
// ---
class MyClassForPlacementNew
{
public:
MyClassForPlacementNew(int _v) : v(_v) {}
~MyClassForPlacementNew() {}
private:
int v;
};
class MyTestForPlacementNew
{
public:
MyTestForPlacementNew()
{
void *buffer_ptr = buffer;
p1 = new MyClassForPlacementNew(1); // BAD: not released
p2 = new (std::nothrow) MyClassForPlacementNew(2); // BAD: not released [NOT DETECTED]
p3 = new (buffer_ptr) MyClassForPlacementNew(3); // GOOD: placement new, not an allocation
}
~MyTestForPlacementNew()
{
}
MyClassForPlacementNew *p1, *p2, *p3;
char buffer[sizeof(MyClassForPlacementNew)];
};

View File

@@ -2,6 +2,8 @@
// library
typedef unsigned int size_t;
void *malloc(size_t size);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
void free(void* ptr);
int *ID(int *x)
@@ -34,3 +36,40 @@ public:
int *a, *b, *c, *d, *e, *f, *g;
};
class MyClass5
{
public:
MyClass5()
{
a = new int[10]; // GOOD
b = (int *)calloc(10, sizeof(int)); // GOOD
c = (int *)realloc(0, 10 * sizeof(int)); // GOOD
}
~MyClass5()
{
delete [] a;
free(b);
free(c);
}
int *a, *b, *c;
};
class MyClass6
{
public:
MyClass6()
{
a = new int[10]; // BAD
b = (int *)calloc(10, sizeof(int)); // BAD
c = (int *)realloc(0, 10 * sizeof(int)); // BAD
}
~MyClass6()
{
}
int *a, *b, *c;
};

View File

@@ -3,7 +3,7 @@
* @description If a synchronized method is overridden in a subclass, and the overriding method is
* not synchronized, the thread-safety of the subclass may be broken.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @precision very-high
* @id java/non-sync-override
* @tags reliability

View File

@@ -3,7 +3,7 @@
* @description A resource that is opened for reading but not closed may cause a resource
* leak.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @precision high
* @id java/input-resource-leak
* @tags efficiency

View File

@@ -2,7 +2,7 @@
* @name Potential database resource leak
* @description A database resource that is opened but not closed may cause a resource leak.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @precision high
* @id java/database-resource-leak
* @tags correctness

View File

@@ -3,7 +3,7 @@
* @description A resource that is opened for writing but not closed may cause a resource
* leak.
* @kind problem
* @problem.severity error
* @problem.severity warning
* @precision high
* @id java/output-resource-leak
* @tags efficiency

View File

@@ -0,0 +1 @@
TestWindows.java eol=crlf

View File

@@ -0,0 +1 @@
TestWindows.java eol=crlf

View File

@@ -38,12 +38,15 @@ predicate hasCookieMiddleware(Express::RouteHandlerExpr expr, Express::RouteHand
* // protected from CSRF
* })
* ```
*
* Currently the predicate only detects `csurf`-based protectors.
*/
DataFlow::CallNode csrfMiddlewareCreation() {
exists (DataFlow::ModuleImportNode mod | result = mod.getACall() |
mod.getPath() = "csurf"
exists (DataFlow::SourceNode callee | result = callee.getACall() |
callee = DataFlow::moduleImport("csurf")
or
callee = DataFlow::moduleImport("lusca") and
exists(result.getOptionArgument(0, "csrf"))
or
callee = DataFlow::moduleMember("lusca", "csrf")
)
}

View File

@@ -785,7 +785,8 @@ module Express {
override MethodCallExpr astNode;
ResponseSendFileAsFileSystemAccess() {
asExpr().(MethodCallExpr).calls(any(ResponseExpr res), "sendFile")
exists (string name | name = "sendFile" or name = "sendfile" |
asExpr().(MethodCallExpr).calls(any(ResponseExpr res), name))
}
override DataFlow::Node getAPathArgument() {

View File

@@ -25,4 +25,5 @@
| tainted-array-steps.js:15:29:15:43 | parts.join('/') | This path depends on $@. | tainted-array-steps.js:9:24:9:30 | req.url | a user-provided value |
| tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value |
| tainted-sendFile.js:7:16:7:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:7:16:7:33 | req.param("gimme") | a user-provided value |
| tainted-sendFile.js:9:16:9:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:9:16:9:33 | req.param("gimme") | a user-provided value |
| views.js:1:43:1:55 | req.params[0] | This path depends on $@. | views.js:1:43:1:55 | req.params[0] | a user-provided value |

View File

@@ -5,4 +5,6 @@ var app = express();
app.get('/some/path', function(req, res) {
// BAD: sending a file based on un-sanitized query parameters
res.sendFile(req.param("gimme"));
// BAD: same as above
res.sendfile(req.param("gimme"));
});

View File

@@ -1,3 +1,5 @@
| MissingCsrfMiddlewareBad.js:7:9:7:22 | cookieParser() | This cookie middleware is serving a request handler $@ without CSRF protection. | MissingCsrfMiddlewareBad.js:10:26:11:1 | functio ... es) {\\n} | here |
| csurf_api_example.js:39:37:39:50 | cookieParser() | This cookie middleware is serving a request handler $@ without CSRF protection. | csurf_api_example.js:39:53:41:3 | functio ... e')\\n } | here |
| csurf_example.js:18:9:18:22 | cookieParser() | This cookie middleware is serving a request handler $@ without CSRF protection. | csurf_example.js:29:40:31:1 | functio ... sed')\\n} | here |
| lusca_example.js:9:9:9:22 | cookieParser() | This cookie middleware is serving a request handler $@ without CSRF protection. | lusca_example.js:23:42:25:1 | functio ... sed')\\n} | here |
| lusca_example.js:9:9:9:22 | cookieParser() | This cookie middleware is serving a request handler $@ without CSRF protection. | lusca_example.js:27:40:29:1 | functio ... sed')\\n} | here |

View File

@@ -0,0 +1,29 @@
var express = require('express')
var cookieParser = require('cookie-parser')
var bodyParser = require('body-parser')
var parseForm = bodyParser.urlencoded({ extended: false })
var lusca = require('lusca');
var app = express()
app.use(cookieParser())
app.post('/process', parseForm, lusca.csrf(), function (req, res) { // OK
res.send('data is being processed')
})
app.post('/process', parseForm, lusca({csrf:true}), function (req, res) { // OK
res.send('data is being processed')
})
app.post('/process', parseForm, lusca({csrf:{}}), function (req, res) { // OK
res.send('data is being processed')
})
app.post('/process', parseForm, lusca(), function (req, res) { // NOT OK - missing csrf option
res.send('data is being processed')
})
app.post('/process_unsafe', parseForm, function (req, res) { // NOT OK
res.send('data is being processed')
})