Compare commits

..

39 Commits

Author SHA1 Message Date
Arthur Baars
306e481c5d Merge pull request #16830 from github/post-release-prep/codeql-cli-2.17.6
Post-release preparation for codeql-cli-2.17.6
2024-06-25 15:26:05 +02:00
Arthur Baars
046a5f0881 Merge branch 'rc/3.14' into post-release-prep/codeql-cli-2.17.6 2024-06-25 11:43:38 +02:00
Arthur Baars
624c574559 Merge pull request #16831 from smowton/smowton/admin/backport-maven-regex-fix
Backport Maven regex fix to rc/3.14
2024-06-25 11:42:54 +02:00
Chris Smowton
5608e0141c Adjust and tolerate variability in test expectations 2024-06-25 09:02:58 +01:00
github-actions[bot]
fd385736e6 Post-release preparation for codeql-cli-2.17.6 2024-06-25 06:39:45 +00:00
Arthur Baars
0508d4fa33 Merge pull request #16821 from github/release-prep/2.17.6
Release preparation for version 2.17.6
2024-06-24 21:17:34 +02:00
github-actions[bot]
e32a587078 Release preparation for version 2.17.6 2024-06-24 14:33:10 +00:00
Florin Coada
b7b35e5913 Merge pull request #16778 from github/coadaflorin/2.17.4-changedocs-patch
2.17.4 Changelog patch
2024-06-18 13:49:17 +01:00
Florin Coada
34f5b676f1 2.17.4 Changelogs patch 2024-06-18 13:34:03 +01:00
Florin Coada
004451ee4b Merge pull request #16773 from github/changedocs/2.17.5
add 2.17.5 unified changelog
2024-06-17 16:09:37 +01:00
Florin Coada
32202acc2d quick fix to remove multiple mentions of CodeQL pack upgrade 2024-06-17 12:19:01 +01:00
Florin Coada
44cca056de add 2.17.5 unified changelog 2024-06-17 12:00:50 +01:00
Mathias Vorreiter Pedersen
9384f6189e Merge pull request #16740 from MathiasVP/fix-join-in-ssa
SSA: Fix bad join in `lastRefRedefExt`
2024-06-13 09:06:20 +01:00
Mathias Vorreiter Pedersen
5b3403c4b1 C++: Fix bad join in 'lastRefRedefExt'. 2024-06-12 15:24:58 +01:00
Mathias Vorreiter Pedersen
b88a1b2d1e Merge pull request #16724 from MathiasVP/cache-asexpr
C++: Cache `asExpr` (and `asIndirectExpr`) implementation predicates
2024-06-11 16:17:29 +01:00
Mathias Vorreiter Pedersen
6a6978398a C++: Add file QLDoc. 2024-06-11 15:39:45 +01:00
Mathias Vorreiter Pedersen
333df03f64 C++: Cache more things. 2024-06-11 15:39:43 +01:00
Chris Smowton
3172054073 Merge pull request #16717 from github/post-release-prep/codeql-cli-2.17.5
Post-release preparation for codeql-cli-2.17.5
2024-06-11 07:56:55 +01:00
github-actions[bot]
8a25081a0e Post-release preparation for codeql-cli-2.17.5 2024-06-10 15:33:08 +00:00
Chris Smowton
a160b891c8 Merge pull request #16715 from github/release-prep/2.17.5
Release preparation for version 2.17.5
2024-06-10 14:46:30 +01:00
github-actions[bot]
877bfa2468 Release preparation for version 2.17.5 2024-06-10 13:40:39 +00:00
Cornelius Riemenschneider
7ecf1f9010 Merge pull request #16713 from github/criemen/csharp-version-fallback
C#: Add fallback for branch detection.
2024-06-10 14:24:37 +02:00
Jeroen Ketema
000a81fd29 Merge pull request #16690 from MathiasVP/better-guards
C++: Fix missing results for `comparesEq` in `IRGuardCondition`
2024-06-10 13:32:10 +02:00
Cornelius Riemenschneider
027c7d0d43 C#: Add fallback for branch detection.
Apparently, when building a release build, we're getting `no-git`
as first part o the version string for the submodule.
If we do, fall back to the internal repo's branch name.
For releases, that's the same anyways.
Luckily, the commit SHA is correct.
2024-06-10 12:14:03 +02:00
Mathias Vorreiter Pedersen
7819cc1c36 C++: Add more QLDoc. 2024-06-10 10:58:52 +01:00
Tamás Vajk
06aa2664bf Merge pull request #16705 from tamasvajk/build/fix-attributes
C#: Add assembly attributes to assemblies built with Bazel
2024-06-10 09:26:31 +02:00
Tamas Vajk
5f98f2aec9 Add assembly attributes to bazel build script 2024-06-07 15:42:12 +02:00
Cornelius Riemenschneider
6731bccc92 C#: Provide skeleton to generate an assemblyInfo file.
Each unit gets a unique assemblyInfo file, on top
of the ones for entrypoints that also gets the git info embedded.
2024-06-07 15:24:53 +02:00
Tamas Vajk
16f8be4ba4 C#: Add product name to assemblies 2024-06-07 15:24:21 +02:00
Tamas Vajk
beffc2a49d C#: Remove unneeded source folder from Bazel build scripts 2024-06-07 15:23:45 +02:00
Mathias Vorreiter Pedersen
7f62085be5 C++: Delete unused predicate. 2024-06-07 09:13:29 +01:00
Mathias Vorreiter Pedersen
ed525fce70 C++: Accept test changes. 2024-06-06 20:38:31 +01:00
Mathias Vorreiter Pedersen
b5a3575130 C++: Make proper use of barrier guards in test. 2024-06-06 20:38:17 +01:00
Mathias Vorreiter Pedersen
7b92554cf2 Merge branch 'main' into better-guards 2024-06-06 19:22:10 +01:00
Mathias Vorreiter Pedersen
9564ae1ca4 C++: Accept more test changes. 2024-06-06 17:04:48 +01:00
Mathias Vorreiter Pedersen
528afba919 C++: Accept test changes. 2024-06-06 16:32:29 +01:00
Mathias Vorreiter Pedersen
36aac3ffd8 C++: Get rid of 'relevantUnaryComparison' since it was excluding too much. The performance is most likely fine with that restriction. 2024-06-06 16:32:16 +01:00
Mathias Vorreiter Pedersen
703832f5a1 C++: Remove a column from a few predicates. 2024-06-06 16:30:32 +01:00
Mathias Vorreiter Pedersen
0298755975 C++: Add a test. 2024-06-06 16:22:23 +01:00
223 changed files with 1388 additions and 649 deletions

View File

@@ -1,3 +1,17 @@
## 1.1.1
No user-facing changes.
## 1.1.0
### New Features
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
### Minor Analysis Improvements
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.
## 1.0.0
### Breaking Changes

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.

View File

@@ -0,0 +1,9 @@
## 1.1.0
### New Features
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
### Minor Analysis Improvements
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.

View File

