Skip to content

Commit e20ae48

Browse files
committed
Merge branch 'main' into models3b
2 parents 68a37f9 + 14a362d commit e20ae48

File tree

134 files changed

+5661
-1107
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

134 files changed

+5661
-1107
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* Added a `isFinalValueOfParameter` predicate to DataFlow::Node which holds when a dataflow node represents the final value of an output parameter of a function.

cpp/ql/lib/ext/pthread.model.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/cpp-all
4+
extensible: summaryModel
5+
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
6+
- ["", "", False, "pthread_create", "", "", "Argument[@3]", "Argument[2].Parameter[@0]", "value", "manual"]

cpp/ql/lib/ext/std.thread.model.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/cpp-all
4+
extensible: summaryModel
5+
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
6+
- ["std", "thread", True, "thread", "", "", "Argument[*@1]", "Argument[0].Parameter[@0]", "value", "manual"]
7+
- ["std", "thread", True, "thread", "", "", "Argument[*@2]", "Argument[0].Parameter[@1]", "value", "manual"]
8+
- ["std", "thread", True, "thread", "", "", "Argument[*@3]", "Argument[0].Parameter[@2]", "value", "manual"]
9+
- ["std", "thread", True, "thread", "", "", "Argument[*@4]", "Argument[0].Parameter[@3]", "value", "manual"]
10+
- ["std", "thread", True, "thread", "", "", "Argument[*@5]", "Argument[0].Parameter[@4]", "value", "manual"]
11+

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,16 +1382,89 @@ predicate neverSkipInPathGraph(Node n) {
13821382
exists(n.asIndirectDefinition())
13831383
}
13841384

1385-
class LambdaCallKind = Unit;
1385+
private newtype TLambdaCallKind =
1386+
TFunctionPointer() or
1387+
TFunctor()
1388+
1389+
class LambdaCallKind extends TLambdaCallKind {
1390+
predicate isFunctionPointer() { this = TFunctionPointer() }
1391+
1392+
predicate isFunctor() { this = TFunctor() }
1393+
1394+
string toString() {
1395+
this.isFunctionPointer() and
1396+
result = "Function pointer kind"
1397+
or
1398+
this.isFunctor() and
1399+
result = "Functor kind"
1400+
}
1401+
}
1402+
1403+
private class ConstructorCallInstruction extends CallInstruction {
1404+
Cpp::Class constructedType;
1405+
1406+
ConstructorCallInstruction() {
1407+
this.getStaticCallTarget().(Cpp::Constructor).getDeclaringType() = constructedType
1408+
}
1409+
1410+
Cpp::Class getConstructedType() { result = constructedType }
1411+
}
1412+
1413+
private class OperatorCall extends Cpp::MemberFunction {
1414+
OperatorCall() { this.hasName("operator()") }
1415+
}
1416+
1417+
private predicate isFunctorCreationWithoutConstructor(Node creation, OperatorCall operator) {
1418+
exists(UninitializedInstruction init, Instruction dest |
1419+
// A construction of an object with no constructor. In this case we use
1420+
// the `UninitializedInstruction` as the creation node.
1421+
init = creation.asInstruction() and
1422+
dest = init.getDestinationAddress() and
1423+
not any(ConstructorCallInstruction constructorCall).getThisArgument() = dest and
1424+
operator.getDeclaringType() = init.getResultType()
1425+
)
1426+
or
1427+
// Workaround for an extractor bug. In this snippet:
1428+
// ```
1429+
// struct S { };
1430+
// void f(S);
1431+
// f(S());
1432+
// ```
1433+
// The expression `S()` is represented as a 0 literal in the database.
1434+
exists(ConstantValueInstruction constant |
1435+
constant.getValue() = "0" and
1436+
creation.asInstruction() = constant and
1437+
constant.getResultType() = operator.getDeclaringType()
1438+
)
1439+
}
1440+
1441+
private predicate isFunctorCreationWithConstructor(Node creation, OperatorCall operator) {
1442+
exists(DataFlowCall constructorCall, IndirectionPosition pos |
1443+
// A construction of an object with a constructor. In this case we use
1444+
// the post-update node of the qualifier
1445+
pos.getArgumentIndex() = -1 and
1446+
isArgumentNode(creation.(PostUpdateNode).getPreUpdateNode(), constructorCall, pos) and
1447+
operator.getDeclaringType() =
1448+
constructorCall.asCallInstruction().(ConstructorCallInstruction).getConstructedType()
1449+
)
1450+
}
13861451

13871452
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
13881453
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
1389-
creation.asInstruction().(FunctionAddressInstruction).getFunctionSymbol() = c.asSourceCallable() and
1390-
exists(kind)
1454+
kind.isFunctionPointer() and
1455+
creation.asInstruction().(FunctionAddressInstruction).getFunctionSymbol() = c.asSourceCallable()
1456+
or
1457+
kind.isFunctor() and
1458+
exists(OperatorCall operator | operator = c.asSourceCallable() |
1459+
isFunctorCreationWithoutConstructor(creation, operator)
1460+
or
1461+
isFunctorCreationWithConstructor(creation, operator)
1462+
)
13911463
}
13921464

