Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
9a048c9
Prepare to share PrintGraph.qll with DFG viewer
asgerf Feb 23, 2026
dc2c8f3
Update PrintCfg queries to use new interface
asgerf Feb 23, 2026
2017f84
Add getOrderDisambiguation to signature and use it
asgerf Feb 23, 2026
71f4436
Move PrintGraph to codeql.util
asgerf Feb 23, 2026
aa587c0
Refactor 'getASuccessor' to edges/3
asgerf Feb 23, 2026
61ae276
Add PrintDfg.qll
asgerf Feb 23, 2026
c236ace
Add 'View DFG' queries for JS, Java, Ruby, C#, Rust
asgerf Feb 23, 2026
2698b44
C++: Add simple range analysis test with repeated if-else statements
paldepind Feb 16, 2026
09fb85d
C++: Include the actual number of lower/upper bounds for added contex…
paldepind Feb 16, 2026
0521eb4
C++: Divide nr of bounds between branches for phi nodes
paldepind Feb 16, 2026
0050ed6
C++: Improve clarity in comment
paldepind Feb 20, 2026
dfe4486
C++: Fix typo
paldepind Feb 20, 2026
d2ffb00
C++: Add more tests for modified years with and without leap year che…
bdrodes Feb 6, 2026
e6c5266
C++: Refactor leap year logic for UncheckedLeapYearAfterYearModificat…
bdrodes Feb 6, 2026
9b2161b
C++. Accept test changes. One false positive introduced, and one fals…
bdrodes Feb 6, 2026
84aaafd
C++: Correct false positive. Only TimeConversionFunction that do not …
bdrodes Feb 6, 2026
24c1a61
C++: Accept test changes.
bdrodes Feb 6, 2026
cfd00a6
C++: Add missing DateTime models for PTIME_FIELDS and TIME_FIELDS
bdrodes Feb 6, 2026
59e8c3b
C++: Accept test changes (removing false negative)
bdrodes Feb 6, 2026
04426ae
C++: Add change note.
bdrodes Feb 6, 2026
6d1f5c8
C++: Addressing Copilot PR suggestions.
bdrodes Feb 9, 2026
b6a4b1b
C++: Change log missing .md extension.
bdrodes Feb 9, 2026
2311d2a
C++: Updating comment per PR reveiw suggestions.
bdrodes Feb 12, 2026
7dcd0a4
C++: misc comment clean up per PR suggestions. Unified additional flo…
bdrodes Feb 12, 2026
38d67c6
Update cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearMod…
bdrodes Feb 12, 2026
2fce632
Update cpp/ql/lib/change-notes/2026-02-06-UncheckedLeapYearAfterModif…
bdrodes Feb 12, 2026
9efa4d9
C++ Suggested code clean up.
bdrodes Feb 12, 2026
9c9c157
Update cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearMod…
bdrodes Feb 12, 2026
b8d8611
Update cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearMod…
bdrodes Feb 12, 2026
35b4b75
Apply suggestion from @geoffw0
bdrodes Feb 12, 2026
3b17084
Apply suggestion from @geoffw0
bdrodes Feb 12, 2026
0839f43
Apply suggestion from @geoffw0
bdrodes Feb 12, 2026
f846daf
C++: Removing unnecessary post update node.
bdrodes Feb 12, 2026
ddb116e
Update cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearMod…
bdrodes Feb 17, 2026
ca433e0
Update cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearMod…
bdrodes Feb 17, 2026
cb16d0b
Apply suggestion from @geoffw0
bdrodes Feb 17, 2026
6748a1f
Update cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearMod…
bdrodes Feb 17, 2026
7f1d04b
Update cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearMod…
bdrodes Feb 17, 2026
49c2e09
Apply suggestion from @bdrodes
bdrodes Feb 17, 2026
cab1081
Address more non-ascii characters.
geoffw0 Feb 18, 2026
1cb3b62
C++: Fixing FP in unit tests.
bdrodes Feb 19, 2026
0f3bd28
chore: upgrade Bazel to 9.0.0
redsun82 Feb 5, 2026
2b4afa3
feat: add rules_cc and rules_java module dependencies
redsun82 Feb 5, 2026
46d76f4
feat: add Python 3.12 toolchain registration
redsun82 Feb 5, 2026
f4b9021
feat: add rules_cc to autoload configuration
redsun82 Feb 5, 2026
dd6da08
refactor: migrate Starlark files to explicit rules_cc imports
redsun82 Feb 5, 2026
8bf9f23
refactor: migrate BUILD files to explicit rules_cc imports
redsun82 Feb 5, 2026
05490b9
refactor: migrate BUILD files to explicit rules_java imports
redsun82 Feb 5, 2026
29b0616
refactor: migrate C++ runfiles API from bazel_tools to rules_cc
redsun82 Feb 5, 2026
06a077b
fix: disable Android SDK auto-detection for Bazel 9 compatibility
redsun82 Feb 5, 2026
d4ed4f5
fix: upgrade rules_kotlin to 2.2.2 for Windows compatibility
redsun82 Feb 6, 2026
c584895
fix: sort use_repo alphabetically in rules_kotlin MODULE.bazel
redsun82 Feb 6, 2026
782c05f
address review
redsun82 Feb 11, 2026
5bd670c
Python: Add overlay annotations to AST classes
tausbn Dec 5, 2025
7aea5b6
Python: Fix broken queries
tausbn Dec 5, 2025
d108ce8
Python: Simple dataflow annotations
tausbn Jan 30, 2026
474535b
Python: `LocalSources.qll` annotations
tausbn Jan 30, 2026
c7f4787
Python: `DataFlowPublic.qll` annotations
tausbn Jan 30, 2026
d76b786
Python: `DataFlowPrivate.qll` annotations
tausbn Jan 30, 2026
972b637
Python: `DataFlowDispatch.qll` annotations
tausbn Jan 30, 2026
24e134a
Python: Fix `frameworks/data/warnings.ql`
tausbn Jan 30, 2026
876fe05
Python: Add more `overlay[caller]` to `Flow.qll`
tausbn Feb 2, 2026
b9e8e5a
Python: Fix bad join in `OutgoingRequestCall`
tausbn Feb 3, 2026
2d6dec9
Python: Fix bad join in `missing_imported_module`
tausbn Feb 3, 2026
47c77ef
Python: Fix bad join in `returnStep`
tausbn Feb 16, 2026
16de6a7
Python: Add change note
tausbn Feb 18, 2026
d43969a
Accept MaD sanitizers for queries with MaD sinks
owen-mc Feb 17, 2026
e6fe4bf
Change how sql-injection barriers are accepted
owen-mc Feb 17, 2026
6341535
Improve Mysql2 test
owen-mc Feb 17, 2026
3e83a53
Move Mysql2 flow model to MaD and remove ql sanitizer
owen-mc Feb 17, 2026
0200e12
Reinstate Mysql2 sanitizer in MaD
owen-mc Feb 17, 2026
01a9b61
Improve Sqlite3 test
owen-mc Feb 17, 2026
d7c8b9a
Move SQLite3 flow model to MaD and remove ql sanitizer
owen-mc Feb 17, 2026
b4ec560
Reinstate SQLite3 sanitizer in MaD
owen-mc Feb 17, 2026
fb21533
Remove Shellwords sanitizer in ql
owen-mc Feb 17, 2026
5b3737e
Model flow through Shellwords escape and shellescape
owen-mc Feb 17, 2026
23ac9fc
Add MaD barriers for Shellwords.escape and shellescape
owen-mc Feb 17, 2026
f4cacc3
Reinstate ql model for `String#shellescape`
owen-mc Feb 17, 2026
36848cf
Add change note
owen-mc Feb 17, 2026
1ee2534
Update other test in same folder
owen-mc Feb 18, 2026
8925535
Update taintstep test for models becoming MaD
owen-mc Feb 18, 2026
03e4dfd
Use postprocessing queries for unrelated test
owen-mc Feb 18, 2026
b01efe1
C++: Update expected test results after extractor changes
jketema Jan 8, 2026
b6614c0
fixup JS
asgerf Feb 23, 2026
7b83da4
Update some tests
asgerf Feb 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ build --compilation_mode opt
common --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub

build --repo_env=CC=clang --repo_env=CXX=clang++
# Disable Android SDK auto-detection (we don't use it, and rules_android has Bazel 9 compatibility issues)
build --repo_env=ANDROID_HOME=

# print test output, like sembuild does.
# Set to `errors` if this is too verbose.
Expand All @@ -34,7 +36,7 @@ common --@rules_dotnet//dotnet/settings:strict_deps=false
common --@rules_rust//rust/toolchain/channel=nightly

# Reduce this eventually to empty, once we've fixed all our usages of java, and https://github.com/bazel-contrib/rules_go/issues/4193 is fixed
common --incompatible_autoload_externally="+@rules_java,+@rules_shell"
common --incompatible_autoload_externally="+@rules_cc,+@rules_java,+@rules_shell"

build --java_language_version=17
build --tool_java_language_version=17
Expand Down
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.4.2
9.0.0
19 changes: 15 additions & 4 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ local_path_override(
# see https://registry.bazel.build/ for a list of available packages

bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "rules_go", version = "0.56.1")
bazel_dep(name = "rules_cc", version = "0.2.16")
bazel_dep(name = "rules_go", version = "0.59.0")
bazel_dep(name = "rules_java", version = "9.0.3")
bazel_dep(name = "rules_pkg", version = "1.0.1")
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
bazel_dep(name = "rules_nodejs", version = "6.7.3")
bazel_dep(name = "rules_python", version = "0.40.0")
bazel_dep(name = "rules_shell", version = "0.5.0")
bazel_dep(name = "bazel_skylib", version = "1.8.1")
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
bazel_dep(name = "rules_kotlin", version = "2.2.0-codeql.1")
bazel_dep(name = "gazelle", version = "0.40.0")
bazel_dep(name = "rules_kotlin", version = "2.2.2-codeql.1")
bazel_dep(name = "gazelle", version = "0.47.0")
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "rules_rust", version = "0.68.1.codeql.1")
Expand Down Expand Up @@ -188,6 +190,15 @@ pip.parse(
)
use_repo(pip, "codegen_deps")

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
is_default = True,
python_version = "3.12",
)
use_repo(python, "python_3_12", "python_versions")