@@ -0,0 +1,3 @@
## 1.1.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.0
lastReleaseVersion: 1.1.1

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 1.0.1-dev
version: 1.1.2-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -375,6 +375,33 @@ cached
class IRGuardCondition extends Instruction {
Instruction branch;
/*
* An `IRGuardCondition` supports reasoning about four different kinds of
* relations:
* 1. A unary equality relation of the form `e == k`
* 2. A binary equality relation of the form `e1 == e2 + k`
* 3. A unary inequality relation of the form `e < k`
* 4. A binary inequality relation of the form `e1 < e2 + k`
*
* where `k` is a constant.
*
* Furthermore, the unary relations (i.e., case 1 and case 3) are also
* inferred from `switch` statement guards: equality relations are inferred
* from the unique `case` statement, if any, and inequality relations are
* inferred from the [case range](https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html)
* gcc extension.
*
* The implementation of all four follows the same structure: Each relation
* has a cached user-facing predicate that. For example,
* `GuardCondition::comparesEq` calls `compares_eq`. This predicate has
* several cases that recursively decompose the relation to bring it to a
* canonical form (i.e., a relation of the form `e1 == e2 + k`). The base
* case for this relation (i.e., `simple_comparison_eq`) handles
* `CompareEQInstruction`s and `CompareNEInstruction`, and recursive
* predicates (e.g., `complex_eq`) rewrites larger expressions such as
* `e1 + k1 == e2 + k2` into canonical the form `e1 == e2 + (k2 - k1)`.
*/
cached
IRGuardCondition() { branch = getBranchForCondition(this) }
@@ -776,7 +803,9 @@ private predicate unary_compares_eq(
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
) {
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
exists(AbstractValue v | unary_simple_comparison_eq(test, op, k, inNonZeroCase, v) |
exists(AbstractValue v |
unary_simple_comparison_eq(test, k, inNonZeroCase, v) and op.getDef() = test
|
areEqual = true and value = v
or
areEqual = false and value = v.getDualValue()
@@ -821,45 +850,55 @@ private predicate simple_comparison_eq(
value.(BooleanValue).getValue() = false
}
/**
* Holds if `test` is an instruction that is part of test that eventually is
* used in a conditional branch.
*/
private predicate relevantUnaryComparison(Instruction test) {
not test instanceof CompareInstruction and
exists(IRType type, ConditionalBranchInstruction branch |
type instanceof IRAddressType or type instanceof IRIntegerType
|
type = test.getResultIRType() and
branch.getCondition() = test
)
or
exists(LogicalNotInstruction logicalNot |
relevantUnaryComparison(logicalNot) and
test = logicalNot.getUnary()
)
}
/**
* Rearrange various simple comparisons into `op == k` form.
*/
private predicate unary_simple_comparison_eq(
Instruction test, Operand op, int k, boolean inNonZeroCase, AbstractValue value
Instruction test, int k, boolean inNonZeroCase, AbstractValue value
) {
exists(SwitchInstruction switch, CaseEdge case |
test = switch.getExpression() and
op.getDef() = test and
case = value.(MatchValue).getCase() and
exists(switch.getSuccessor(case)) and
case.getValue().toInt() = k and
inNonZeroCase = false
)
or
// There's no implicit CompareInstruction in files compiled as C since C
// doesn't have implicit boolean conversions. So instead we check whether
// there's a branch on a value of pointer or integer type.
relevantUnaryComparison(test) and
op.getDef() = test and
// Any instruction with an integral type could potentially be part of a
// check for nullness when used in a guard. So we include all integral
// typed instructions here. However, since some of these instructions are
// already included as guards in other cases, we exclude those here.
// These are instructions that compute a binary equality or inequality
// relation. For example, the following:
// ```cpp
// if(a == b + 42) { ... }
// ```
// generates the following IR:
// ```
// r1(glval<int>) = VariableAddress[a] :
// r2(int) = Load[a] : &:r1, m1
// r3(glval<int>) = VariableAddress[b] :
// r4(int) = Load[b] : &:r3, m2
// r5(int) = Constant[42] :
// r6(int) = Add : r4, r5
// r7(bool) = CompareEQ : r2, r6
// v1(void) = ConditionalBranch : r7
// ```
// and since `r7` is an integral typed instruction this predicate could
// include a case for when `r7` evaluates to true (in which case we would
// infer that `r6` was non-zero, and a case for when `r7` evaluates to false
// (in which case we would infer that `r6` was zero).
// However, since `a == b + 42` is already supported when reasoning about
// binary equalities we exclude those cases here.
not test.isGLValue() and
not simple_comparison_eq(test, _, _, _, _) and
not simple_comparison_lt(test, _, _, _) and
not test = any(SwitchInstruction switch).getExpression() and
(
test.getResultIRType() instanceof IRAddressType or
test.getResultIRType() instanceof IRIntegerType or
test.getResultIRType() instanceof IRBooleanType
) and
(
k = 1 and
value.(BooleanValue).getValue() = true and
@@ -913,7 +952,8 @@ private predicate compares_lt(
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
private predicate compares_lt(Instruction test, Operand op, int k, boolean isLt, AbstractValue value) {
simple_comparison_lt(test, op, k, isLt, value)
unary_simple_comparison_lt(test, k, isLt, value) and
op.getDef() = test
or
complex_lt(test, op, k, isLt, value)
or
@@ -960,12 +1000,11 @@ private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Ope
}
/** Rearrange various simple comparisons into `op < k` form. */
private predicate simple_comparison_lt(
Instruction test, Operand op, int k, boolean isLt, AbstractValue value
private predicate unary_simple_comparison_lt(
Instruction test, int k, boolean isLt, AbstractValue value
) {
exists(SwitchInstruction switch, CaseEdge case |
test = switch.getExpression() and
op.getDef() = test and
case = value.(MatchValue).getCase() and
exists(switch.getSuccessor(case)) and
case.getMaxValue() > case.getMinValue()

View File

@@ -17,6 +17,7 @@ private import SsaInternals as Ssa
private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
private import Node0ToString
import ExprNodes
/**
* The IR dataflow graph consists of the following nodes:
@@ -1296,466 +1297,6 @@ class UninitializedNode extends Node {
LocalVariable getLocalVariable() { result = v }
}
private module GetConvertedResultExpression {
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
}
/**
* Gets the expression that should be returned as the result expression from `instr`.
*
* Note that this predicate may return multiple results in cases where a conversion belongs to a
* different AST element than its operand.
*/
Expr getConvertedResultExpression(Instruction instr, int n) {
// Only fully converted instructions have a result for `asConvertedExpr`
not conversionFlow(unique(Operand op |
// The address operand of a `InitializeDynamicAllocationInstruction` is
// special: we need to handle it during dataflow (since it's
// effectively a store to an indirection), but it doesn't appear in
// source syntax, so dataflow node <-> expression conversion shouldn't
// care about it.
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
op
), _, false, false) and
result = getConvertedResultExpressionImpl(instr) and
n = 0
or
// If the conversion also has a result then we return multiple results
exists(Operand operand | conversionFlow(operand, instr, false, false) |
n = 1 and
result = getConvertedResultExpressionImpl(operand.getDef())
or
result = getConvertedResultExpression(operand.getDef(), n - 1)
)
}
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
// IR construction inserts an additional cast to a `size_t` on the extent
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
// a result for `getConvertedResultExpression`. We remap this here so that
// this `ConvertInstruction` maps to the result of the expression that
// represents the extent.
exists(TranslatedNonConstantAllocationSize tas |
result = tas.getExtent().getExpr() and
instr = tas.getInstruction(AllocationExtentConvertTag())
)
or
// There's no instruction that returns `ParenthesisExpr`, but some queries
// expect this
exists(TranslatedTransparentConversion ttc |
result = ttc.getExpr().(ParenthesisExpr) and
instr = ttc.getResult()
)
or
// Certain expressions generate `CopyValueInstruction`s only when they
// are needed. Examples of this include crement operations and compound
// assignment operations. For example:
// ```cpp
// int x = ...
// int y = x++;
// ```
// this generate IR like:
// ```
// r1(glval<int>) = VariableAddress[x] :
// r2(int) = Constant[0] :
// m3(int) = Store[x] : &:r1, r2
// r4(glval<int>) = VariableAddress[y] :
// r5(glval<int>) = VariableAddress[x] :
// r6(int) = Load[x] : &:r5, m3
// r7(int) = Constant[1] :
// r8(int) = Add : r6, r7
// m9(int) = Store[x] : &:r5, r8
// r11(int) = CopyValue : r6
// m12(int) = Store[y] : &:r4, r11
// ```
// When the `CopyValueInstruction` is not generated there is no instruction
// whose `getConvertedResultExpression` maps back to the expression. When
// such an instruction doesn't exist it means that the old value is not
// needed, and in that case the only value that will propagate forward in
// the program is the value that's been updated. So in those cases we just
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
exists(TranslatedCoreExpr tco |
tco.getInstruction(_) = instr and
tco.producesExprResult() and
result = asDefinitionImpl0(instr)
)
}
private Expr getConvertedResultExpressionImpl(Instruction instr) {
result = getConvertedResultExpressionImpl0(instr)
or
not exists(getConvertedResultExpressionImpl0(instr)) and
result = instr.getConvertedResultExpression()
}
/**
* Gets the result for `node.asDefinition()` (when `node` is the instruction
* node that wraps `store`) in the cases where `store.getAst()` should not be
* used to define the result of `node.asDefinition()`.
*/
private Expr asDefinitionImpl0(StoreInstruction store) {
// For an expression such as `i += 2` we pretend that the generated
// `StoreInstruction` contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedAssignOperation tao |
store = tao.getInstruction(AssignmentStoreTag()) and
result = tao.getExpr()
)
or
// Similarly for `i++` and `++i` we pretend that the generated
// `StoreInstruction` is contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedCrementOperation tco |
store = tco.getInstruction(CrementStoreTag()) and
result = tco.getExpr()
)
}
/**
* Holds if the expression returned by `store.getAst()` should not be
* returned as the result of `node.asDefinition()` when `node` is the
* instruction node that wraps `store`.
*/
private predicate excludeAsDefinitionResult(StoreInstruction store) {
// Exclude the store to the temporary generated by a ternary expression.
exists(TranslatedConditionalExpr tce |
store = tce.getInstruction(ConditionValueFalseStoreTag())
or
store = tce.getInstruction(ConditionValueTrueStoreTag())
)
}
/**
* Gets the expression that represents the result of `StoreInstruction` for
* dataflow purposes.
*
* For example, consider the following example
* ```cpp
* int x = 42; // 1
* x = 34; // 2
* ++x; // 3
* x++; // 4
* x += 1; // 5
* int y = x += 2; // 6
* ```
* For (1) the result is `42`.
* For (2) the result is `x = 34`.
* For (3) the result is `++x`.
* For (4) the result is `x++`.
* For (5) the result is `x += 1`.
* For (6) there are two results:
* - For the `StoreInstruction` generated by `x += 2` the result
* is `x += 2`
* - For the `StoreInstruction` generated by `int y = ...` the result
* is also `x += 2`
*/
Expr asDefinitionImpl(StoreInstruction store) {
not exists(asDefinitionImpl0(store)) and
not excludeAsDefinitionResult(store) and
result = store.getAst().(Expr).getUnconverted()
or
result = asDefinitionImpl0(store)
}
}
private import GetConvertedResultExpression
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
not exprNodeShouldBeIndirectOperand(_, e, n) and
exists(Instruction def |
unique( | | getAUse(def)) = node.getOperand() and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
private predicate indirectExprNodeShouldBeIndirectOperand(
IndirectOperand node, Expr e, int n, int indirectionIndex
) {
exists(Instruction def |
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
exists(ArgumentOperand operand |
// When an argument (qualifier or positional) is a prvalue and the
// parameter (qualifier or positional) is a (const) reference, IR
// construction introduces a temporary `IRVariable`. The `VariableAddress`
// instruction has the argument as its `getConvertedResultExpression`
// result. However, the instruction actually represents the _address_ of
// the argument. So to fix this mismatch, we have the indirection of the
// `VariableAddressInstruction` map to the expression.
node.hasOperandAndIndirectionIndex(operand, 1) and
e = getConvertedResultExpression(operand.getDef(), n) and
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
)
}
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
exists(CallInstruction call |
call.getStaticCallTarget() instanceof Constructor and
e = getConvertedResultExpression(call, n) and
call.getThisArgumentOperand() = node.getAddressOperand()
)
}
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
not exprNodeShouldBeOperand(_, e, n) and
not exprNodeShouldBeIndirectOutNode(_, e, n) and
not exprNodeShouldBeIndirectOperand(_, e, n) and
e = getConvertedResultExpression(node.asInstruction(), n)
}
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
predicate indirectExprNodeShouldBeIndirectInstruction(
IndirectInstruction node, Expr e, int n, int indirectionIndex
) {
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
exists(Instruction instr |
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
e = getConvertedResultExpression(instr, n)
)
}
abstract private class ExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
}
/**
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
* to `e`.
*/
private predicate exprNodeShouldBe(Expr e, int n) {
exprNodeShouldBeInstruction(_, e, n) or
exprNodeShouldBeOperand(_, e, n) or
exprNodeShouldBeIndirectOutNode(_, e, n) or
exprNodeShouldBeIndirectOperand(_, e, n)
}
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
InstructionExprNode() {
exists(Expr e, int n |
exprNodeShouldBeInstruction(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
}
private class OperandExprNode extends ExprNodeBase, OperandNode {
OperandExprNode() {
exists(Expr e, int n |
exprNodeShouldBeOperand(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
}
abstract private class IndirectExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n, int indirectionIndex);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n, int indirectionIndex) {
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
}
}
/** A signature for converting an indirect node to an expression. */
private signature module IndirectNodeToIndirectExprSig {
/** The indirect node class to be converted to an expression */
class IndirectNode;
/**
* Holds if the indirect expression at indirection index `indirectionIndex`
* of `node` is `e`. The integer `n` specifies how many conversions has been
* applied to `node`.
*/
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
}
/**
* A module that implements the logic for deciding whether an indirect node
* should be an `IndirectExprNode`.
*/
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
import Sig
/**
* This predicate shifts the indirection index by one when `conv` is a
* `ReferenceDereferenceExpr`.
*
* This is necessary because `ReferenceDereferenceExpr` is a conversion
* in the AST, but appears as a `LoadInstruction` in the IR.
*/
bindingset[e, indirectionIndex]
private predicate adjustForReference(
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
) {
conv.(ReferenceDereferenceExpr).getExpr() = e and
adjustedIndirectionIndex = indirectionIndex - 1
or
not conv instanceof ReferenceDereferenceExpr and
conv = e and
adjustedIndirectionIndex = indirectionIndex
}
/** Holds if `node` should be an `IndirectExprNode`. */
predicate charpred(IndirectNode node) {
exists(Expr e, int n, int indirectionIndex |
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
not exists(Expr conv, int adjustedIndirectionIndex |
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
)
)
}
}
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
}
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectOperand;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
}
module IndirectOperandToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
{
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectInstruction;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
}
module IndirectInstructionToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
{
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
}
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
}
/**
* An expression, viewed as a node in a data flow graph.
*/
class ExprNode extends Node instanceof ExprNodeBase {
/**
* INTERNAL: Do not use.
*/
Expr getExpr(int n) { result = super.getExpr(n) }
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
final Expr getExpr() { result = this.getExpr(_) }
/**
* INTERNAL: Do not use.
*/
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
}
/**
* An indirect expression, viewed as a node in a data flow graph.
*/
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
Expr getConvertedExpr(int n, int indirectionIndex) {
result = super.getConvertedExpr(n, indirectionIndex)
}
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
Expr getConvertedExpr(int indirectionIndex) {
result = this.getConvertedExpr(_, indirectionIndex)
}
}
abstract private class AbstractParameterNode extends Node {
/**
* Holds if this node is the parameter of `f` at the specified position. The

View File

@@ -0,0 +1,479 @@
/**
* Provides the classes `ExprNode` and `IndirectExprNode` for converting between `Expr` and `Node`.
*/
private import cpp
private import semmle.code.cpp.ir.IR
private import DataFlowUtil
private import DataFlowPrivate
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
cached
private module Cached {
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
}
/**
* Gets the expression that should be returned as the result expression from `instr`.
*
* Note that this predicate may return multiple results in cases where a conversion belongs to a
* different AST element than its operand.
*/
private Expr getConvertedResultExpression(Instruction instr, int n) {
// Only fully converted instructions have a result for `asConvertedExpr`
not conversionFlow(unique(Operand op |
// The address operand of a `InitializeDynamicAllocationInstruction` is
// special: we need to handle it during dataflow (since it's
// effectively a store to an indirection), but it doesn't appear in
// source syntax, so dataflow node <-> expression conversion shouldn't
// care about it.
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
op
), _, false, false) and
result = getConvertedResultExpressionImpl(instr) and
n = 0
or
// If the conversion also has a result then we return multiple results
exists(Operand operand | conversionFlow(operand, instr, false, false) |
n = 1 and
result = getConvertedResultExpressionImpl(operand.getDef())
or
result = getConvertedResultExpression(operand.getDef(), n - 1)
)
}
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
// IR construction inserts an additional cast to a `size_t` on the extent
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
// a result for `getConvertedResultExpression`. We remap this here so that
// this `ConvertInstruction` maps to the result of the expression that
// represents the extent.
exists(TranslatedNonConstantAllocationSize tas |
result = tas.getExtent().getExpr() and
instr = tas.getInstruction(AllocationExtentConvertTag())
)
or
// There's no instruction that returns `ParenthesisExpr`, but some queries
// expect this
exists(TranslatedTransparentConversion ttc |
result = ttc.getExpr().(ParenthesisExpr) and
instr = ttc.getResult()
)
or
// Certain expressions generate `CopyValueInstruction`s only when they
// are needed. Examples of this include crement operations and compound
// assignment operations. For example:
// ```cpp
// int x = ...
// int y = x++;
// ```
// this generate IR like:
// ```
// r1(glval<int>) = VariableAddress[x] :
// r2(int) = Constant[0] :
// m3(int) = Store[x] : &:r1, r2
// r4(glval<int>) = VariableAddress[y] :
// r5(glval<int>) = VariableAddress[x] :
// r6(int) = Load[x] : &:r5, m3
// r7(int) = Constant[1] :
// r8(int) = Add : r6, r7
// m9(int) = Store[x] : &:r5, r8
// r11(int) = CopyValue : r6
// m12(int) = Store[y] : &:r4, r11
// ```
// When the `CopyValueInstruction` is not generated there is no instruction
// whose `getConvertedResultExpression` maps back to the expression. When
// such an instruction doesn't exist it means that the old value is not
// needed, and in that case the only value that will propagate forward in
// the program is the value that's been updated. So in those cases we just
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
exists(TranslatedCoreExpr tco |
tco.getInstruction(_) = instr and
tco.producesExprResult() and
result = asDefinitionImpl0(instr)
)
}
private Expr getConvertedResultExpressionImpl(Instruction instr) {
result = getConvertedResultExpressionImpl0(instr)
or
not exists(getConvertedResultExpressionImpl0(instr)) and
result = instr.getConvertedResultExpression()
}
/**
* Gets the result for `node.asDefinition()` (when `node` is the instruction
* node that wraps `store`) in the cases where `store.getAst()` should not be
* used to define the result of `node.asDefinition()`.
*/
private Expr asDefinitionImpl0(StoreInstruction store) {
// For an expression such as `i += 2` we pretend that the generated
// `StoreInstruction` contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedAssignOperation tao |
store = tao.getInstruction(AssignmentStoreTag()) and
result = tao.getExpr()
)
or
// Similarly for `i++` and `++i` we pretend that the generated
// `StoreInstruction` is contains the result of the expression even though
// this isn't totally aligned with the C/C++ standard.
exists(TranslatedCrementOperation tco |
store = tco.getInstruction(CrementStoreTag()) and
result = tco.getExpr()
)
}
/**
* Holds if the expression returned by `store.getAst()` should not be
* returned as the result of `node.asDefinition()` when `node` is the
* instruction node that wraps `store`.
*/
private predicate excludeAsDefinitionResult(StoreInstruction store) {
// Exclude the store to the temporary generated by a ternary expression.
exists(TranslatedConditionalExpr tce |
store = tce.getInstruction(ConditionValueFalseStoreTag())
or
store = tce.getInstruction(ConditionValueTrueStoreTag())
)
}
/**
* Gets the expression that represents the result of `StoreInstruction` for
* dataflow purposes.
*
* For example, consider the following example
* ```cpp
* int x = 42; // 1
* x = 34; // 2
* ++x; // 3
* x++; // 4
* x += 1; // 5
* int y = x += 2; // 6
* ```
* For (1) the result is `42`.
* For (2) the result is `x = 34`.
* For (3) the result is `++x`.
* For (4) the result is `x++`.
* For (5) the result is `x += 1`.
* For (6) there are two results:
* - For the `StoreInstruction` generated by `x += 2` the result
* is `x += 2`
* - For the `StoreInstruction` generated by `int y = ...` the result
* is also `x += 2`
*/
cached
Expr asDefinitionImpl(StoreInstruction store) {
not exists(asDefinitionImpl0(store)) and
not excludeAsDefinitionResult(store) and
result = store.getAst().(Expr).getUnconverted()
or
result = asDefinitionImpl0(store)
}
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
not exprNodeShouldBeIndirectOperand(_, e, n) and
exists(Instruction def |
unique( | | getAUse(def)) = node.getOperand() and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
private predicate indirectExprNodeShouldBeIndirectOperand(
IndirectOperand node, Expr e, int n, int indirectionIndex
) {
exists(Instruction def |
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
e = getConvertedResultExpression(def, n)
)
}
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
exists(ArgumentOperand operand |
// When an argument (qualifier or positional) is a prvalue and the
// parameter (qualifier or positional) is a (const) reference, IR
// construction introduces a temporary `IRVariable`. The `VariableAddress`
// instruction has the argument as its `getConvertedResultExpression`
// result. However, the instruction actually represents the _address_ of
// the argument. So to fix this mismatch, we have the indirection of the
// `VariableAddressInstruction` map to the expression.
node.hasOperandAndIndirectionIndex(operand, 1) and
e = getConvertedResultExpression(operand.getDef(), n) and
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
)
}
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
exists(CallInstruction call |
call.getStaticCallTarget() instanceof Constructor and
e = getConvertedResultExpression(call, n) and
call.getThisArgumentOperand() = node.getAddressOperand()
)
}
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
private predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
not exprNodeShouldBeOperand(_, e, n) and
not exprNodeShouldBeIndirectOutNode(_, e, n) and
not exprNodeShouldBeIndirectOperand(_, e, n) and
e = getConvertedResultExpression(node.asInstruction(), n)
}
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
private predicate indirectExprNodeShouldBeIndirectInstruction(
IndirectInstruction node, Expr e, int n, int indirectionIndex
) {
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
exists(Instruction instr |
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
e = getConvertedResultExpression(instr, n)
)
}
abstract private class ExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
}
/**
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
* to `e`.
*/
private predicate exprNodeShouldBe(Expr e, int n) {
exprNodeShouldBeInstruction(_, e, n) or
exprNodeShouldBeOperand(_, e, n) or
exprNodeShouldBeIndirectOutNode(_, e, n) or
exprNodeShouldBeIndirectOperand(_, e, n)
}
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
InstructionExprNode() {
exists(Expr e, int n |
exprNodeShouldBeInstruction(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
}
private class OperandExprNode extends ExprNodeBase, OperandNode {
OperandExprNode() {
exists(Expr e, int n |
exprNodeShouldBeOperand(this, e, n) and
not exists(Expr conv |
exprNodeShouldBe(conv, n + 1) and
conv.getUnconverted() = e.getUnconverted()
)
)
}
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
}
abstract private class IndirectExprNodeBase extends Node {
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
abstract Expr getConvertedExpr(int n, int indirectionIndex);
/** Gets the non-conversion expression corresponding to this node, if any. */
final Expr getExpr(int n, int indirectionIndex) {
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
}
}
/** A signature for converting an indirect node to an expression. */
private signature module IndirectNodeToIndirectExprSig {
/** The indirect node class to be converted to an expression */
class IndirectNode;
/**
* Holds if the indirect expression at indirection index `indirectionIndex`
* of `node` is `e`. The integer `n` specifies how many conversions has been
* applied to `node`.
*/
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
}
/**
* A module that implements the logic for deciding whether an indirect node
* should be an `IndirectExprNode`.
*/
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
import Sig
/**
* This predicate shifts the indirection index by one when `conv` is a
* `ReferenceDereferenceExpr`.
*
* This is necessary because `ReferenceDereferenceExpr` is a conversion
* in the AST, but appears as a `LoadInstruction` in the IR.
*/
bindingset[e, indirectionIndex]
private predicate adjustForReference(
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
) {
conv.(ReferenceDereferenceExpr).getExpr() = e and
adjustedIndirectionIndex = indirectionIndex - 1
or
not conv instanceof ReferenceDereferenceExpr and
conv = e and
adjustedIndirectionIndex = indirectionIndex
}
/** Holds if `node` should be an `IndirectExprNode`. */
predicate charpred(IndirectNode node) {
exists(Expr e, int n, int indirectionIndex |
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
not exists(Expr conv, int adjustedIndirectionIndex |
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
)
)
}
}
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
}
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectOperand;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
}
module IndirectOperandToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
{
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
class IndirectNode = IndirectInstruction;
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
}
module IndirectInstructionToIndirectExpr =
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
{
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
final override Expr getConvertedExpr(int n, int index) {
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
}
}
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
}
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
}
/**
* An expression, viewed as a node in a data flow graph.
*/
cached
class ExprNode extends Node instanceof ExprNodeBase {
/**
* INTERNAL: Do not use.
*/
cached
Expr getExpr(int n) { result = super.getExpr(n) }
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
cached
final Expr getExpr() { result = this.getExpr(_) }
/**
* INTERNAL: Do not use.
*/
cached
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
cached
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
}
/**
* An indirect expression, viewed as a node in a data flow graph.
*/
cached
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
/**
* Gets the non-conversion expression corresponding to this node, if any. If
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
* expression.
*/
cached
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
cached
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
/**
* INTERNAL: Do not use.
*/
cached
Expr getConvertedExpr(int n, int indirectionIndex) {
result = super.getConvertedExpr(n, indirectionIndex)
}
/**
* Gets the expression corresponding to this node, if any. The returned
* expression may be a `Conversion`.
*/
cached
Expr getConvertedExpr(int indirectionIndex) {
result = this.getConvertedExpr(_, indirectionIndex)
}
}
}
import Cached

