diff --git a/MODULE.bazel b/MODULE.bazel
index 474e6df0aba..3b2532b08af 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -230,6 +230,7 @@ use_repo(
"kotlin-compiler-2.1.0-Beta1",
"kotlin-compiler-2.1.20-Beta1",
"kotlin-compiler-2.2.0-Beta1",
+ "kotlin-compiler-2.2.20-Beta2",
"kotlin-compiler-embeddable-1.6.0",
"kotlin-compiler-embeddable-1.6.20",
"kotlin-compiler-embeddable-1.7.0",
@@ -242,6 +243,7 @@ use_repo(
"kotlin-compiler-embeddable-2.1.0-Beta1",
"kotlin-compiler-embeddable-2.1.20-Beta1",
"kotlin-compiler-embeddable-2.2.0-Beta1",
+ "kotlin-compiler-embeddable-2.2.20-Beta2",
"kotlin-stdlib-1.6.0",
"kotlin-stdlib-1.6.20",
"kotlin-stdlib-1.7.0",
@@ -254,6 +256,7 @@ use_repo(
"kotlin-stdlib-2.1.0-Beta1",
"kotlin-stdlib-2.1.20-Beta1",
"kotlin-stdlib-2.2.0-Beta1",
+ "kotlin-stdlib-2.2.20-Beta2",
)
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
diff --git a/actions/ql/lib/CHANGELOG.md b/actions/ql/lib/CHANGELOG.md
index 241e94c0065..dffad0539b0 100644
--- a/actions/ql/lib/CHANGELOG.md
+++ b/actions/ql/lib/CHANGELOG.md
@@ -1,7 +1,13 @@
-## 0.4.13
+## 0.4.14
No user-facing changes.
+## 0.4.13
+
+### Bug Fixes
+
+* The `actions/artifact-poisoning/critical` and `actions/artifact-poisoning/medium` queries now exclude artifacts downloaded to `$[{ runner.temp }}` in addition to `/tmp`.
+
## 0.4.12
### Minor Analysis Improvements
diff --git a/actions/ql/lib/change-notes/2025-07-11-artifact-poisoning.md b/actions/ql/lib/change-notes/2025-07-11-artifact-poisoning.md
deleted file mode 100644
index 893a695a22c..00000000000
--- a/actions/ql/lib/change-notes/2025-07-11-artifact-poisoning.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* The `actions/artifact-poisoning/critical` and `actions/artifact-poisoning/medium` queries now exclude artifacts downloaded to `$[{ runner.temp }}` in addition to `/tmp`.
diff --git a/actions/ql/lib/change-notes/released/0.4.13.md b/actions/ql/lib/change-notes/released/0.4.13.md
index b061eef7d3b..1c7fa59a356 100644
--- a/actions/ql/lib/change-notes/released/0.4.13.md
+++ b/actions/ql/lib/change-notes/released/0.4.13.md
@@ -1,3 +1,5 @@
## 0.4.13
-No user-facing changes.
+### Bug Fixes
+
+* The `actions/artifact-poisoning/critical` and `actions/artifact-poisoning/medium` queries now exclude artifacts downloaded to `$[{ runner.temp }}` in addition to `/tmp`.
diff --git a/csharp/ql/lib/change-notes/released/5.1.10.md b/actions/ql/lib/change-notes/released/0.4.14.md
similarity index 71%
rename from csharp/ql/lib/change-notes/released/5.1.10.md
rename to actions/ql/lib/change-notes/released/0.4.14.md
index f22ccf3e6e9..09e58196373 100644
--- a/csharp/ql/lib/change-notes/released/5.1.10.md
+++ b/actions/ql/lib/change-notes/released/0.4.14.md
@@ -1,3 +1,3 @@
-## 5.1.10
+## 0.4.14
No user-facing changes.
diff --git a/actions/ql/lib/codeql-pack.release.yml b/actions/ql/lib/codeql-pack.release.yml
index 88ad5ab8f22..3841668fe04 100644
--- a/actions/ql/lib/codeql-pack.release.yml
+++ b/actions/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.4.13
+lastReleaseVersion: 0.4.14
diff --git a/actions/ql/lib/qlpack.yml b/actions/ql/lib/qlpack.yml
index 81cda8662de..dd2723b0315 100644
--- a/actions/ql/lib/qlpack.yml
+++ b/actions/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/actions-all
-version: 0.4.14-dev
+version: 0.4.15-dev
library: true
warnOnImplicitThis: true
dependencies:
diff --git a/actions/ql/src/CHANGELOG.md b/actions/ql/src/CHANGELOG.md
index d0db2aff304..09fb20778fc 100644
--- a/actions/ql/src/CHANGELOG.md
+++ b/actions/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.6.6
+
+No user-facing changes.
+
## 0.6.5
No user-facing changes.
diff --git a/java/ql/lib/change-notes/released/7.3.3.md b/actions/ql/src/change-notes/released/0.6.6.md
similarity index 73%
rename from java/ql/lib/change-notes/released/7.3.3.md
rename to actions/ql/src/change-notes/released/0.6.6.md
index 3546e57ff57..ab10d897be1 100644
--- a/java/ql/lib/change-notes/released/7.3.3.md
+++ b/actions/ql/src/change-notes/released/0.6.6.md
@@ -1,3 +1,3 @@
-## 7.3.3
+## 0.6.6
No user-facing changes.
diff --git a/actions/ql/src/codeql-pack.release.yml b/actions/ql/src/codeql-pack.release.yml
index 86780fb6148..f4cae0a77ad 100644
--- a/actions/ql/src/codeql-pack.release.yml
+++ b/actions/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.6.5
+lastReleaseVersion: 0.6.6
diff --git a/actions/ql/src/qlpack.yml b/actions/ql/src/qlpack.yml
index f422500da37..911d1e19168 100644
--- a/actions/ql/src/qlpack.yml
+++ b/actions/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/actions-queries
-version: 0.6.6-dev
+version: 0.6.7-dev
library: false
warnOnImplicitThis: true
groups: [actions, queries]
diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md
index 6b056a683e4..def048bdd3c 100644
--- a/cpp/ql/lib/CHANGELOG.md
+++ b/cpp/ql/lib/CHANGELOG.md
@@ -1,11 +1,26 @@
+## 5.4.0
+
+### New Features
+
+* Exposed various SSA-related classes (`Definition`, `PhiNode`, `ExplicitDefinition`, `DirectExplicitDefinition`, and `IndirectExplicitDefinition`) which were previously only usable inside the internal dataflow directory.
+
+### Minor Analysis Improvements
+
+* The `cpp/overrun-write` query now recognizes more bound checks and thus produces fewer false positives.
+
## 5.3.0
### Deprecated APIs
* The `UnknownDefaultLocation`, `UnknownExprLocation`, and `UnknownStmtLocation` classes have been deprecated. Use `UnknownLocation` instead.
+### New Features
+
+* Added a `isFinalValueOfParameter` predicate to `DataFlow::Node` which holds when a dataflow node represents the final value of an output parameter of a function.
+
### Minor Analysis Improvements
+* The `FunctionWithWrappers` library (`semmle.code.cpp.security.FunctionWithWrappers`) no longer considers calls through function pointers as wrapper functions.
* The analysis of C/C++ code targeting 64-bit Arm platforms has been improved. This includes support for the Arm-specific builtin functions, support for the `arm_neon.h` header and Neon vector types, and support for the `fp8` scalar type. The `arm_sve.h` header and scalable vectors are only partially supported at this point.
* Added support for `__fp16 _Complex` and `__bf16 _Complex` types
* Added `sql-injection` sink models for the Oracle Call Interface (OCI) database library functions `OCIStmtPrepare` and `OCIStmtPrepare2`.
diff --git a/cpp/ql/lib/change-notes/2025-07-10-final.md b/cpp/ql/lib/change-notes/2025-07-10-final.md
deleted file mode 100644
index 8e6b3dba266..00000000000
--- a/cpp/ql/lib/change-notes/2025-07-10-final.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: feature
----
-* Added a `isFinalValueOfParameter` predicate to DataFlow::Node which holds when a dataflow node represents the final value of an output parameter of a function.
diff --git a/cpp/ql/lib/change-notes/2025-07-16-FunctionWithWrappers.md b/cpp/ql/lib/change-notes/2025-07-16-FunctionWithWrappers.md
deleted file mode 100644
index 80b70a8c80f..00000000000
--- a/cpp/ql/lib/change-notes/2025-07-16-FunctionWithWrappers.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* The `FunctionWithWrappers` library (`semmle.code.cpp.security.FunctionWithWrappers`) no longer considers calls through function pointers as wrapper functions.
\ No newline at end of file
diff --git a/cpp/ql/lib/change-notes/2025-08-02-gvn.md b/cpp/ql/lib/change-notes/2025-08-02-gvn.md
new file mode 100644
index 00000000000..70c9f7dbb15
--- /dev/null
+++ b/cpp/ql/lib/change-notes/2025-08-02-gvn.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering` and `semmle.code.cpp.ir.ValueNumbering`) has been improved so more expressions are assigned the same value number.
\ No newline at end of file
diff --git a/cpp/ql/lib/change-notes/2025-08-11-global-variable-flow.md b/cpp/ql/lib/change-notes/2025-08-11-global-variable-flow.md
new file mode 100644
index 00000000000..c140570df31
--- /dev/null
+++ b/cpp/ql/lib/change-notes/2025-08-11-global-variable-flow.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Improved dataflow through global variables in the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`). Queries based on these libraries will produce more results on codebases with many global variables.
\ No newline at end of file
diff --git a/cpp/ql/lib/change-notes/released/5.3.0.md b/cpp/ql/lib/change-notes/released/5.3.0.md
index 439486f3fca..a7ea151fcf3 100644
--- a/cpp/ql/lib/change-notes/released/5.3.0.md
+++ b/cpp/ql/lib/change-notes/released/5.3.0.md
@@ -4,8 +4,13 @@
* The `UnknownDefaultLocation`, `UnknownExprLocation`, and `UnknownStmtLocation` classes have been deprecated. Use `UnknownLocation` instead.
+### New Features
+
+* Added a `isFinalValueOfParameter` predicate to `DataFlow::Node` which holds when a dataflow node represents the final value of an output parameter of a function.
+
### Minor Analysis Improvements
+* The `FunctionWithWrappers` library (`semmle.code.cpp.security.FunctionWithWrappers`) no longer considers calls through function pointers as wrapper functions.
* The analysis of C/C++ code targeting 64-bit Arm platforms has been improved. This includes support for the Arm-specific builtin functions, support for the `arm_neon.h` header and Neon vector types, and support for the `fp8` scalar type. The `arm_sve.h` header and scalable vectors are only partially supported at this point.
* Added support for `__fp16 _Complex` and `__bf16 _Complex` types
* Added `sql-injection` sink models for the Oracle Call Interface (OCI) database library functions `OCIStmtPrepare` and `OCIStmtPrepare2`.
diff --git a/cpp/ql/lib/change-notes/released/5.4.0.md b/cpp/ql/lib/change-notes/released/5.4.0.md
new file mode 100644
index 00000000000..8c8cea5440c
--- /dev/null
+++ b/cpp/ql/lib/change-notes/released/5.4.0.md
@@ -0,0 +1,9 @@
+## 5.4.0
+
+### New Features
+
+* Exposed various SSA-related classes (`Definition`, `PhiNode`, `ExplicitDefinition`, `DirectExplicitDefinition`, and `IndirectExplicitDefinition`) which were previously only usable inside the internal dataflow directory.
+
+### Minor Analysis Improvements
+
+* The `cpp/overrun-write` query now recognizes more bound checks and thus produces fewer false positives.
diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml
index b0a1c83e5bc..afb2156eaa2 100644
--- a/cpp/ql/lib/codeql-pack.release.yml
+++ b/cpp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 5.3.0
+lastReleaseVersion: 5.4.0
diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml
index 9df7c16850f..ccebfc9f340 100644
--- a/cpp/ql/lib/ext/Windows.model.yml
+++ b/cpp/ql/lib/ext/Windows.model.yml
@@ -36,4 +36,14 @@ extensions:
# processthreadsapi.h
- ["", "", False, "CreateThread", "", "", "Argument[@3]", "Argument[2].Parameter[@0]", "value", "manual"]
- ["", "", False, "CreateRemoteThread", "", "", "Argument[@4]", "Argument[3].Parameter[@0]", "value", "manual"]
- - ["", "", False, "CreateRemoteThreadEx", "", "", "Argument[@4]", "Argument[3].Parameter[@0]", "value", "manual"]
\ No newline at end of file
+ - ["", "", False, "CreateRemoteThreadEx", "", "", "Argument[@4]", "Argument[3].Parameter[@0]", "value", "manual"]
+ # wdm.h
+ - ["", "", False, "RtlCopyVolatileMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
+ - ["", "", False, "RtlCopyDeviceMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
+ - ["", "", False, "RtlCopyMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
+ - ["", "", False, "RtlCopyMemoryNonTemporal", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
+ - ["", "", False, "RtlCopyUnicodeString", "", "", "Argument[*1].Field[*Buffer]", "Argument[*0].Field[*Buffer]", "value", "manual"]
+ - ["", "", False, "RtlMoveMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
+ - ["", "", False, "RtlMoveVolatileMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
+ # winternl.h
+ - ["", "", False, "RtlInitUnicodeString", "", "", "Argument[*1]", "Argument[*0].Field[*Buffer]", "value", "manual"]
\ No newline at end of file
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index c34c35f239a..7c1fb8aad1c 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 5.3.1-dev
+version: 5.4.1-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll b/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll
index 565c15d0d5c..675090ad958 100644
--- a/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll
+++ b/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll
@@ -57,6 +57,18 @@ private Class getRootType(FieldAccess fa) {
)
}
+/**
+ * Gets the size of `v`. This predicate does not have a result when the
+ * unspecified type of `v` is a `ReferenceType`.
+ */
+private int getVariableSize(Variable v) {
+ exists(Type t |
+ t = v.getUnspecifiedType() and
+ not t instanceof ReferenceType and
+ result = t.getSize()
+ )
+}
+
/**
* Gets the size of the buffer access at `va`.
*/
@@ -64,12 +76,8 @@ private int getSize(VariableAccess va) {
exists(Variable v | va.getTarget() = v |
// If `v` is not a field then the size of the buffer is just
// the size of the type of `v`.
- exists(Type t |
- t = v.getUnspecifiedType() and
- not v instanceof Field and
- not t instanceof ReferenceType and
- result = t.getSize()
- )
+ not v instanceof Field and
+ result = getVariableSize(v)
or
exists(Class c, int trueSize |
// Otherwise, we find the "outermost" object and compute the size
@@ -92,7 +100,7 @@ private int getSize(VariableAccess va) {
// buffer is `12 - 4 = 8`.
c = getRootType(va) and
// we calculate the size based on the last field, to avoid including any padding after it
- trueSize = max(Field f | | f.getOffsetInClass(c) + f.getUnspecifiedType().getSize()) and
+ trueSize = max(Field f | | f.getOffsetInClass(c) + getVariableSize(f)) and
result = trueSize - v.(Field).getOffsetInClass(c)
)
)
diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll
index 1e0b39be1ac..9c6069d4a0c 100644
--- a/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll
+++ b/cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll
@@ -15,6 +15,13 @@ class StandardSsa extends SsaHelper {
}
/**
+ * NOTE: If possible, prefer the SSA classes exposed by the new dataflow
+ * library:
+ * ```
+ * import semmle.code.cpp.dataflow.new.DataFlow
+ * // use `DataFlow::Ssa::Definition`
+ * ```
+ *
* A definition of one or more SSA variables, including phi node definitions.
* An _SSA variable_, as defined in the literature, is effectively the pair of
* an `SsaDefinition d` and a `StackVariable v`, written `(d, v)` in this
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll
index 1a4c777af35..b5e899bf0aa 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll
@@ -1,6 +1,5 @@
private import cpp
private import semmle.code.cpp.ir.IR
-private import semmle.code.cpp.ir.dataflow.DataFlow
private import DataFlowPrivate
private import DataFlowUtil
private import DataFlowImplCommon as DataFlowImplCommon
@@ -60,7 +59,7 @@ private module VirtualDispatch {
* `resolve` predicate to stitch that information together and resolve the
* call.
*/
- abstract DataFlow::Node getDispatchValue();
+ abstract Node getDispatchValue();
/** Gets a candidate target for this call. */
abstract Function resolve();
@@ -72,17 +71,13 @@ private module VirtualDispatch {
* parameter is true when the search is allowed to continue backwards into
* a parameter; non-recursive callers should pass `_` for `allowFromArg`.
*/
- predicate flowsFrom(DataFlow::Node src, boolean allowFromArg) {
+ predicate flowsFrom(Node src, boolean allowFromArg) {
src = this.getDispatchValue() and allowFromArg = true
or
- exists(DataFlow::Node other, boolean allowOtherFromArg |
- this.flowsFrom(other, allowOtherFromArg)
- |
+ exists(Node other, boolean allowOtherFromArg | this.flowsFrom(other, allowOtherFromArg) |
// Call argument
exists(DataFlowCall call, Position i |
- other
- .(DataFlow::ParameterNode)
- .isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and
+ other.(ParameterNode).isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and
src.(ArgumentNode).argumentOf(call, pragma[only_bind_into](pragma[only_bind_out](i)))
) and
allowOtherFromArg = true and
@@ -96,7 +91,7 @@ private module VirtualDispatch {
allowFromArg = false
or
// Local flow
- DataFlow::localFlowStep(src, other) and
+ localFlowStep(src, other) and
allowFromArg = allowOtherFromArg
or
// Flow from global variable to load.
@@ -159,11 +154,11 @@ private module VirtualDispatch {
private class DataSensitiveExprCall extends DataSensitiveCall {
DataSensitiveExprCall() { not exists(this.getStaticCallTarget()) }
- override DataFlow::Node getDispatchValue() { result.asOperand() = this.getCallTargetOperand() }
+ override Node getDispatchValue() { result.asOperand() = this.getCallTargetOperand() }
override Function resolve() {
exists(FunctionInstruction fi |
- this.flowsFrom(DataFlow::instructionNode(fi), _) and
+ this.flowsFrom(instructionNode(fi), _) and
result = fi.getFunctionSymbol()
) and
(
@@ -186,7 +181,7 @@ private module VirtualDispatch {
)
}
- override DataFlow::Node getDispatchValue() { result.asInstruction() = this.getArgument(-1) }
+ override Node getDispatchValue() { result.asInstruction() = this.getArgument(-1) }
override MemberFunction resolve() {
exists(Class overridingClass |
@@ -213,7 +208,7 @@ private module VirtualDispatch {
pragma[noinline]
private predicate hasFlowFromCastFrom(Class derivedClass) {
exists(ConvertToBaseInstruction toBase |
- this.flowsFrom(DataFlow::instructionNode(toBase), _) and
+ this.flowsFrom(instructionNode(toBase), _) and
derivedClass = toBase.getDerivedClass()
)
}
@@ -270,7 +265,7 @@ private predicate mayBenefitFromCallContext(
exists(InitializeParameterInstruction init |
not exists(call.getStaticCallTarget()) and
init.getEnclosingFunction() = f.getUnderlyingCallable() and
- call.flowsFrom(DataFlow::instructionNode(init), _) and
+ call.flowsFrom(instructionNode(init), _) and
init.getParameter().getIndex() = arg
)
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
index d7f26dd0051..a03042a77ff 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll
@@ -4,7 +4,7 @@ private import semmle.code.cpp.ir.IR
private import DataFlowDispatch
private import semmle.code.cpp.ir.internal.IRCppLanguage
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
-private import SsaInternals as Ssa
+private import SsaImpl as Ssa
private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
private import Node0ToString
@@ -332,6 +332,13 @@ private module IndirectInstructions {
import IndirectInstructions
+predicate isPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
+ operand = any(FieldAddress fa).getObjectAddressOperand() and
+ indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(Ssa::getLanguageType(operand))]
+ or
+ Ssa::isModifiableByCall(operand, indirectionIndex)
+}
+
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
@@ -1982,19 +1989,23 @@ module IteratorFlow {
predicate allowFlowIntoUncertainDef(IteratorSsa::UncertainWriteDefinition def) { any() }
+ class GuardValue = Void;
+
class Guard extends Void {
- predicate hasBranchEdge(SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, boolean branch) {
+ predicate hasValueBranchEdge(
+ SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue val
+ ) {
none()
}
- predicate controlsBranchEdge(
- SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, boolean branch
+ predicate valueControlsBranchEdge(
+ SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue val
) {
none()
}
}
- predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, boolean branch) {
+ predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, GuardValue val) {
none()
}
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
index 38a4d827a4d..a0a99711552 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
@@ -13,7 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import DataFlowPrivate
private import ModelUtil
-private import SsaInternals as Ssa
+private import SsaImpl as SsaImpl
private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
private import Node0ToString
@@ -39,38 +39,35 @@ private newtype TIRDataFlowNode =
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
TGlobalLikeVariableNode(GlobalLikeVariable var, int indirectionIndex) {
indirectionIndex =
- [getMinIndirectionsForType(var.getUnspecifiedType()) .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
+ [getMinIndirectionsForType(var.getUnspecifiedType()) .. SsaImpl::getMaxIndirectionsForType(var.getUnspecifiedType())]
} or
TPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
- operand = any(FieldAddress fa).getObjectAddressOperand() and
- indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(Ssa::getLanguageType(operand))]
- or
- Ssa::isModifiableByCall(operand, indirectionIndex)
+ isPostUpdateNodeImpl(operand, indirectionIndex)
} or
- TSsaSynthNode(Ssa::SynthNode n) or
+ TSsaSynthNode(SsaImpl::SynthNode n) or
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
- Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
+ SsaImpl::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
} or
TRawIndirectInstruction0(Node0Impl node, int indirectionIndex) {
not exists(node.asOperand()) and
- Ssa::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
+ SsaImpl::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
} or
TFinalParameterNode(Parameter p, int indirectionIndex) {
- exists(Ssa::FinalParameterUse use |
+ exists(SsaImpl::FinalParameterUse use |
use.getParameter() = p and
use.getIndirectionIndex() = indirectionIndex
)
} or
- TFinalGlobalValue(Ssa::GlobalUse globalUse) or
- TInitialGlobalValue(Ssa::GlobalDef globalUse) or
+ TFinalGlobalValue(SsaImpl::GlobalUse globalUse) or
+ TInitialGlobalValue(SsaImpl::GlobalDef globalUse) or
TBodyLessParameterNodeImpl(Parameter p, int indirectionIndex) {
// Rule out parameters of catch blocks.
not exists(p.getCatchBlock()) and
// We subtract one because `getMaxIndirectionsForType` returns the maximum
// indirection for a glvalue of a given type, and this doesn't apply to
// parameters.
- indirectionIndex = [0 .. Ssa::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
+ indirectionIndex = [0 .. SsaImpl::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
not any(InitializeParameterInstruction init).getParameter() = p
} or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn)
@@ -81,7 +78,7 @@ private newtype TIRDataFlowNode =
class FieldAddress extends Operand {
FieldAddressInstruction fai;
- FieldAddress() { fai = this.getDef() and not Ssa::ignoreOperand(this) }
+ FieldAddress() { fai = this.getDef() and not SsaImpl::ignoreOperand(this) }
/** Gets the field associated with this instruction. */
Field getField() { result = fai.getField() }
@@ -126,7 +123,7 @@ predicate conversionFlow(
)
or
additional = true and
- Ssa::isAdditionalConversionFlow(opFrom, instrTo)
+ SsaImpl::isAdditionalConversionFlow(opFrom, instrTo)
)
or
isPointerArith = true and
@@ -183,7 +180,7 @@ class Node extends TIRDataFlowNode {
or
this.asOperand().getUse() = block.getInstruction(i)
or
- exists(Ssa::SynthNode ssaNode |
+ exists(SsaImpl::SynthNode ssaNode |
this.(SsaSynthNode).getSynthNode() = ssaNode and
ssaNode.getBasicBlock() = block and
ssaNode.getIndex() = i
@@ -364,10 +361,10 @@ class Node extends TIRDataFlowNode {
* pointed to by `p`.
*/
Expr asDefinition(boolean uncertain) {
- exists(StoreInstruction store, Ssa::Definition def |
+ exists(StoreInstruction store, SsaImpl::Definition def |
store = this.asInstruction() and
result = asDefinitionImpl(store) and
- Ssa::defToNode(this, def, _) and
+ SsaImpl::defToNode(this, def, _) and
if def.isCertain() then uncertain = false else uncertain = true
)
}
@@ -627,7 +624,7 @@ class OperandNode extends Node, Node0 {
* For example, `stripPointers(int*&)` is `int*` and `stripPointers(int*)` is `int`.
*/
Type stripPointer(Type t) {
- result = any(Ssa::Indirection ind | ind.getType() = t).getBaseType()
+ result = any(SsaImpl::Indirection ind | ind.getType() = t).getBaseType()
or
result = t.(PointerToMemberType).getBaseType()
or
@@ -694,12 +691,12 @@ class PostFieldUpdateNode extends PostUpdateNodeImpl {
* in a data flow graph.
*/
class SsaSynthNode extends Node, TSsaSynthNode {
- Ssa::SynthNode node;
+ SsaImpl::SynthNode node;
SsaSynthNode() { this = TSsaSynthNode(node) }
/** Gets the synthesized SSA node associated with this node. */
- Ssa::SynthNode getSynthNode() { result = node }
+ SsaImpl::SynthNode getSynthNode() { result = node }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
@@ -782,12 +779,12 @@ class SideEffectOperandNode extends Node instanceof IndirectOperand {
* from a function body.
*/
class FinalGlobalValue extends Node, TFinalGlobalValue {
- Ssa::GlobalUse globalUse;
+ SsaImpl::GlobalUse globalUse;
FinalGlobalValue() { this = TFinalGlobalValue(globalUse) }
/** Gets the underlying SSA use. */
- Ssa::GlobalUse getGlobalUse() { result = globalUse }
+ SsaImpl::GlobalUse getGlobalUse() { result = globalUse }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
@@ -814,12 +811,12 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
* a function body.
*/
class InitialGlobalValue extends Node, TInitialGlobalValue {
- Ssa::GlobalDef globalDef;
+ SsaImpl::GlobalDef globalDef;
InitialGlobalValue() { this = TInitialGlobalValue(globalDef) }
/** Gets the underlying SSA definition. */
- Ssa::GlobalDef getGlobalDef() { result = globalDef }
+ SsaImpl::GlobalDef getGlobalDef() { result = globalDef }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getFunction()
@@ -1288,11 +1285,11 @@ class UninitializedNode extends Node {
LocalVariable v;
UninitializedNode() {
- exists(Ssa::Definition def, Ssa::SourceVariable sv |
+ exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv |
def.getIndirectionIndex() = 0 and
def.getValue().asInstruction() instanceof UninitializedInstruction and
- Ssa::defToNode(this, def, sv) and
- v = sv.getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
+ SsaImpl::defToNode(this, def, sv) and
+ v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst()
)
}
@@ -1722,7 +1719,7 @@ private module Cached {
cached
predicate flowsToBackEdge(Node n) {
exists(Node succ, IRBlock bb1, IRBlock bb2 |
- Ssa::ssaFlow(n, succ) and
+ SsaImpl::ssaFlow(n, succ) and
bb1 = n.getBasicBlock() and
bb2 = succ.getBasicBlock() and
bb1 != bb2 and
@@ -1820,7 +1817,7 @@ private module Cached {
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
(
// Def-use/Use-use flow
- Ssa::ssaFlow(nodeFrom, nodeTo)
+ SsaImpl::ssaFlow(nodeFrom, nodeTo)
or
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
or
@@ -1833,7 +1830,7 @@ private module Cached {
|
simpleOperandLocalFlowStep(iFrom, opTo) and
// Omit when the instruction node also represents the operand.
- not iFrom = Ssa::getIRRepresentationOfOperand(opTo)
+ not iFrom = SsaImpl::getIRRepresentationOfOperand(opTo)
)
or
// Indirect operand -> (indirect) instruction flow
@@ -1906,7 +1903,7 @@ private module Cached {
// We also want a write coming out of an `OutNode` to flow `nodeTo`.
// This is different from `reverseFlowInstruction` since `nodeFrom` can never
// be an `OutNode` when it's defined by an instruction.
- Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
+ SsaImpl::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
)
}
@@ -2099,7 +2096,7 @@ private newtype TContent =
TFieldContent(Field f, int indirectionIndex) {
// the indirection index for field content starts at 1 (because `TFieldContent` is thought of as
// the address of the field, `FieldAddress` in the IR).
- indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(f.getUnspecifiedType())] and
+ indirectionIndex = [1 .. SsaImpl::getMaxIndirectionsForType(f.getUnspecifiedType())] and
// Reads and writes of union fields are tracked using `UnionContent`.
not f.getDeclaringType() instanceof Union
} or
@@ -2111,7 +2108,9 @@ private newtype TContent =
// field can be read by any read of the union's fields. Again, the indirection index
// is 1-based (because 0 is considered the address).
indirectionIndex =
- [1 .. max(Ssa::getMaxIndirectionsForType(getAFieldWithSize(u, bytes).getUnspecifiedType()))]
+ [1 .. max(SsaImpl::getMaxIndirectionsForType(getAFieldWithSize(u, bytes)
+ .getUnspecifiedType())
+ )]
)
} or
TElementContent(int indirectionIndex) {
@@ -2354,7 +2353,7 @@ module BarrierGuard SnakeYAML - XML Decoder - org.yaml:snakeyaml
-
org.yaml.snakeyaml.constructor.SafeConstructor to org.yaml.snakeyaml.Yaml's constructor before using it to deserialize untrusted data.org.yaml.snakeyaml.constructor.SafeConstructor to org.yaml.snakeyaml.Yaml's constructor before using it to deserialize untrusted data.Standard Java LibraryKeyboardInterrupt to propagate.
except block may be an indication that the programmer intended to
-handle the exception but never wrote the code to do so.
In this example the program keeps running with the same privileges if it fails to drop to lower +
In this example, the program keeps running with the same privileges if it fails to drop to lower privileges.
NotImplemented is not an Exception, but is often mistakenly used in place of NotImplementedError.
-Executing raise NotImplemented or raise NotImplemented() will raise a TypeError.
-When raise NotImplemented is used to mark code that is genuinely never called, this mistake is benign.
-
-However, should it be called, then a TypeError will be raised rather than the expected NotImplemented,
-which might make debugging the issue difficult.
+
+The constant NotImplemented is not an Exception, but is often confused for NotImplementedError.
+If it is used as an exception, such as in raise NotImplemented or raise NotImplemented("message"),
+a TypeError will be raised rather than the expected NotImplemented. This may make debugging more difficult.
The correct use of NotImplemented is to implement binary operators.
+
NotImplemented should only be used as a special return value for implementing special methods such as __lt__.
Code that is not intended to be called should raise NotImplementedError.
Replace uses of NotImplemented with NotImplementedError.
If a NotImplementedError is intended to be raised, replace the use of NotImplemented
+with that. If NotImplemented is intended to be returned rather than raised, replace the raise with return NotImplemented.
+
-In the example below, the method wrong will incorrectly raise a TypeError when called.
+In the following example, the method wrong will incorrectly raise a TypeError when called.
The method right will raise a NotImplementedError.
right will raise a NotImplementedError.
-In this example the call to super(Vehicle, self) in Car.__init__ is incorrect as it
+In this example, the call to super(Vehicle, self) in Car.__init__ is incorrect, as it
passes Vehicle rather than Car as the first argument to super.
As a result, super(SportsCar, self).__init__() in the SportsCar.__init__ method will not call
all __init__() methods because the call to super(Vehicle, self).__init__()
@@ -37,7 +37,7 @@ skips StatusSymbol.__init__().
Dictionary literals are constructed in the order given in the source. -This means that if a key is duplicated the second key-value pair will overwrite -the first as a dictionary can only have one value per key. +This means that if a key is duplicated, the second key-value pair will overwrite +the first; as a dictionary can only have one value per key.
This example will output "c" because the mapping between 2 and "b" is overwritten by the -mapping from 2 to "c". The programmer may have meant to map 3 to "c" instead.
+The following example will output "c", because the mapping between 2 and "b" is overwritten by the
+mapping from 2 to "c". The programmer may have meant to map 3 to "c" instead.
with statement.
In the first example, rather than close the zip file in a conventional manner the programmer has called __del__.
+
In the first example, rather than close the zip file in a conventional manner, the programmer has called __del__.
A safer alternative is shown in the second example.
A format string, that is the string on the left hand side of an expression like fmt % arguments, must consist of legal conversion specifiers.
+
A printf-style format string (i.e. a string that is used as the left hand side of the % operator, such as fmt % arguments)
+must consist of valid conversion specifiers, such as %s, %d, etc.
Otherwise, a ValueError will be raised.
Choose a legal conversion specifier.
+Ensure a valid conversion specifier is used.
In format_as_tuple_incorrect, "t" is not a legal conversion specifier.
+
In the following example, format_as_tuple_incorrect, %t is not a valid conversion specifier.
ValueError will be raised.
When a function contains both explicit returns (return value) and implicit returns
-(where code falls off the end of a function) this often indicates that a return
+(where code falls off the end of a function), this often indicates that a return
statement has been forgotten. It is best to return an explicit return value even when returning
None because this makes it easier for other developers to read your code.
None as this equates to False. However
default=None, check if the parameter is
+Sensitive information that is stored unencrypted in a database is accessible to an attacker +who gains access to that database. For example, the information could be accessed by any +process or user in a rooted device, or exposed through another vulnerability. +
++Either encrypt the entire database, or ensure that each piece of sensitive information is +encrypted before being stored. In general, decrypt sensitive information only at the point +where it is necessary for it to be used in cleartext. Avoid storing sensitive information +at all if you do not need to keep it. +
++The following example stores sensitive information into a database without encryption, using the +SQLx library: +
++This is insecure because the sensitive data is stored in cleartext, making it accessible to anyone +with access to the database. +
++To fix this, we can either encrypt the entire database or encrypt just the sensitive data before it +is stored. Take care to select a secure modern encryption algorithm and put suitable key management +practices into place. In the following example, we have encrypted the sensitive data using 256-bit +AES before storing it in the database: +
++Hard-coded passwords, keys, initialization vectors, and salts should not be used for cryptographic operations. +
++Use randomly generated key material, initialization vectors, and salts. Use strong passwords that are not hard-coded. +
+ ++The following example shows instantiating a cipher with hard-coded key material, making the encrypted data vulnerable to recovery. +
+ ++In the fixed code below, the key material is randomly generated and not hard-coded, which protects the encrypted data against recovery. A real application would also need a strategy for secure key management after the key has been generated. +
+ +