13931465
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
13941466
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
1467+
kind.isFunctionPointer() and
13951468
(
13961469
call.(SummaryCall).getReceiver() = receiver.(FlowSummaryNode).getSummaryNode()
13971470
or
@@ -1400,8 +1473,15 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
14001473
// has a result for `getStaticCallTarget`.
14011474
not exists(call.getStaticCallTarget()) and
14021475
call.asCallInstruction().getCallTargetOperand() = receiver.asOperand()
1403-
) and
1404-
exists(kind)
1476+
)
1477+
or
1478+
kind.isFunctor() and
1479+
(
1480+
call.(SummaryCall).getReceiver() = receiver.(FlowSummaryNode).getSummaryNode()
1481+
or
1482+
not exists(call.getStaticCallTarget()) and
1483+
call.asCallInstruction().getThisArgumentOperand() = receiver.asOperand()
1484+
)
14051485
}
14061486

14071487
/** Extra data-flow steps needed for lambda flow analysis. */

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,23 @@ class Node extends TIRDataFlowNode {
488488
result = this.(IndirectParameterNode).getParameter()
489489
}
490490

491+
/**
492+
* Holds if this node represents the `indirectionIndex`'th indirection of
493+
* the value of an output parameter `p` just before reaching the end of a function.
494+
*/
495+
predicate isFinalValueOfParameter(Parameter p, int indirectionIndex) {
496+
exists(FinalParameterNode n | n = this |
497+
p = n.getParameter() and
498+
indirectionIndex = n.getIndirectionIndex()
499+
)
500+
}
501+
502+
/**
503+
* Holds if this node represents the value of an output parameter `p`
504+
* just before reaching the end of a function.
505+
*/
506+
predicate isFinalValueOfParameter(Parameter p) { this.isFinalValueOfParameter(p, _) }
507+
491508
/**
492509
* Gets the variable corresponding to this node, if any. This can be used for
493510
* modeling flow in and out of global variables.
@@ -1225,7 +1242,7 @@ import RawIndirectNodes
12251242
/**
12261243
* INTERNAL: do not use.
12271244
*
1228-
* A node representing the value of an update parameter
1245+
* A node representing the value of an output parameter
12291246
* just before reaching the end of a function.
12301247
*/
12311248
class FinalParameterNode extends Node, TFinalParameterNode {

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,20 @@ class UninitializedInstruction extends VariableInstruction {
725725
* Gets the variable that is uninitialized.
726726
*/
727727
final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() }
728+
729+
/**
730+
* Gets the operand that provides the address of the location to which the
731+
* uninitialized value will be stored.
732+
*/
733+
final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() }
734+
735+
/**
736+
* Gets the instruction whose result provides the address of the location to
737+
* which the value will be stored, if an exact definition is available.
738+
*/
739+
final Instruction getDestinationAddress() {
740+
result = this.getDestinationAddressOperand().getDef()
741+
}
728742
}
729743

730744
/**

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,20 @@ class UninitializedInstruction extends VariableInstruction {
725725
* Gets the variable that is uninitialized.
726726
*/
727727
final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() }
728+
729+
/**
730+
* Gets the operand that provides the address of the location to which the
731+
* uninitialized value will be stored.
732+
*/
733+
final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() }
734+
735+
/**
736+
* Gets the instruction whose result provides the address of the location to
737+
* which the value will be stored, if an exact definition is available.
738+
*/
739+
final Instruction getDestinationAddress() {
740+
result = this.getDestinationAddressOperand().getDef()
741+
}
728742
}
729743

730744
/**

cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,20 @@ class UninitializedInstruction extends VariableInstruction {
725725
* Gets the variable that is uninitialized.
726726
*/
727727
final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() }
728+
729+
/**
730+
* Gets the operand that provides the address of the location to which the
731+
* uninitialized value will be stored.
732+
*/
733+
final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() }
734+
735+
/**
736+
* Gets the instruction whose result provides the address of the location to
737+
* which the value will be stored, if an exact definition is available.
738+
*/
739+
final Instruction getDestinationAddress() {
740+
result = this.getDestinationAddressOperand().getDef()
741+
}
728742
}
729743

730744
/**

cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import cpp
1616
import semmle.code.cpp.controlflow.Guards
17+
import semmle.code.cpp.ir.IR
1718

1819
class WideCharPointerType extends PointerType {
1920
WideCharPointerType() { this.getBaseType() instanceof WideCharType }
@@ -108,7 +109,9 @@ where
108109
// Avoid cases where the cast is guarded by a check to determine if
109110
// unicode encoding is enabled in such a way to disallow the dangerous cast
110111
// at runtime.
111-
not isLikelyDynamicallyChecked(e1)
112+
not isLikelyDynamicallyChecked(e1) and
113+
// Avoid cases in unreachable blocks.
114+
any(EnterFunctionInstruction e).getASuccessor+().getAst() = e1
112115
select e1,
113116
"Conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
114117
". Use of invalid string can lead to undefined behavior."
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added flow models for `pthread_create` and `std::thread`.

0 commit comments

Comments
 (0)