View File

@@ -1,3 +1,13 @@
## 1.0.2
No user-facing changes.
## 1.0.1
### Minor Analysis Improvements
* The `cpp/dangerous-function-overflow` no longer produces a false positive alert when the `gets` function does not have exactly one parameter.
## 1.0.0
### Breaking Changes

View File

@@ -1,4 +1,5 @@
---
category: minorAnalysis
---
## 1.0.1
### Minor Analysis Improvements
* The `cpp/dangerous-function-overflow` no longer produces a false positive alert when the `gets` function does not have exactly one parameter.

View File

@@ -0,0 +1,3 @@
## 1.0.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.0
lastReleaseVersion: 1.0.2

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.0.1-dev
version: 1.0.3-dev
groups:
- cpp
- queries

View File

@@ -74,6 +74,8 @@ astGuardsCompare
| 34 | j >= 10+0 when ... < ... is false |
| 42 | 10 < j+1 when ... < ... is false |
| 42 | 10 >= j+1 when ... < ... is true |
| 42 | call to getABool != 0 when call to getABool is true |
| 42 | call to getABool == 0 when call to getABool is false |
| 42 | j < 10+0 when ... < ... is true |
| 42 | j >= 10+0 when ... < ... is false |
| 44 | 0 < z+0 when ... > ... is true |
@@ -537,6 +539,8 @@ astGuardsEnsure_const
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
irGuards
| test.c:7:9:7:13 | CompareGT: ... > ... |
| test.c:17:8:17:12 | CompareLT: ... < ... |
@@ -613,6 +617,8 @@ irGuardsCompare
| 34 | j >= 10+0 when CompareLT: ... < ... is false |
| 42 | 10 < j+1 when CompareLT: ... < ... is false |
| 42 | 10 >= j+1 when CompareLT: ... < ... is true |
| 42 | call to getABool != 0 when Call: call to getABool is true |
| 42 | call to getABool == 0 when Call: call to getABool is false |
| 42 | j < 10 when CompareLT: ... < ... is true |
| 42 | j < 10+0 when CompareLT: ... < ... is true |
| 42 | j >= 10 when CompareLT: ... < ... is false |
@@ -1081,3 +1087,5 @@ irGuardsEnsure_const
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 32 | 32 |
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | != | 0 | 44 | 44 |
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | == | 0 | 53 | 53 |