register_toolchains("@python_versions//3.12:all")

swift_deps = use_extension("//swift/third_party:load.bzl", "swift_deps")

# following list can be kept in sync with `bazel mod tidy`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
25 changes: 24 additions & 1 deletion cpp/ql/lib/semmle/code/cpp/commons/DateTime.qll
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ class PackedTimeType extends Type {
}
}

private predicate timeType(string typeName) { typeName = ["_SYSTEMTIME", "SYSTEMTIME", "tm"] }
private predicate timeType(string typeName) {
typeName = ["_SYSTEMTIME", "SYSTEMTIME", "tm", "TIME_FIELDS", "_TIME_FIELDS", "PTIME_FIELDS"]
}

/**
* A type that is used to represent times and dates in an 'unpacked' form, that is,
Expand Down Expand Up @@ -95,3 +97,24 @@ class StructTmMonthFieldAccess extends MonthFieldAccess {
class StructTmYearFieldAccess extends YearFieldAccess {
StructTmYearFieldAccess() { this.getTarget().getName() = "tm_year" }
}

/**
* A `DayFieldAccess` for the `TIME_FIELDS` struct.
*/
class TimeFieldsDayFieldAccess extends DayFieldAccess {
TimeFieldsDayFieldAccess() { this.getTarget().getName() = "Day" }
}

/**
* A `MonthFieldAccess` for the `TIME_FIELDS` struct.
*/
class TimeFieldsMonthFieldAccess extends MonthFieldAccess {
TimeFieldsMonthFieldAccess() { this.getTarget().getName() = "Month" }
}

