Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions cpp/ql/src/semmle/code/cpp/Parameter.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand Down
26 changes: 16 additions & 10 deletions cpp/ql/src/semmle/code/cpp/internal/ResolveClass.qll
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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(
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)
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) {
isFirstValueInitializedElementInRange(initList, afterElementIndex) and
result = min(int i | exists(initList.getElementExpr(i)) and i > afterElementIndex)
}

/**
Expand Down
32 changes: 32 additions & 0 deletions cpp/ql/test/library-tests/ir/ir/PrintAST.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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
46 changes: 46 additions & 0 deletions cpp/ql/test/library-tests/ir/ir/aliased_ssa_ir.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 5 additions & 0 deletions cpp/ql/test/library-tests/ir/ir/ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 46 additions & 0 deletions cpp/ql/test/library-tests/ir/ir/raw_ir.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions cpp/ql/test/library-tests/ir/ir/ssa_block_count.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
46 changes: 46 additions & 0 deletions cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ir.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions cpp/ql/test/library-tests/structs/compatible_cpp/b1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ class Damson {
int damson_x;
void foo();
};

namespace unrelated {
class AppleCompatible {
long apple_x;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -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= |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
Original file line number Diff line number Diff line change
@@ -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 |
28 changes: 28 additions & 0 deletions cpp/ql/test/library-tests/structs/incomplete_definition/x.cpp
Original file line number Diff line number Diff line change
@@ -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 *>;
Loading