View File

@@ -42,3 +42,6 @@
| test.cpp:99:6:99:6 | f |
| test.cpp:105:6:105:14 | ... != ... |
| test.cpp:111:6:111:14 | ... != ... |
| test.cpp:122:9:122:9 | b |
| test.cpp:125:13:125:20 | ! ... |
| test.cpp:125:14:125:17 | call to safe |

View File

@@ -44,6 +44,8 @@
| 34 | j >= 10+0 when ... < ... is false |
| 42 | 10 < j+1 when ... < ... is false |
| 42 | 10 >= j+1 when ... < ... is true |
| 42 | call to getABool != 0 when call to getABool is true |
| 42 | call to getABool == 0 when call to getABool is false |
| 42 | j < 10 when ... < ... is true |
| 42 | j < 10+0 when ... < ... is true |
| 42 | j >= 10 when ... < ... is false |
@@ -149,6 +151,13 @@
| 111 | 0.0 == i+0 when ... != ... is false |
| 111 | i != 0.0+0 when ... != ... is true |
| 111 | i == 0.0+0 when ... != ... is false |
| 122 | b != 0 when b is true |
| 122 | b == 0 when b is false |
| 125 | ! ... != 0 when ! ... is true |
| 125 | ! ... == 0 when ! ... is false |
| 125 | call to safe != 0 when ! ... is false |
| 125 | call to safe != 0 when call to safe is true |
| 125 | call to safe == 0 when call to safe is false |
| 126 | 1 != 0 when 1 is true |
| 126 | 1 != 0 when ... && ... is true |
| 126 | 1 == 0 when 1 is false |