/**
* A `YearFieldAccess` for the `TIME_FIELDS` struct.
*/
class TimeFieldsYearFieldAccess extends YearFieldAccess {
TimeFieldsYearFieldAccess() { this.getTarget().getName() = "Year" }
}
75 changes: 49 additions & 26 deletions cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
Original file line number Diff line number Diff line change
Expand Up @@ -552,34 +552,47 @@ private module BoundsEstimate {
private float nrOfBoundsPhiGuard(RangeSsaDefinition def, StackVariable v) {
// If we have
//
// if (x < c) { e1 }
// e2
// if (x < c) { e1 } else { e2 }
// e3
//
// then `e2` is both a guard phi node (guarded by `x < c`) and a normal
// phi node (control is merged after the `if` statement).
// then `{ e1 }` and `{ e2 }` are both guard phi nodes guarded by `x < c`.
// The range analysis propagates bounds on `x` into both branches, filtered
// by the condition. In this case all lower bounds flow to `{ e1 }` and only
// lower bounds that are smaller than `c` flow to `{ e2 }`.
//
// Assume `x` has `n` bounds. Then `n` bounds are propagated to the guard
// phi node `{ e1 }` and, since `{ e1 }` is input to `e2` as a normal phi
// node, `n` bounds are propagated to `e2`. If we also propagate the `n`
// bounds to `e2` as a guard phi node, then we square the number of
// bounds.
// The largest number of bounds possible for `e3` is the number of bounds on `x` plus
// one. This happens when all bounds flow from `x` to `e1` to `e3` and the
// bound `c` can flow to `e2` to `e3`.
//
// However in practice `x < c` is going to cut down the number of bounds:
// The tracked bounds can't flow to both branches as that would require
// them to simultaneously be greater and smaller than `c`. To approximate
// this better, the contribution from a guard phi node that is also a
// normal phi node is 1.
exists(def.getAPhiInput(v)) and
isGuardPhiWithBound(def, v, _) and
result = 1
or
not exists(def.getAPhiInput(v)) and
// If there's different `access`es, then they refer to the same variable
// with the same lower bounds. Hence adding these guards make no sense (the
// implementation will take the union, but they'll be removed by
// deduplication). Hence we use `max` as an approximation.
result =
max(VariableAccess access | isGuardPhiWithBound(def, v, access) | nrOfBoundsExpr(access))
// We want to optimize our bounds estimate for `e3`, as that is the estimate
// that can continue propagating forward. We don't know how the existing
// bounds will be split between the different branches. That depends on
// whether the range analysis is tracking lower bounds or upper bounds, and
// on the meaning of the condition.
//
// As a heuristic we divide the number of bounds on `x` by 2 to "average"
// the effect of the condition and add 1 to account for the bound from the
// condition itself. This will approximate estimates inside the branches,
// but will give a good estimate after the branches are merged.
//
// This also handles cases such as this one
//
// if (x < c) { e1 }
// e3
//
// where `e3` is both a guard phi node (guarded by `x < c`) and a normal
// phi node (control is merged after the `if` statement). Here half of the
// bounds flow into the branch and then to `e3` as a normal phi node and the
// "other" half flow from the condition to `e3` as a guard phi node.
exists(float varBounds |
// If there's different `access`es, then they refer to the same
// variable with the same lower bounds. Hence adding these guards makes no
// sense (the implementation will take the union, but they'll be removed by
// deduplication). Hence we use `max` as an approximation.
varBounds =
max(VariableAccess access | isGuardPhiWithBound(def, v, access) | nrOfBoundsExpr(access)) and
result = (varBounds + 1) / 2
)
or
def.isPhiNode(v) and
not isGuardPhiWithBound(def, v, _) and
Expand Down Expand Up @@ -2180,6 +2193,16 @@ module SimpleRangeAnalysisInternal {

/** Gets the estimate of the number of bounds for `e`. */
float estimateNrOfBounds(Expr e) { result = BoundsEstimate::nrOfBoundsExpr(e) }

/** Counts the numbers of lower bounds that are computed internally for `e`. */
float countNrOfLowerBounds(Expr e) {
result = strictcount(float lb | lb = getLowerBoundsImpl(e) | lb)
}

/** Counts the numbers of upper bounds that are computed internally for `e`. */
float countNrOfUpperBounds(Expr e) {
result = strictcount(float ub | ub = getUpperBoundsImpl(e) | ub)
}
}

/** Provides predicates for debugging the simple range analysis library. */
Expand Down Expand Up @@ -2208,7 +2231,7 @@ private module Debug {
*/
predicate countGetLowerBoundsImpl(Expr e, int n) {
e = getRelevantLocatable() and
n = strictcount(float lb | lb = getLowerBoundsImpl(e) | lb)
n = SimpleRangeAnalysisInternal::countNrOfLowerBounds(e)
}

float debugNrOfBounds(Expr e) {
Expand Down
34 changes: 34 additions & 0 deletions cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,37 @@ private module PossibleYearArithmeticOperationCheckConfig implements DataFlow::C

module PossibleYearArithmeticOperationCheckFlow =
TaintTracking::Global<PossibleYearArithmeticOperationCheckConfig>;

/**
* A time conversion function where either
* 1) an incorrect leap year date would result in an error that can be checked from the return value or
* 2) an incorrect leap year date is auto corrected (no checks required)
*/
class TimeConversionFunction extends Function {
boolean autoLeapYearCorrecting;

TimeConversionFunction() {
autoLeapYearCorrecting = false and
(
this.getName() =
[
"FileTimeToSystemTime", "SystemTimeToFileTime", "SystemTimeToTzSpecificLocalTime",
"SystemTimeToTzSpecificLocalTimeEx", "TzSpecificLocalTimeToSystemTime",
"TzSpecificLocalTimeToSystemTimeEx", "RtlLocalTimeToSystemTime",
"RtlTimeToSecondsSince1970", "_mkgmtime", "SetSystemTime", "VarUdateFromDate", "from_tm"
]
or
// Matches all forms of GetDateFormat, e.g. GetDateFormatA/W/Ex
this.getName().matches("GetDateFormat%")
)
or
autoLeapYearCorrecting = true and
this.getName() =
["mktime", "_mktime32", "_mktime64", "SystemTimeToVariantTime", "VariantTimeToSystemTime"]
}

/**
* Holds if the function is expected to auto convert a bad leap year date.
*/
predicate isAutoLeapYearCorrecting() { autoLeapYearCorrecting = true }
}
Loading