Skip to content

Commit 0f56e40

Browse files
authored
Merge branch 'main' into mbg/go/fix/build-scripts-running-more-than-once
2 parents e7a60b7 + cf4736c commit 0f56e40

File tree

243 files changed

+3434
-10676
lines changed

Some content is hidden

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

243 files changed

+3434
-10676
lines changed

.bazelversion

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7.1.2
1+
7.2.0

MODULE.bazel

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,45 @@ local_path_override(
1313

1414
# see https://registry.bazel.build/ for a list of available packages
1515

16-
bazel_dep(name = "platforms", version = "0.0.9")
17-
bazel_dep(name = "rules_go", version = "0.47.0")
16+
bazel_dep(name = "platforms", version = "0.0.10")
17+
bazel_dep(name = "rules_go", version = "0.48.0")
1818
bazel_dep(name = "rules_pkg", version = "0.10.1")
19-
bazel_dep(name = "rules_nodejs", version = "6.0.3")
20-
bazel_dep(name = "rules_python", version = "0.31.0")
21-
bazel_dep(name = "bazel_skylib", version = "1.5.0")
19+
bazel_dep(name = "rules_nodejs", version = "6.2.0")
20+
bazel_dep(name = "rules_python", version = "0.32.2")
21+
bazel_dep(name = "bazel_skylib", version = "1.6.1")
2222
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
2323
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
2424
bazel_dep(name = "fmt", version = "10.0.0")
2525
bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
26-
bazel_dep(name = "gazelle", version = "0.36.0")
26+
bazel_dep(name = "gazelle", version = "0.37.0")
2727
bazel_dep(name = "rules_dotnet", version = "0.15.1")
2828
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
29+
bazel_dep(name = "rules_rust", version = "0.46.0")
2930

3031
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
3132

33+
crate = use_extension(
34+
"@rules_rust//crate_universe:extension.bzl",
35+
"crate",
36+
)
37+
crate.from_cargo(
38+
name = "py_deps",
39+
cargo_lockfile = "//python/extractor/tsg-python:Cargo.lock",
40+
manifests = [
41+
"//python/extractor/tsg-python:Cargo.toml",
42+
"//python/extractor/tsg-python/tsp:Cargo.toml",
43+
],
44+
)
45+
crate.from_cargo(
46+
name = "ruby_deps",
47+
cargo_lockfile = "//ruby/extractor:Cargo.lock",
48+
manifests = [
49+
"//ruby/extractor:Cargo.toml",
50+
"//ruby/extractor/codeql-extractor-fake-crate:Cargo.toml",
51+
],
52+
)
53+
use_repo(crate, "py_deps", "ruby_deps")
54+
3255
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
3356
dotnet.toolchain(dotnet_version = "8.0.101")
3457
use_repo(dotnet, "dotnet_toolchains")

cpp/ql/lib/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 1.1.0
2+
3+
### New Features
4+
5+
* 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.
6+
7+
### Minor Analysis Improvements
8+
9+
* 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`.
10+
111
## 1.0.0
212

313
### Breaking Changes

cpp/ql/lib/change-notes/2024-06-14-boost-asio.md

Lines changed: 0 additions & 4 deletions
This file was deleted.

cpp/ql/lib/change-notes/2024-06-14-models-as-data-yml-extensions.md

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The "Guards" library (`semmle.code.cpp.controlflow.Guards`) now also infers guards from calls to the builtin operation `__builtin_expect`. As a result, some queries may produce fewer false positives.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## 1.1.0
2+
3+
### New Features
4+
5+
* 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.
6+
7+
### Minor Analysis Improvements
8+
9+
* 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`.

cpp/ql/lib/codeql-pack.release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
lastReleaseVersion: 1.0.0
2+
lastReleaseVersion: 1.1.0

cpp/ql/lib/qlpack.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: codeql/cpp-all
2-
version: 1.0.1-dev
2+
version: 1.1.1-dev
33
groups: cpp
44
dbscheme: semmlecode.cpp.dbscheme
55
extractor: cpp

cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll

Lines changed: 133 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,33 @@ cached
375375
class IRGuardCondition extends Instruction {
376376
Instruction branch;
377377

378+
/*
379+
* An `IRGuardCondition` supports reasoning about four different kinds of
380+
* relations:
381+
* 1. A unary equality relation of the form `e == k`
382+
* 2. A binary equality relation of the form `e1 == e2 + k`
383+
* 3. A unary inequality relation of the form `e < k`
384+
* 4. A binary inequality relation of the form `e1 < e2 + k`
385+
*
386+
* where `k` is a constant.
387+
*
388+
* Furthermore, the unary relations (i.e., case 1 and case 3) are also
389+
* inferred from `switch` statement guards: equality relations are inferred
390+
* from the unique `case` statement, if any, and inequality relations are
391+
* inferred from the [case range](https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html)
392+
* gcc extension.
393+
*
394+
* The implementation of all four follows the same structure: Each relation
395+
* has a cached user-facing predicate that. For example,
396+
* `GuardCondition::comparesEq` calls `compares_eq`. This predicate has
397+
* several cases that recursively decompose the relation to bring it to a
398+
* canonical form (i.e., a relation of the form `e1 == e2 + k`). The base
399+
* case for this relation (i.e., `simple_comparison_eq`) handles
400+
* `CompareEQInstruction`s and `CompareNEInstruction`, and recursive
401+
* predicates (e.g., `complex_eq`) rewrites larger expressions such as
402+
* `e1 + k1 == e2 + k2` into canonical the form `e1 == e2 + (k2 - k1)`.
403+
*/
404+
378405
cached
379406
IRGuardCondition() { branch = getBranchForCondition(this) }
380407

@@ -735,6 +762,8 @@ private predicate compares_eq(
735762
exists(AbstractValue dual | value = dual.getDualValue() |
736763
compares_eq(test.(LogicalNotInstruction).getUnary(), left, right, k, areEqual, dual)
737764
)
765+
or
766+
compares_eq(test.(BuiltinExpectCallInstruction).getCondition(), left, right, k, areEqual, value)
738767
}
739768

740769
/**
@@ -776,7 +805,9 @@ private predicate unary_compares_eq(
776805
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
777806
) {
778807
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
779-
exists(AbstractValue v | unary_simple_comparison_eq(test, op, k, inNonZeroCase, v) |
808+
exists(AbstractValue v |
809+
unary_simple_comparison_eq(test, k, inNonZeroCase, v) and op.getDef() = test
810+
|
780811
areEqual = true and value = v
781812
or
782813
areEqual = false and value = v.getDualValue()
@@ -802,6 +833,9 @@ private predicate unary_compares_eq(
802833
int_value(const) = k1 and
803834
k = k1 + k2
804835
)
836+
or
837+
unary_compares_eq(test.(BuiltinExpectCallInstruction).getCondition(), op, k, areEqual,
838+
inNonZeroCase, value)
805839
}
806840

807841
/** Rearrange various simple comparisons into `left == right + k` form. */
@@ -821,45 +855,55 @@ private predicate simple_comparison_eq(
821855
value.(BooleanValue).getValue() = false
822856
}
823857

824-
/**
825-
* Holds if `test` is an instruction that is part of test that eventually is
826-
* used in a conditional branch.
827-
*/
828-
private predicate relevantUnaryComparison(Instruction test) {
829-
not test instanceof CompareInstruction and
830-
exists(IRType type, ConditionalBranchInstruction branch |
831-
type instanceof IRAddressType or type instanceof IRIntegerType
832-
|
833-
type = test.getResultIRType() and
834-
branch.getCondition() = test
835-
)
836-
or
837-
exists(LogicalNotInstruction logicalNot |
838-
relevantUnaryComparison(logicalNot) and
839-
test = logicalNot.getUnary()
840-
)
841-
}
842-
843858
/**
844859
* Rearrange various simple comparisons into `op == k` form.
845860
*/
846861
private predicate unary_simple_comparison_eq(
847-
Instruction test, Operand op, int k, boolean inNonZeroCase, AbstractValue value
862+
Instruction test, int k, boolean inNonZeroCase, AbstractValue value
848863
) {
849864
exists(SwitchInstruction switch, CaseEdge case |
850865
test = switch.getExpression() and
851-
op.getDef() = test and
852866
case = value.(MatchValue).getCase() and
853867
exists(switch.getSuccessor(case)) and
854868
case.getValue().toInt() = k and
855869
inNonZeroCase = false
856870
)
857871
or
858-
// There's no implicit CompareInstruction in files compiled as C since C
859-
// doesn't have implicit boolean conversions. So instead we check whether
860-
// there's a branch on a value of pointer or integer type.
861-
relevantUnaryComparison(test) and
862-
op.getDef() = test and
872+
// Any instruction with an integral type could potentially be part of a
873+
// check for nullness when used in a guard. So we include all integral
874+
// typed instructions here. However, since some of these instructions are
875+
// already included as guards in other cases, we exclude those here.
876+
// These are instructions that compute a binary equality or inequality
877+
// relation. For example, the following:
878+
// ```cpp
879+
// if(a == b + 42) { ... }
880+
// ```
881+
// generates the following IR:
882+
// ```
883+
// r1(glval<int>) = VariableAddress[a] :
884+
// r2(int) = Load[a] : &:r1, m1
885+
// r3(glval<int>) = VariableAddress[b] :
886+
// r4(int) = Load[b] : &:r3, m2
887+
// r5(int) = Constant[42] :
888+
// r6(int) = Add : r4, r5
889+
// r7(bool) = CompareEQ : r2, r6
890+
// v1(void) = ConditionalBranch : r7
891+
// ```
892+
// and since `r7` is an integral typed instruction this predicate could
893+
// include a case for when `r7` evaluates to true (in which case we would
894+
// infer that `r6` was non-zero, and a case for when `r7` evaluates to false
895+
// (in which case we would infer that `r6` was zero).
896+
// However, since `a == b + 42` is already supported when reasoning about
897+
// binary equalities we exclude those cases here.
898+
not test.isGLValue() and
899+
not simple_comparison_eq(test, _, _, _, _) and
900+
not simple_comparison_lt(test, _, _, _) and
901+
not test = any(SwitchInstruction switch).getExpression() and
902+
(
903+
test.getResultIRType() instanceof IRAddressType or
904+
test.getResultIRType() instanceof IRIntegerType or
905+
test.getResultIRType() instanceof IRBooleanType
906+
) and
863907
(
864908
k = 1 and
865909
value.(BooleanValue).getValue() = true and
@@ -871,12 +915,68 @@ private predicate unary_simple_comparison_eq(
871915
)
872916
}
873917

918+
/** A call to the builtin operation `__builtin_expect`. */
919+
private class BuiltinExpectCallInstruction extends CallInstruction {
920+
BuiltinExpectCallInstruction() { this.getStaticCallTarget().hasName("__builtin_expect") }
921+
922+
/** Gets the condition of this call. */
923+
Instruction getCondition() {
924+
// The first parameter of `__builtin_expect` has type `long`. So we skip
925+
// the conversion when inferring guards.
926+
result = this.getArgument(0).(ConvertInstruction).getUnary()
927+
}
928+
}
929+
930+
/**
931+
* Holds if `left == right + k` is `areEqual` if `cmp` evaluates to `value`,
932+
* and `cmp` is an instruction that compares the value of
933+
* `__builtin_expect(left == right + k, _)` to `0`.
934+
*/
935+
private predicate builtin_expect_eq(
936+
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
937+
) {
938+
exists(BuiltinExpectCallInstruction call, Instruction const, AbstractValue innerValue |
939+
int_value(const) = 0 and
940+
cmp.hasOperands(call.getAUse(), const.getAUse()) and
941+
compares_eq(call.getCondition(), left, right, k, areEqual, innerValue)
942+
|
943+
cmp instanceof CompareNEInstruction and
944+
value = innerValue
945+
or
946+
cmp instanceof CompareEQInstruction and
947+
value.getDualValue() = innerValue
948+
)
949+
}
950+
874951
private predicate complex_eq(
875952
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
876953
) {
877954
sub_eq(cmp, left, right, k, areEqual, value)
878955
or
879956
add_eq(cmp, left, right, k, areEqual, value)
957+
or
958+
builtin_expect_eq(cmp, left, right, k, areEqual, value)
959+
}
960+
961+
/**
962+
* Holds if `op == k` is `areEqual` if `cmp` evaluates to `value`, and `cmp` is
963+
* an instruction that compares the value of `__builtin_expect(op == k, _)` to `0`.
964+
*/
965+
private predicate unary_builtin_expect_eq(
966+
CompareInstruction cmp, Operand op, int k, boolean areEqual, boolean inNonZeroCase,
967+
AbstractValue value
968+
) {
969+
exists(BuiltinExpectCallInstruction call, Instruction const, AbstractValue innerValue |
970+
int_value(const) = 0 and
971+
cmp.hasOperands(call.getAUse(), const.getAUse()) and
972+
unary_compares_eq(call.getCondition(), op, k, areEqual, inNonZeroCase, innerValue)
973+
|
974+
cmp instanceof CompareNEInstruction and
975+
value = innerValue
976+
or
977+
cmp instanceof CompareEQInstruction and
978+
value.getDualValue() = innerValue
979+
)
880980
}
881981

882982
private predicate unary_complex_eq(
@@ -885,6 +985,8 @@ private predicate unary_complex_eq(
885985
unary_sub_eq(test, op, k, areEqual, inNonZeroCase, value)
886986
or
887987
unary_add_eq(test, op, k, areEqual, inNonZeroCase, value)
988+
or
989+
unary_builtin_expect_eq(test, op, k, areEqual, inNonZeroCase, value)
888990
}
889991

890992
/*
@@ -913,7 +1015,8 @@ private predicate compares_lt(
9131015

9141016
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
9151017
private predicate compares_lt(Instruction test, Operand op, int k, boolean isLt, AbstractValue value) {
916-
simple_comparison_lt(test, op, k, isLt, value)
1018+
unary_simple_comparison_lt(test, k, isLt, value) and
1019+
op.getDef() = test
9171020
or
9181021
complex_lt(test, op, k, isLt, value)
9191022
or
@@ -960,12 +1063,11 @@ private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Ope
9601063
}
9611064

9621065
/** Rearrange various simple comparisons into `op < k` form. */
963-
private predicate simple_comparison_lt(
964-
Instruction test, Operand op, int k, boolean isLt, AbstractValue value
1066+
private predicate unary_simple_comparison_lt(
1067+
Instruction test, int k, boolean isLt, AbstractValue value
9651068
) {
9661069
exists(SwitchInstruction switch, CaseEdge case |
9671070
test = switch.getExpression() and
968-
op.getDef() = test and
9691071
case = value.(MatchValue).getCase() and
9701072
exists(switch.getSuccessor(case)) and
9711073
case.getMaxValue() > case.getMinValue()

0 commit comments

Comments
 (0)