View File

@@ -100,3 +100,7 @@
| test.cpp:99:6:99:6 | f | true | 99 | 100 |
| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
| test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 |
| test.cpp:122:9:122:9 | b | true | 123 | 125 |
| test.cpp:122:9:122:9 | b | true | 125 | 125 |
| test.cpp:125:13:125:20 | ! ... | true | 125 | 125 |
| test.cpp:125:14:125:17 | call to safe | false | 125 | 125 |

View File

@@ -257,6 +257,8 @@ unary
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 0 | 62 | 64 |
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 1 | 65 | 66 |
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | < | 11 | 75 | 77 |
@@ -264,3 +266,7 @@ unary
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 0 | 75 | 77 |
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 11 | 78 | 79 |
| test.cpp:93:6:93:6 | c | test.cpp:93:6:93:6 | c | != | 0 | 93 | 94 |
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 123 | 125 |
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 125 | 125 |
| test.cpp:125:13:125:20 | ! ... | test.cpp:125:13:125:20 | ! ... | != | 0 | 125 | 125 |
| test.cpp:125:14:125:17 | call to safe | test.cpp:125:14:125:17 | call to safe | == | 0 | 125 | 125 |

View File

@@ -112,3 +112,17 @@ void int_float_comparison(int i) {
use(i);
}
}
int source();
bool safe(int);
void test(bool b)
{
int x;
if (b)
{
x = source();
if (!safe(x)) return;
}
use(x);
}

View File

@@ -83,7 +83,7 @@ void test_guard_and_reassign() {
if(!guarded(x)) {
x = 0;
}
sink(x); // $ SPURIOUS: ast,ir
sink(x); // $ SPURIOUS: ast
}
void test_phi_read_guard(bool b) {
@@ -98,7 +98,7 @@ void test_phi_read_guard(bool b) {
return;
}
sink(x); // $ SPURIOUS: ast,ir
sink(x); // $ SPURIOUS: ast
}
bool unsafe(int);

View File

@@ -7,14 +7,17 @@ module AstTest {
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
g.(FunctionCall).getTarget().getName() = "guarded" and
checked = g.(FunctionCall).getArgument(0) and
isTrue = true
or
g.(FunctionCall).getTarget().getName() = "unsafe" and
checked = g.(FunctionCall).getArgument(0) and
isTrue = false
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean branch) {
exists(Call call, boolean b |
checked = call.getArgument(0) and
g.comparesEq(call, 0, b, any(BooleanValue bv | bv.getValue() = branch))
|
call.getTarget().hasName("guarded") and
b = false
or
call.getTarget().hasName("unsafe") and
b = true
)
}
/** Common data flow configuration to be used by tests. */
@@ -106,16 +109,16 @@ module IRTest {
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
exists(Call call |
call = g.getUnconvertedResultExpression() and
checked = call.getArgument(0)
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean branch) {
exists(CallInstruction call, boolean b |
checked = call.getArgument(0).getUnconvertedResultExpression() and
g.comparesEq(call.getAUse(), 0, b, any(BooleanValue bv | bv.getValue() = branch))
|
call.getTarget().hasName("guarded") and
isTrue = true
call.getStaticCallTarget().hasName("guarded") and
b = false
or
call.getTarget().hasName("unsafe") and
isTrue = false
call.getStaticCallTarget().hasName("unsafe") and
b = true
)
}

View File

@@ -145,8 +145,6 @@ irFlow
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
| BarrierGuard.cpp:81:11:81:16 | call to source | BarrierGuard.cpp:86:8:86:8 | x |
| BarrierGuard.cpp:90:11:90:16 | call to source | BarrierGuard.cpp:101:8:101:8 | x |
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | *& ... |

View File

@@ -7,10 +7,11 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Company>GitHub</Company>
<Product>CodeQL</Product>
<Copyright>Copyright © $([System.DateTime]::Now.Year) $(Company)</Copyright>
<Version>1.0.0.0</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
</PropertyGroup>
</Project>

View File

@@ -7,7 +7,6 @@ codeql_xunit_test(
name = "Semmle.Autobuild.CSharp.Tests",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
deps = [
"//csharp/autobuilder/Semmle.Autobuild.CSharp:bin/Semmle.Autobuild.CSharp",

View File

@@ -7,7 +7,6 @@ codeql_csharp_binary(
name = "Semmle.Autobuild.CSharp",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
visibility = ["//csharp:__subpackages__"],
deps = [

View File

@@ -7,7 +7,6 @@ codeql_xunit_test(
name = "Semmle.Autobuild.Cpp.Tests",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
deps = [
"//csharp/autobuilder/Semmle.Autobuild.Cpp:bin/Semmle.Autobuild.Cpp",

View File

@@ -7,7 +7,6 @@ codeql_csharp_binary(
name = "Semmle.Autobuild.Cpp",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
visibility = ["//visibility:public"],
deps = [

View File

@@ -7,7 +7,6 @@ codeql_csharp_library(
name = "Semmle.Autobuild.Shared",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
visibility = ["//visibility:public"],
deps = [

View File

@@ -7,7 +7,6 @@ codeql_csharp_library(
name = "Semmle.Extraction.CSharp.DependencyFetching",
srcs = glob([
"*.cs",
"Properties/*.cs",
"SourceGenerators/**/*.cs",
]),
allow_unsafe_blocks = True,

View File

@@ -1,4 +0,0 @@
using System.Runtime.CompilerServices;
// Expose internals for testing purposes.
[assembly: InternalsVisibleTo("Semmle.Extraction.Tests")]

View File

@@ -6,6 +6,8 @@
<ItemGroup>
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
<InternalsVisibleTo Include="Semmle.Extraction.Tests" />
</ItemGroup>
<Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>

View File

@@ -7,7 +7,6 @@ codeql_csharp_binary(
name = "Semmle.Extraction.CSharp.DependencyStubGenerator",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
visibility = ["//csharp:__pkg__"],
deps = [

View File

@@ -7,7 +7,6 @@ codeql_csharp_binary(
name = "Semmle.Extraction.CSharp.Driver",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
visibility = ["//csharp:__pkg__"],
deps = [

View File

@@ -7,7 +7,6 @@ codeql_csharp_binary(
name = "Semmle.Extraction.CSharp.Standalone",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
visibility = ["//csharp:__subpackages__"],
deps = [

View File

@@ -7,7 +7,6 @@ codeql_csharp_library(
name = "Semmle.Extraction.CSharp.StubGenerator",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
internals_visible_to = ["Semmle.Extraction.Tests"],
visibility = ["//csharp:__subpackages__"],

View File

@@ -1,4 +0,0 @@
using System.Runtime.CompilerServices;
// Expose internals for testing purposes.
[assembly: InternalsVisibleTo("Semmle.Extraction.Tests")]

View File

@@ -4,6 +4,8 @@
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
<ProjectReference Include="..\Semmle.Extraction.CSharp.DependencyFetching\Semmle.Extraction.CSharp.DependencyFetching.csproj" />
<ProjectReference Include="..\Semmle.Extraction.CSharp.Util\Semmle.Extraction.CSharp.Util.csproj" />
<InternalsVisibleTo Include="Semmle.Extraction.Tests" />
</ItemGroup>
<Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>

View File

@@ -6,7 +6,6 @@ load(
codeql_csharp_library(
name = "Semmle.Extraction.CSharp.Util",
srcs = glob([
"Properties/*.cs",
"*.cs",
]),
visibility = ["//csharp:__subpackages__"],

View File

@@ -7,7 +7,6 @@ codeql_xunit_test(
name = "Semmle.Extraction.Tests",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
deps = [
"//csharp/extractor/Semmle.Extraction",

View File

@@ -15,7 +15,6 @@ codeql_csharp_library(
srcs = glob([
"Entities/**/*.cs",
"Extractor/**/*.cs",
"Properties/*.cs",
"*.cs",
]),
# enable via -c dbg on the bazel command line/in .bazelrc.local

View File

@@ -7,7 +7,6 @@ codeql_xunit_test(
name = "Semmle.Util.Tests",
srcs = glob([
"*.cs",
"Properties/*.cs",
]),
deps = [
"//csharp/extractor/Semmle.Util",

View File

@@ -9,7 +9,6 @@ codeql_csharp_library(
"Logging/**/*.cs",
"ToolStatusPage/**/*.cs",
"*.cs",
"Properties/*.cs",
]),
visibility = ["//visibility:public"],
deps = [

View File

@@ -1,3 +1,11 @@
## 1.7.19
No user-facing changes.
## 1.7.18
No user-facing changes.
## 1.7.17
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.18
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.19
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.17
lastReleaseVersion: 1.7.19

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.7.18-dev
version: 1.7.20-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,11 @@
## 1.7.19
No user-facing changes.
## 1.7.18
No user-facing changes.
## 1.7.17
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.18
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.19
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.17
lastReleaseVersion: 1.7.19

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.7.18-dev
version: 1.7.20-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,11 @@
## 1.0.2
No user-facing changes.
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes

View File

@@ -0,0 +1,3 @@
## 1.0.1
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.0
lastReleaseVersion: 1.0.2

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all
version: 1.0.1-dev
version: 1.0.3-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp

View File

@@ -1,3 +1,13 @@
## 1.0.2
No user-facing changes.
## 1.0.1
### Minor Analysis Improvements
* .NET 8 Runtime models have been updated based on the newest version of the model generator. Furthermore, the database sources have been changed slightly to reduce result multiplicity.
## 1.0.0
### Breaking Changes

View File

@@ -1,4 +1,5 @@
---
category: minorAnalysis
---
## 1.0.1
### Minor Analysis Improvements
* .NET 8 Runtime models have been updated based on the newest version of the model generator. Furthermore, the database sources have been changed slightly to reduce result multiplicity.

View File

@@ -0,0 +1,3 @@
## 1.0.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.0
lastReleaseVersion: 1.0.2

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries
version: 1.0.1-dev
version: 1.0.3-dev
groups:
- csharp
- queries

View File

@@ -21,7 +21,14 @@ output_file = pathlib.Path(opts.output)
output_file_contents = f"""
using System.Reflection;
[assembly: XX("{opts.name}")]
[assembly: YY("ZZ")]
[assembly: AssemblyTitle("{opts.name}")]
[assembly: AssemblyProduct("CodeQL")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyCompany("GitHub")]
[assembly: AssemblyCopyright("Copyright © 2024 GitHub")]
[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]
"""
output_file.write_text(output_file_contents)

View File

@@ -23,6 +23,8 @@ for file in map(pathlib.Path, opts.gitinfo_files):
gitfiles[file.name] = file
version_string = gitfiles["git-ql-describe-all.log"].read_text().strip()
if version_string == "no-git":
version_string = gitfiles["git-describe-all.log"].read_text().strip()
version_string += f" ({gitfiles['git-ql-rev-parse.log'].read_text().strip()})"
output_file = pathlib.Path(opts.output)

View File

@@ -19,7 +19,10 @@ CodeQL 2.17.4 runs a total of 414 security queries when configured with the Defa
CodeQL CLI
----------
There are no user-facing CLI changes in this release.
New Features
~~~~~~~~~~~~
* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0.
Query Packs
-----------

View File

@@ -0,0 +1,127 @@
.. _codeql-cli-2.17.5:
==========================
CodeQL 2.17.5 (2024-06-12)
==========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: none
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/code-scanning/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
Security Coverage
-----------------
CodeQL 2.17.5 runs a total of 414 security queries when configured with the Default suite (covering 161 CWE). The Extended suite enables an additional 131 queries (covering 35 more CWE).
CodeQL CLI
----------
Breaking Changes
~~~~~~~~~~~~~~~~
* All the commands that output SARIF will output a minified version to reduce the size.
The :code:`codeql database analyze`, :code:`codeql database interpret-results`, :code:`codeql generate query-help`, and :code:`codeql bqrs interpret` commands support the option :code:`--no-sarif-minify` to output a pretty printed SARIF file.
* A number of breaking changes have been made to the :code:`semmle-extractor-options` functionality available for C and C++ CodeQL tests.
* The Arm, Intel, and CodeWarrior compilers are no longer supported and the
:code:`--armcc`, :code:`--intel`, :code:`--codewarrior` flags are now ignored, as are all the flags that only applied to those compilers.
* The :code:`--threads` and :code:`-main-file-name` options, which did not have any effect on tests, are now ignored. Any specification of these options as part of
:code:`semmle-extractor-options` should be removed.
* Support for :code:`--linker`, all flags that would only invoke the preprocessor,
and the :code:`/clr` flag have been removed, as those flags would never produce any usable test output.
* Support for the :code:`--include_path_environment` flag has been removed. All include paths should directly be specified as part of :code:`semmle-extractor-options`.
* Microsoft C/C++ compiler response files specified via :code:`@some_file_name` are now ignored. Instead, all options should directly be specified as part of
:code:`semmle-extractor-options`.
* Support for Microsoft :code:`#import` preprocessor directive has been removed, as support depends on the availability of the Microsoft C/C++ compiler, and availability cannot be guaranteed on all platforms while executing tests.
* Support for the Microsoft :code:`/EHa`, :code:`/EHs`, :code:`/GX`, :code:`/GZ`, :code:`/Tc`, :code:`/Tp`, and :code:`/Zl` flags, and all :code:`/RTC` flags have been removed. Any specification of these options as part of :code:`semmle-extractor-options` should be removed.
* Support for the Apple-specific :code:`-F` and :code:`-iframework` flags has been removed.
The :code:`-F` flag can still be used by replacing :code:`-F <directory>` by
:code:`--edg -F --edg <directory>`. Any occurrence of :code:`-iframework <arg>` should be replaced by :code:`--edg --sys_framework --edg <arg>`.
* Support for the :code:`/TC`, :code:`/TP`, and :code:`-x` flags has been removed. Please ensure all C, respectively C++, source files have a :code:`.c`, respectively :code:`.cpp`,
extension.
* The :code:`--build_error_dir`, :code:`-db`, :code:`--edg_base_dir`, :code:`--error_limit`,
:code:`--src_archive`, :code:`--trapfolder`, and :code:`--variadic_macros` flags are now ignored.
The above changes do not affect the creation of databases through the CodeQL CLI,
or when calling the C/C++ extractor directly with the :code:`--mimic` or :code:`--linker` flags.
Similar functionality continues to be supported in those scenarios, except for CodeWarrior and the :code:`--edg_base_dir`, :code:`--include_path_environment`, :code:`/Tc`, and :code:`/Tp` flags, which were never supported.
Improvements
~~~~~~~~~~~~
* :code:`codeql generate log-summary` now reports completed pipeline runs that are part of an incomplete recursive predicate.
Miscellaneous
~~~~~~~~~~~~~
* The OWASP Java HTML Sanitizer library used by the CodeQL CLI for internal documentation generation commands has been updated to version
\ `20240325.1 <https://github.com/OWASP/java-html-sanitizer/releases/tag/release-20240325.1>`__.
Query Packs
-----------
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* The :code:`cpp/dangerous-function-overflow` no longer produces a false positive alert when the :code:`gets` function does not have exactly one parameter.
C#
""
* .NET 8 Runtime models have been updated based on the newest version of the model generator. Furthermore, the database sources have been changed slightly to reduce result multiplicity.
Java
""""
* The query :code:`java/spring-disabled-csrf-protection` detects disabling CSRF via :code:`ServerHttpSecurity$CsrfSpec::disable`.
* Added more :code:`java.io.File`\ -related sinks to the path injection query.
Python
""""""
* Added models for :code:`opml` library.
Language Libraries
------------------
Major Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Java
""""
* The precision of virtual dispatch has been improved. This increases precision in general for all data flow queries.
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* A partial model for the :code:`Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in :code:`Boost.Asio`, such as :code:`read_until` and :code:`write`.
Java
""""
* Support for Eclipse Compiler for Java (ecj) has been fixed to work with (a) runs that don't pass :code:`-noExit` and (b) runs that use post-Java-9 command-line arguments.
New Features
~~~~~~~~~~~~
C/C++
"""""
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension :code:`.model.yml` files, rather than by writing classes in QL code. New models should be added in the :code:`lib/ext` folder.
Golang
""""""
* When writing models-as-data models, the receiver is now referred to as :code:`Argument[receiver]` rather than :code:`Argument[-1]`.
* Neutral models are now supported. They have no effect except that a manual neutral summary model will stop a generated summary model from having any effect.

View File

@@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here <https://docs.g
.. toctree::
:maxdepth: 1
codeql-cli-2.17.5
codeql-cli-2.17.4
codeql-cli-2.17.3
codeql-cli-2.17.2

View File

@@ -1,3 +1,11 @@
## 1.0.2
No user-facing changes.
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes

View File

@@ -0,0 +1,3 @@
## 1.0.1
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.0
lastReleaseVersion: 1.0.2

View File

@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries
version: 1.0.1-dev
version: 1.0.3-dev
groups:
- go
- queries

View File

@@ -1,3 +1,14 @@
## 1.1.1
No user-facing changes.
## 1.1.0
### New Features
* When writing models-as-data models, the receiver is now referred to as `Argument[receiver]` rather than `Argument[-1]`.
* Neutral models are now supported. They have no effect except that a manual neutral summary model will stop a generated summary model from having any effect.
## 1.0.0
### Breaking Changes

View File

@@ -1,5 +1,6 @@
---
category: feature
---
## 1.1.0
### New Features
* When writing models-as-data models, the receiver is now referred to as `Argument[receiver]` rather than `Argument[-1]`.
* Neutral models are now supported. They have no effect except that a manual neutral summary model will stop a generated summary model from having any effect.

View File

@@ -0,0 +1,3 @@
## 1.1.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.0
lastReleaseVersion: 1.1.1

View File

@@ -1,5 +1,5 @@
name: codeql/go-all
version: 1.0.1-dev
version: 1.1.2-dev
groups: go
dbscheme: go.dbscheme
extractor: go

View File

@@ -1,3 +1,11 @@
## 1.0.2
No user-facing changes.
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes

View File

@@ -0,0 +1,3 @@
## 1.0.1
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.0
lastReleaseVersion: 1.0.2

View File

@@ -1,5 +1,5 @@
name: codeql/go-queries
version: 1.0.1-dev
version: 1.0.3-dev
groups:
- go
- queries

View File

@@ -1,3 +1,11 @@
## 1.0.2
No user-facing changes.
## 1.0.1
No user-facing changes.
## 1.0.0
### Breaking Changes

View File

@@ -0,0 +1,3 @@
## 1.0.1
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.0
lastReleaseVersion: 1.0.2

View File

@@ -1,5 +1,5 @@
name: codeql/java-automodel-queries
version: 1.0.1-dev
version: 1.0.3-dev
groups:
- java
- automodel

View File

@@ -1,5 +1,5 @@
{
"markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [supply credentials for any private dependencies](https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows).\n\nRelevant output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`",
"markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [supply credentials for any private dependencies](https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows).\n\n",
"severity": "error",
"source": {
"extractorName": "java",

View File

@@ -1,6 +1,7 @@
import os
import pathlib
import shutil
import re
from create_database_utils import *
from diagnostics_test_utils import *
@@ -13,4 +14,5 @@ except FileNotFoundError:
run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None)
check_diagnostics()
# Drop the specific output line here because it varies from version to version of Maven.
check_diagnostics(replacements = {"Relevant output line: [^\"]*": ""})

View File

@@ -1,3 +1,17 @@
{
"markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [supply credentials for any private dependencies](https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows).\n\nRelevant output line: `Caused by: org.apache.maven.project.DependencyResolutionException: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11`",
"severity": "error",
"source": {
"extractorName": "java",
"id": "java/autobuilder/dependency-download-failure",
"name": "Failed to download a dependency"
},
"visibility": {
"cliSummaryTable": false,
"statusPage": false,
"telemetry": true
}
}
{
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked).\n\nRelevant output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
"severity": "error",

View File

@@ -1,3 +1,17 @@
## 1.1.1
No user-facing changes.
## 1.1.0
### Major Analysis Improvements
* The precision of virtual dispatch has been improved. This increases precision in general for all data flow queries.
### Minor Analysis Improvements
* Support for Eclipse Compiler for Java (ecj) has been fixed to work with (a) runs that don't pass `-noExit` and (b) runs that use post-Java-9 command-line arguments.
## 1.0.0
### Breaking Changes

View File

@@ -1,4 +0,0 @@
---
category: majorAnalysis
---
* The precision of virtual dispatch has been improved. This increases precision in general for all data flow queries.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Support for Eclipse Compiler for Java (ecj) has been fixed to work with (a) runs that don't pass `-noExit` and (b) runs that use post-Java-9 command-line arguments.

View File

@@ -0,0 +1,9 @@
## 1.1.0
### Major Analysis Improvements
* The precision of virtual dispatch has been improved. This increases precision in general for all data flow queries.
### Minor Analysis Improvements
* Support for Eclipse Compiler for Java (ecj) has been fixed to work with (a) runs that don't pass `-noExit` and (b) runs that use post-Java-9 command-line arguments.

View File

@@ -0,0 +1,3 @@
## 1.1.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.0
lastReleaseVersion: 1.1.1

View File

@@ -1,5 +1,5 @@
name: codeql/java-all
version: 1.0.1-dev
version: 1.1.2-dev
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java

View File

@@ -1,3 +1,14 @@
## 1.0.2
No user-facing changes.
## 1.0.1
### Minor Analysis Improvements
* The query `java/spring-disabled-csrf-protection` detects disabling CSRF via `ServerHttpSecurity$CsrfSpec::disable`.
* Added more `java.io.File`-related sinks to the path injection query.
## 1.0.0
### Breaking Changes

Some files were not shown because too many files have changed in this diff Show More