Compare commits

...

121 Commits

Author SHA1 Message Date
yoff
0b473e3763 Python: deprecate Function.getAReturnValueFlowNode() and rewrite internal callers
Follow-up to the getAFlowNode deprecation in the same PR: same AST→legacy-CFG
bridge pattern. The 11 internal call sites (across objects/, types/,
frameworks/, and TypeTrackingImpl) are rewritten to bind a `Return ret`
explicitly, then constrain via `ret.getScope() = f and n.getNode() = ret.getValue()`.

The predicate itself is preserved with a deprecation note so external
users do not experience churn.

Semantic noop.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 08:41:44 +00:00
Copilot
a13dfaa44f Python: deprecate AstNode.getAFlowNode() and rewrite internal callers
Preparatory refactor for the shared-CFG dataflow migration.

Deprecates the AstNode.getAFlowNode() cached predicate on the public
Python QL API and rewrites all ~140 internal callers across lib/, src/,
test/, and tools/ from `expr.getAFlowNode() = cfgNode` to
`cfgNode.getNode() = expr`, using ControlFlowNode.getNode() which
already exists in Flow.qll.

The predicate itself is preserved (with a deprecation note pointing at
the new pattern) so external users do not experience churn — they can
migrate at their own pace and the AST/CFG hierarchies still get the
intended untangling once the deprecation eventually elapses.

Semantic noop verified by:
- All 361 lib/ + src/ queries compile clean.
- All 122 ControlFlow + PointsTo library-tests pass.
- All 64 dataflow library-tests pass.
- All 113 Variables/Exceptions/Expressions/Statements/Functions/Imports/
  Security/CWE-798/ModificationOfParameterWithDefault query-tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 08:37:30 +00:00
yoff
ac5fa629ef Python: inline init_module_submodule_defn into ImportResolution
The new-dataflow ImportResolution module only used
semmle.python.essa.SsaDefinitions for the 5-line helper predicate
SsaSource::init_module_submodule_defn. Inline it locally and drop the
dependency on legacy SsaDefinitions. This is the only remaining direct
import of semmle.python.essa.* in the new dataflow stack, so dropping
it makes the layering cleaner.

Semantic noop on the current SSA: SsaSourceVariable.getName() and
GlobalVariable.getId() both project the same DB column
(variable(_,_,result)), and the old call's 'init.getEntryNode() = f'
join was just constraining init = package via Scope.getEntryNode()'s
functional uniqueness. RA dump of accesses.ql confirms only the
expected predicate-rename shuffle; all 70 dataflow + ApiGraphs library
tests pass.

This factors out commit 8cab5a20f2 from the larger shared-CFG
migration #21925.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 08:24:17 +00:00
yoff
5fb75ac987 Python: simplify decorator-detection predicates to pure AST match
The internal predicates that identify `@staticmethod`, `@classmethod` and
`@property` decorators previously required the decorator's `NameNode` to
satisfy `isGlobal()` (i.e. no SSA def reaches the decorator's name use).
That filter was correct but unnecessarily indirect: these three names
are builtins, and even when a class body redefines one, the class body
has not started executing at the decorator position, so Python uses the
builtin.

Match the decorator's AST `Name` directly instead, dropping the CFG/SSA
detour. The slight semantic change — `isGlobal()` would have rejected
module-level shadowing of these builtins — is negligible in practice
and explicitly documented in the change note.

`hasContextmanagerDecorator` and `hasOverloadDecorator` keep the
`NameNode.isGlobal()` check because their target names (`contextmanager`,
`overload`) are imported, not builtin, and local shadowing is a real
concern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-01 14:04:43 +00:00
Jeroen Ketema
ab4a575243 Merge pull request #21899 from MathiasVP/use-new-prototype-extensionals
C++: Use the new `prototype`-related extensionals in MaD
2026-06-01 10:24:19 +02:00
Mathias Vorreiter Pedersen
22b08f1ea4 C++: Add a test with a kind of "partial function template" instantiation. 2026-05-31 12:47:31 +02:00
Mathias Vorreiter Pedersen
e18448dd59 C++: Add more tests. 2026-05-29 18:22:13 +02:00
Henry Mercer
a16f1c555c Merge pull request #21912 from github/post-release-prep/codeql-cli-2.25.6
Post-release preparation for codeql-cli-2.25.6
2026-05-29 14:43:56 +01:00
Geoffrey White
43c1152634 Merge pull request #21905 from geoffw0/swiftflow2
Swift: Update the new metatype sinks
2026-05-29 14:18:45 +01:00
github-actions[bot]
cfb18c2477 Post-release preparation for codeql-cli-2.25.6 2026-05-29 12:04:35 +00:00
Anders Schack-Mulligen
4c31866910 Merge pull request #21867 from aschackmull/ruby/callable-body
Ruby: Split callable and its body into two AST nodes.
2026-05-29 10:16:19 +02:00
Taus
6165623cbf Merge pull request #21724 from github/tausbn/python-add-self-validating-cfg-tests 2026-05-28 22:07:55 +02:00
Michael Nebel
2eac8890d3 Merge pull request #21893 from michaelnebel/cshar/updateroslyn
C#: Update Roslyn and other pinned depenencies.
2026-05-28 13:49:29 +02:00
Mathias Vorreiter Pedersen
2d581504f7 C++: Fix Copilot comments. 2026-05-28 13:34:18 +02:00
Mathias Vorreiter Pedersen
9f211cebd5 C++: Accept test changes. 2026-05-28 13:34:16 +02:00
Mathias Vorreiter Pedersen
8393b40b59 C++: Use the new extensionals to map template functions and classes to their fully templated versions. 2026-05-28 13:34:12 +02:00
Geoffrey White
f8ab76e1ba Swift: Update the new metatype sinks to not rely on name matching '.Type'. 2026-05-28 12:14:10 +01:00
Geoffrey White
34d4e9a8e2 Merge pull request #21898 from geoffw0/swiftflow
Swift: Extend swift/weak-sensitive-data-hashing, swift/weak-password-hashing sinks
2026-05-28 11:52:32 +01:00
Michael Nebel
ed8b9c29cc Merge pull request #21866 from michaelnebel/csharp/refreturnindexerproperty
C#: Property- and Indexer calls for ref return properties and indexers.
2026-05-28 12:31:17 +02:00
Asger F
17fe3e4e31 Merge pull request #21901 from asgerf/unified-fix-test
Unified: fix test output
2026-05-27 22:19:17 +02:00
Asger F
313500e581 Unified: update test outputs 2026-05-27 21:27:09 +02:00
Asger F
ad56ebd361 Unified: update test output 2026-05-27 21:25:32 +02:00
Asger F
6be9e2315d Merge pull request #21841 from github/tausbn/unified-swift-named-body-fields
Unified: Get rid of all `$children` fields
2026-05-27 21:25:11 +02:00
Geoffrey White
5c2488e304 Swift: Fix typo. 2026-05-27 16:29:48 +01:00
Geoffrey White
4fbea4ef95 Swift: Autoformat. 2026-05-27 16:28:21 +01:00
Taus
35faec3db1 Python: Address review comments
- Get rid of unnecessary parentheses
- Use call syntax in the relevant test
- Get rid of `dead(2)` annotation
2026-05-27 15:27:19 +00:00
Mathias Vorreiter Pedersen
5f54a8691d C++: Small cleanup. This has no effect on semantics. 2026-05-27 17:16:22 +02:00
Taus
41fd59c1c1 Unified: regenerate Ast.qll and dbscheme 2026-05-27 15:02:28 +00:00
Taus
d6e7e38e1c Unified: merge in main
Keeps our version of the conflicting files. They will be regenerated in
the next commit.
2026-05-27 15:01:03 +00:00
Jeroen Ketema
7723324687 Merge pull request #21896 from jketema/jketema/deprecated
C++: Remove deprecated code
2026-05-27 14:11:10 +02:00
Michael Nebel
d4c7b5b6fe C#: Update encoding of SBCS to UTF8 with BOM. 2026-05-27 14:01:34 +02:00
Michael Nebel
6b55f865cd C#: Update integration test expected output. 2026-05-27 13:24:45 +02:00
Jeroen Ketema
42c4d8a98b Merge pull request #21897 from jketema/jketema/missing-friend
C++: Update expected test results after extractor changes
2026-05-27 12:54:00 +02:00
Geoffrey White
f962eac914 Swift: Fill the simple gaps in modelling. 2026-05-27 11:20:00 +01:00
Geoffrey White
c6c3e1474c Swift: Add a few more test cases for simple missing models. 2026-05-27 11:15:28 +01:00
Geoffrey White
94e6ec6511 Swift: Widen the new sinks to cover more cases the MaD sinks are missing. 2026-05-27 10:34:12 +01:00
Geoffrey White
c902c75651 Swift: Add change note. 2026-05-27 10:33:42 +01:00
Geoffrey White
2b4ea18dfe Swift: Add a similar sink for password hashing as well. 2026-05-27 10:33:41 +01:00
Geoffrey White
98b7659cc1 Swift: Add a special case sink for weak sensitive data hashing sinks that are calls through a metatype. 2026-05-27 10:33:39 +01:00
Geoffrey White
d9c0b9ca31 Swift: Additional test cases for CryptoKit. 2026-05-27 10:33:37 +01:00
Geoffrey White
b44bca9ea7 Swift: Add HashFunction protocol and other realism to the CryptoKit test stubs (this is needed for new cases to work as intended). 2026-05-27 10:33:31 +01:00
Jeroen Ketema
e66b1e4beb Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-27 10:58:05 +02:00
Jeroen Ketema
362c48cc6d C++: Add change note 2026-05-27 10:44:44 +02:00
Jeroen Ketema
35364a087a C++: Update expected test results after extractor changes 2026-05-27 10:23:16 +02:00
Anders Schack-Mulligen
780591d42a Ruby: Remove spurious parent-child edges for Ruby::SimpleSymbol.
These treesitter nodes translate to multiple AstNodes, but we only want
those that are Stmts.
2026-05-27 10:06:15 +02:00
Anders Schack-Mulligen
3aa69823af Ruby: Skip BodyStmt in ErbDirective.getAChildStmt. 2026-05-27 10:06:14 +02:00
Asger F
f18cdcfec6 Merge pull request #21848 from asgerf/asgerf/swift-yeast
Unified: Add schema checking and corpus-style tests
2026-05-26 22:00:21 +02:00
Jeroen Ketema
7862922e5c C++: Remove deprecated code 2026-05-26 17:54:51 +02:00
Taus
fbc861e7a4 unified: Clarify grammar comment
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-26 16:19:02 +02:00
Michael Nebel
7f2fb2eb99 C#: Use the generic version of the associated implementation. 2026-05-26 15:59:25 +02:00
Michael Nebel
769b1957a5 C#: Update generated files. 2026-05-26 14:13:02 +02:00
Michael Nebel
26da373bd4 C#: Update Roslyn and other pinned dependencies. 2026-05-26 14:11:36 +02:00
Anders Schack-Mulligen
e07f45fff4 Ruby: Accept test changes. 2026-05-22 13:36:59 +02:00
Anders Schack-Mulligen
3adb7043e8 Ruby: Fix pre-existing bug. 2026-05-22 13:29:45 +02:00
Anders Schack-Mulligen
7dcd2d6ab6 Ruby: Adjust CFG to updated AST. 2026-05-22 11:06:15 +02:00
Anders Schack-Mulligen
b6c2915f24 Ruby: Split callable and its body into two AST nodes. 2026-05-22 11:06:14 +02:00
Michael Nebel
6825ccc74f C#: Add change-note. 2026-05-19 14:24:08 +02:00
Michael Nebel
c0273ae94f C#: Update other affected tests (including database quality). 2026-05-19 14:24:05 +02:00
Michael Nebel
1c01bb32d9 C#: Update test expected output. 2026-05-19 14:24:03 +02:00
Michael Nebel
c3bb5e8eff C#: Use ref return getters for properties/indexers in write contexts. 2026-05-19 14:24:00 +02:00
Michael Nebel
9d0d4e4912 C#: Add ref return info for accessors. 2026-05-19 14:23:57 +02:00
Michael Nebel
a2ac0ab7d5 C#: Add test case for indexer calls and update test expected for other files. 2026-05-19 14:23:55 +02:00
Michael Nebel
42aaae7cf3 C#: Add test case for property calls and update test expected for other files. 2026-05-19 14:23:52 +02:00
Anders Schack-Mulligen
cb0fc786c7 Ruby: Minor cleanup, Callable is a StmtSequence. 2026-05-18 13:05:14 +02:00
Taus
dd9c066c61 unified: Regenerate files 2026-05-13 14:24:12 +00:00
Taus
f4f85b58ca unified: Remove some pointless fields
All of these fields have contents that are uniquely determined by the
node they appear on, so they convey no information.
2026-05-13 14:22:06 +00:00
Taus
caef72b047 unified: Introduced named property_binding node
This groups together a bunch of related values that would otherwise be
impossible to match up correctly.
2026-05-13 13:54:21 +00:00
Taus
9787a8b072 unified: Group enum entries
Same as in the preceding commit.
2026-05-13 13:51:25 +00:00
Taus
c8f7c3d7f2 unified: Group more paired items
Same as in the preceding commit, these items do not make sense as
separate fields on the parent node, so we materialise (or create new)
intermediate nodes to group them together.
2026-05-13 13:49:30 +00:00
Taus
ea6f3a9568 unified: Encapsulate function parameters
The field representation would have made it difficult to figure out
which parameters correspond to which default values and attributes, so
instead we now encapsulate these in a new `function_parameter` node.
2026-05-13 13:20:58 +00:00
Taus
5d6dc5c3c3 unified: Clean up statements/block mess
Introduces (by making it named) a `block` node, and conversely makes
`statements` anonymous. This enables us to sensibly distinguish between
the "then" and "else" branch of an `if_statement`, which we were not
able to previously.
2026-05-13 13:06:34 +00:00
Asger F
554bdf14b2 Yeast: fix warning about unnecessary mutability 2026-05-13 11:19:51 +02:00
Asger F
b031e5b1f8 Unified: regenerate QL and make tests not crash
The output is not so interesting as the mapping removes most nodes from the current test file.

I added a name_expr.swift test so at least one NameExpr makes it through.
2026-05-13 10:48:43 +02:00
Asger F
7fa6c4e4a3 Unified: Update test output after rebasing on grammar changes
The branch was rebased on the grammar changes, but rewriting the history was too difficult, so I'm just updating the test output here.
2026-05-13 10:35:34 +02:00
Asger F
600a4969c9 Unified: Simplify concatenation of arguments 2026-05-13 10:35:33 +02:00
Asger F
55194dd757 Unified: Support for calls and member access 2026-05-13 10:35:31 +02:00
Asger F
cbe4c81ca6 Unified: add tuple_pattern and sequence_condition; refine if-let/guard mapping
ast_types.yml additions:
- tuple_pattern { element*: pattern } in the pattern supertype.
- sequence_condition { stmt*: stmt, condition: condition } in the
  condition supertype.

swift.rs:
- Map Swift tuple destructuring (e.g. `let (a, b) = pair`) to the new
  tuple_pattern instead of synthesizing an apply_pattern.
- if-let / guard-let: explicitly match the value_binding_pattern
  (the `let` keyword) and bind the source expression as the next
  condition child, so `let` no longer leaks into the output.
2026-05-13 10:35:29 +02:00
Asger F
3b7a53f678 yeast-macros: merge repeated field declarations and support repetition in field patterns
Two changes to parse_query_fields:

- Allow `field: (kind)* @cap` (repetition + optional capture) in field
  position, mirroring how it works for bare children.
- When the same field name is declared multiple times in a query (e.g.
  `condition: (foo) condition: (bar)`), merge them into a single
  ordered list of children rather than emitting duplicate field
  entries (which at runtime restart the iterator for the field and
  cause the second declaration to re-match from the first child).
2026-05-13 10:35:27 +02:00
Asger F
ccc1dd5d3e Unified: Add tuple_pattern 2026-05-13 10:35:26 +02:00
Asger F
a966dff76e Unified: Add more patterns and some fixes to the AST 2026-05-13 10:35:24 +02:00
Asger F
6b58482dfb Yeast: Fix text associated with synthesized nodes 2026-05-13 10:35:22 +02:00
Asger F
2307839050 Yeast: Change how patterns with repetition are parsed 2026-05-13 10:35:21 +02:00
Asger F
92838011dd Unified: Add some more AST nodes and rules 2026-05-13 10:35:19 +02:00
Asger F
5772ee4d9b YEAST: add NodeRef type, YeastDisplay trait, and source text storage
Introduce NodeRef as a typed wrapper around node arena IDs. Captures in
desugaring rules are now bound as NodeRef instead of raw usize, which
prevents accidental misuse and enables source-text-aware rendering.

Add the YeastDisplay trait as an alternative to Display: its
yeast_to_string method receives the Ast, allowing NodeRef to resolve to
the captured node's source text instead of printing a numeric ID.

Store the original source bytes in the Ast so that NodeContent::Range
values (from synthesized literal nodes) can be resolved back to text.

Update yeast-macros to emit NodeRef-typed capture bindings and use
Into::<usize>::into where raw IDs are needed. The #{expr} template
syntax now uses YeastDisplay instead of Display.

The effect is visible in the corpus tests: operator nodes now correctly
render as e.g. operator "+" instead of operator "3".

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-13 10:35:17 +02:00
Asger F
72b683d63c Unified: Add Swift corpus tests
Add corpus test cases for Swift covering closures, collections, control
flow, functions, literals, loops, operators, optionals/errors, types,
and variables. Update existing desugar.txt with raw parse sections.

Note: operator nodes currently render their node ID instead of the actual
operator text (e.g. operator "3" instead of operator "+"). This will be
fixed in the next commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-13 10:35:16 +02:00
Asger F
8a2a48d2dd Unified extractor: add AST schema, swift translation rules, and corpus framework
Add ast_types.yml defining the unified output AST schema with supertypes
(expr, stmt, condition, pattern) and named nodes (top_level, binary_expr,
name_expr, etc.).

Rewrite swift translation rules to map from tree-sitter Swift grammar to
the unified AST, using one-shot phase rules.

Update the generator to use the output AST schema for dbscheme/QL
generation, and normalize the extraction table prefix to 'unified'.

Improve the corpus test framework to include raw tree-sitter parse output,
type-error checking against the output schema, and better failure
reporting.

Regenerate Ast.qll, unified.dbscheme, and update BasicTest accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-13 10:35:14 +02:00
Asger F
5d0cb9e805 YEAST: fix one-shot rules for unnamed nodes and self-captures
One-shot desugaring rules now skip unnamed nodes (punctuation, keywords,
etc.) since rules are intended to target named nodes only.

Also prevent infinite recursion when a capture refers to the root node of
the matched tree (e.g. an @_ capture on the pattern root).

Additionally fix the swift.rs add_phase call to match the updated 3-arg
signature introduced by the one-shot phase kind commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-13 10:35:12 +02:00
Asger F
bb9e996cb6 Shared: Do not emit ReservedWord class when there are no unnamed tokens 2026-05-13 10:35:11 +02:00
Asger F
c3a9218dcf Yeast: Add one-shot phase kind 2026-05-13 10:35:09 +02:00
Asger F
a049850c51 Yeast: add type-checking errors in AST dump 2026-05-13 10:35:07 +02:00
Asger F
49f19092fb Yeast: add reachable_node_ids() 2026-05-13 10:35:05 +02:00
Asger F
f668b99d6d Unified: Add support for tree-sitter-style corpus tests
This adds tests consisting of source code and a printout of its rewritten AST.
2026-05-13 10:35:02 +02:00
Taus
bfe5aa8d42 unified: Regenerate files 2026-05-12 16:01:32 +00:00
Taus
52d72836f9 unified: Fix multiline_comment issue
This named node (which is in fact emitted by the scanner as an
`external`) was appearing as a child of `class_body` because of inlining
via `_class_member_separator`. This, in itself, appears to be somewhat
of a hack, to handle cases where a multiline comment signals the end of
a class member.

To fix this, we make the external node _unnamed_, but keep the `extras`
node _named_ (so we can still extract it from the parse tree), and we
add a new rule `multiline_comment` that mediates between the two. That
way, the use inside `_class_member_separator` can use the unnamed
variant, and no node is pushed into $children.
2026-05-12 15:59:18 +00:00
Taus
eb480d1de4 unified: Make parenthesized_type named
I'm not entirely happy about this solution, but it seemed to be the most
straightforward way of avoiding various kinds of token bleeding.
2026-05-12 15:38:29 +00:00
Taus
1ef557c972 Python: Address Copilot's comments 2026-05-12 15:27:14 +00:00
Taus
2eee2e50dc unified: clean up patterns
Mostly by materialising a bunch of (useful) intermediate nodes.
2026-05-12 15:23:26 +00:00
Taus
2010844b1e unified: Add fields to property_declaration
Not entirely sure about the `binding?` field on `pattern`, but it looks
like that might actually be useful.
2026-05-12 15:14:35 +00:00
Taus
406a02fa49 unified: Add fields to switch_entry
Of note: this involved un-inlining where_clause.
2026-05-12 15:09:02 +00:00
Taus
6e5e650b42 unified: Add fields for macro_declaration 2026-05-12 15:03:29 +00:00
Taus
eba9f35673 unified: Get rid of $children* on key_path_expression
Doing this involved materialising a lot of previously anonymous nodes,
and I'm not entirely sure it's the best solution, but the node types
look decent enough.
2026-05-12 15:01:10 +00:00
Taus
e1a0e204b1 unified: Promote enum_type_parameter to named and add fields 2026-05-12 14:55:43 +00:00
Taus
5e14a7574e unified: make compilation_condition named and add fields 2026-05-12 14:55:42 +00:00
Taus
6ff404a6d0 unified: More miscellaneous field additions 2026-05-12 14:50:01 +00:00
Taus
9902beddec unified: add proper fields for availability_condition 2026-05-12 14:47:58 +00:00
Taus
e6eac3784a unified: Consolidate fields in if_let_binding 2026-05-12 14:43:13 +00:00
Taus
5784ef22f6 unified: Unify more fields
Not entirely happy about the mixed nature of the `kind` filed (having
both tokens and the named node `throw_keyword` in there), but that's a
problem for a different time.
2026-05-12 14:40:17 +00:00
Taus
bc96ae6e47 unified: Add lambda and arguments fields 2026-05-12 14:29:23 +00:00
Taus
15d84b3e53 unified: More $children fixes
Some nodes with a single child (arguably redundant to do, but I think
it's nice to have the types be consistent), and also an instance of
ensuring that all branches of a `choice` expose consistent field names.
2026-05-12 14:15:36 +00:00
Taus
0499932ba0 unified: Fix fields in await_expression
This required a change in a different place, due to aliasing.
2026-05-12 14:10:38 +00:00
Taus
732cc7bee0 unified: Add fields to inheritance specifiers and calls 2026-05-12 14:07:58 +00:00
Taus
853a98842d unified: Regenerate files 2026-05-12 14:00:14 +00:00
Taus
d6ef467fba unified: Add more fields
A lot of changes, but for the most part these are just adding named
fields in places where they make sense.

After this, there are still ~20 instances of unnamed children appearing.
2026-05-12 13:59:56 +00:00
Taus
c75d819a92 unified: Add effect field
I ended up also aliasing `_async_keyword` to a named node to make it
more consistent with the other node kinds that can be in this field (as
it would be awkward to have two named types and a token here).

Elsewhere in the node types, we'll still have `async?: "async"`, and I
think that's okay.
2026-05-12 13:46:25 +00:00
Taus
75c07996f3 unified: regenerate files 2026-05-12 12:57:26 +00:00
Taus
9dddd93460 unified: add field declarations for statements and members
Part 1 of N of "getting rid of $children" in node-types.yml

Note: in one of the cases the affected node still has the $children
field present. This is because there's some weirdness about recording
multiline comments as class member separators that I did not want to
figure out how to address right now.
2026-05-12 12:57:26 +00:00
Taus
f5c3b63a4a Python: Add ConsecutiveTimestamps test
This one is potentially a bit iffy -- it checks for a very powerful
property (that implies many of the other queries), but as the test
results show, it can produce false positives when there is in fact no
problem. We may want to get rid of it entirely, if it becomes too noisy.
2026-05-12 12:54:26 +00:00
Taus
c30d6ae3aa Python: Add NeverReachable test
This looks for nodes annotated with `t[never]` in the test that are
reachable in the CFG. This should not happen (it messes with various
queries, e.g. the "mixed returns" query), but the test shows that in a
few particular cases (involving the `match` statement where all cases
contain `return`s), we _do_ have reachable nodes that shouldn't be.
2026-05-12 12:54:26 +00:00
Taus
fc2bc26f36 Python: Add BasicBlockOrdering test
This one demonstrates a bug in the current CFG. In a dictionary
comprehension `{k: v for k, v in d.items()}`, we evaluate the value
before the key, which is incorrect. (A fix for this bug has been
implemented in a separate PR.)
2026-05-12 12:54:25 +00:00
Taus
3a979ac2f8 Python: Add some CFG-validation queries
These use the annotated, self-verifying test files to check various
consistency requirements.

Some of these may be expressing the same thing in different ways, but
it's fairly cheap to keep them around, so I have not attempted to
produce a minimal set of queries for this.
2026-05-12 12:54:25 +00:00
Taus
71cd5be513 Python: Add self-validating CFG tests
These tests consist of various Python constructions (hopefully a
somewhat comprehensive set) with specific timestamp annotations
scattered throughout. When the tests are run using the Python 3
interpreter, these annotations are checked and compared to the "current
timestamp" to see that they are in agreement. This is what makes the
tests "self-validating".

There are a few different kinds of annotations: the basic `t[4]` style
(meaning this is executed at timestamp 4), the `t[dead(4)]` variant
(meaning this _would_ happen at timestamp 4, but it is in a dead
branch), and `t[never]` (meaning this is never executed at all).

In addition to this, there is a query, MissingAnnotations, which checks
whether we have applied these annotations maximally. Many expression
nodes are not actually annotatable, so there is a sizeable list of
excluded nodes for that query.
2026-05-12 12:42:29 +00:00
268 changed files with 11136 additions and 6562 deletions

View File

@@ -1,5 +1,5 @@
name: codeql/actions-all
version: 0.4.37
version: 0.4.38-dev
library: true
warnOnImplicitThis: true
dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/actions-queries
version: 0.6.29
version: 0.6.30-dev
library: false
warnOnImplicitThis: true
groups: [actions, queries]

View File

@@ -30,8 +30,6 @@ class Options extends string {
predicate overrideReturnsNull(Call call) {
// Used in CVS:
call.(FunctionCall).getTarget().hasGlobalName("Xstrdup")
or
CustomOptions::overrideReturnsNull(call) // old Options.qll
}
/**
@@ -45,8 +43,6 @@ class Options extends string {
// Used in CVS:
call.(FunctionCall).getTarget().hasGlobalName("Xstrdup") and
nullValue(call.getArgument(0))
or
CustomOptions::returnsNull(call) // old Options.qll
}
/**
@@ -65,8 +61,6 @@ class Options extends string {
f.hasGlobalOrStdName([
"exit", "_exit", "_Exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
])
or
CustomOptions::exits(f) // old Options.qll
}
/**
@@ -79,8 +73,7 @@ class Options extends string {
* runtime, the program's behavior is undefined)
*/
predicate exprExits(Expr e) {
e.(AssumeExpr).getChild(0).(CompileTimeConstantInt).getIntValue() = 0 or
CustomOptions::exprExits(e) // old Options.qll
e.(AssumeExpr).getChild(0).(CompileTimeConstantInt).getIntValue() = 0
}
/**
@@ -88,10 +81,7 @@ class Options extends string {
*
* By default holds only for `fgets`.
*/
predicate alwaysCheckReturnValue(Function f) {
f.hasGlobalOrStdName("fgets") or
CustomOptions::alwaysCheckReturnValue(f) // old Options.qll
}
predicate alwaysCheckReturnValue(Function f) { f.hasGlobalOrStdName("fgets") }
/**
* Holds if it is reasonable to ignore the return value of function
@@ -107,8 +97,6 @@ class Options extends string {
// common way of sleeping using select:
fc.getTarget().hasGlobalName("select") and
fc.getArgument(0).getValue() = "0"
or
CustomOptions::okToIgnoreReturnValue(fc) // old Options.qll
}
}

View File

@@ -98,57 +98,3 @@ class CustomMutexType extends MutexType {
*/
override predicate unlockAccess(FunctionCall fc, Expr arg) { none() }
}
/**
* DEPRECATED: customize `CustomOptions.overrideReturnsNull` instead.
*
* This predicate is required to support backwards compatibility for
* older `Options.qll` files. It should not be removed or modified by
* end users.
*/
predicate overrideReturnsNull(Call call) { none() }
/**
* DEPRECATED: customize `CustomOptions.returnsNull` instead.
*
* This predicate is required to support backwards compatibility for
* older `Options.qll` files. It should not be removed or modified by
* end users.
*/
predicate returnsNull(Call call) { none() }
/**
* DEPRECATED: customize `CustomOptions.exits` instead.
*
* This predicate is required to support backwards compatibility for
* older `Options.qll` files. It should not be removed or modified by
* end users.
*/
predicate exits(Function f) { none() }
/**
* DEPRECATED: customize `CustomOptions.exprExits` instead.
*
* This predicate is required to support backwards compatibility for
* older `Options.qll` files. It should not be removed or modified by
* end users.
*/
predicate exprExits(Expr e) { none() }
/**
* DEPRECATED: customize `CustomOptions.alwaysCheckReturnValue` instead.
*
* This predicate is required to support backwards compatibility for
* older `Options.qll` files. It should not be removed or modified by
* end users.
*/
predicate alwaysCheckReturnValue(Function f) { none() }
/**
* DEPRECATED: customize `CustomOptions.okToIgnoreReturnValue` instead.
*
* This predicate is required to support backwards compatibility for
* older `Options.qll` files. It should not be removed or modified by
* end users.
*/
predicate okToIgnoreReturnValue(FunctionCall fc) { none() }

View File

@@ -0,0 +1,15 @@
---
category: breaking
---
* Removed the deprecated `overrideReturnsNull` predicate from `Options.qll`. Use `CustomOptions.overrideReturnsNull` instead.
* Removed the deprecated `returnsNull` predicate from `Options.qll`. Use `CustomOptions.returnsNull` instead.
* Removed the deprecated `exits` predicate from `Options.qll`. Use `CustomOptions.exits` instead.
* Removed the deprecated `exprExits` predicate from `Options.qll`. Use `CustomOptions.exprExits` instead.
* Removed the deprecated `alwaysCheckReturnValue` predicate from `Options.qll`. Use `CustomOptions.alwaysCheckReturnValue` instead.
* Removed the deprecated `okToIgnoreReturnValue` predicate from `Options.qll`. Use `CustomOptions.okToIgnoreReturnValue` instead.
* Removed the deprecated `semmle.code.cpp.Member`. Import `semmle.code.cpp.Element` and/or `semmle.code.cpp.Type` directly.
* Removed the deprecated `UnknownDefaultLocation` class. Use `UnknownLocation` instead.
* Removed the deprecated `UnknownExprLocation` class. Use `UnknownLocation` instead.
* Removed the deprecated `UnknownStmtLocation` class. Use `UnknownLocation` instead.
* Removed the deprecated `TemplateParameter` class. Use `TypeTemplateParameter` instead.
* Support for class resolution across link targets has been removed for databases which were created with CodeQL versions before 1.23.0.

View File

@@ -32,7 +32,6 @@ import semmle.code.cpp.Class
import semmle.code.cpp.Struct
import semmle.code.cpp.Union
import semmle.code.cpp.Enum
import semmle.code.cpp.Member
import semmle.code.cpp.Field
import semmle.code.cpp.Function
import semmle.code.cpp.MemberFunction

View File

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

View File

@@ -148,28 +148,3 @@ class UnknownLocation extends Location {
this.getFile().getAbsolutePath() = "" and locations_default(this, _, 0, 0, 0, 0)
}
}
/**
* A dummy location which is used when something doesn't have a location in
* the source code but needs to have a `Location` associated with it.
*
* DEPRECATED: use `UnknownLocation`
*/
deprecated class UnknownDefaultLocation extends UnknownLocation { }
/**
* A dummy location which is used when an expression doesn't have a
* location in the source code but needs to have a `Location` associated
* with it.
*
* DEPRECATED: use `UnknownLocation`
*/
deprecated class UnknownExprLocation extends UnknownLocation { }
/**
* A dummy location which is used when a statement doesn't have a location
* in the source code but needs to have a `Location` associated with it.
*
* DEPRECATED: use `UnknownLocation`
*/
deprecated class UnknownStmtLocation extends UnknownLocation { }

View File

@@ -1,6 +0,0 @@
/**
* DEPRECATED: import `semmle.code.cpp.Element` and/or `semmle.code.cpp.Type` directly as required.
*/
import semmle.code.cpp.Element
import semmle.code.cpp.Type

View File

@@ -35,13 +35,6 @@ class NonTypeTemplateParameter extends Literal, TemplateParameterImpl {
override string getAPrimaryQlClass() { result = "NonTypeTemplateParameter" }
}
/**
* A C++ `typename` (or `class`) template parameter.
*
* DEPRECATED: Use `TypeTemplateParameter` instead.
*/
deprecated class TemplateParameter = TypeTemplateParameter;
/**
* A C++ `typename` (or `class`) template parameter.
*

View File

@@ -276,6 +276,45 @@ private predicate isClassConstructedFrom(Class c, Class templateClass) {
not c.isConstructedFrom(_) and c = templateClass
}
/** Gets the fully templated version of `c`. */
private Class getFullyTemplatedClassOld(Class c) {
not c.isFromUninstantiatedTemplate(_) and
isClassConstructedFrom(c, result)
}
private TemplateClass getOriginalClassTemplate(TemplateClass tc) {
result = tc.getOriginalTemplate()
or
not exists(tc.getOriginalTemplate()) and
result = tc
}
/** Gets the fully templated version of `c`. */
private Class getFullyTemplatedClassNew(Class c) {
not c.isFromUninstantiatedTemplate(_) and
exists(Class mid |
c.isConstructedFrom(mid)
or
not c.isConstructedFrom(_) and c = mid
|
result = getOriginalClassTemplate(mid)
or
not mid instanceof TemplateClass and mid = result
)
}
/** Gets the fully templated version of `c`. */
private Class getFullyTemplatedClass(Class c) {
// The `Class::getOriginalTemplate` predicate was introduced in CodeQL
// version 2.25.6 and the upgrade script leaves the
// `class_template_generated_from` extensionals empty if the database
// was generated with an older extractor. So we use the old implementation
// if the `class_template_generated_from` extensional is empty.
if class_template_generated_from(_, _)
then result = getFullyTemplatedClassNew(c)
else result = getFullyTemplatedClassOld(c)
}
/**
* Holds if `f` is an instantiation of a function template `templateFunc`, or
* holds with `f = templateFunc` if `f` is not an instantiation of any function
@@ -292,7 +331,7 @@ private predicate isFunctionConstructedFrom(Function f, Function templateFunc) {
}
/** Gets the fully templated version of `f`. */
Function getFullyTemplatedFunction(Function f) {
private Function getFullyTemplatedFunctionOld(Function f) {
not f.isFromUninstantiatedTemplate(_) and
(
exists(Class c, Class templateClass, int i |
@@ -306,13 +345,46 @@ Function getFullyTemplatedFunction(Function f) {
)
}
private TemplateFunction getOriginalFunctionTemplate(TemplateFunction tf) {
result = tf.getOriginalTemplate()
or
not exists(tf.getOriginalTemplate()) and
result = tf
}
/** Gets the fully templated version of `f`. */
private Function getFullyTemplatedFunctionNew(Function f) {
not f.isFromUninstantiatedTemplate(_) and
exists(Function mid |
f.isConstructedFrom(mid)
or
not f.isConstructedFrom(_) and f = mid
|
result = getOriginalFunctionTemplate(mid)
or
not mid instanceof TemplateFunction and mid = result
)
}
/** Gets the fully templated version of `f`. */
Function getFullyTemplatedFunction(Function f) {
// The `Function::getOriginalTemplate` predicate was introduced in CodeQL
// version 2.25.6 and the upgrade script leaves the
// `function_template_generated_from` extensionals empty if the database
// was generated with an older extractor. So we use the old implementation
// if the `function_template_generated_from` extensional is empty.
if function_template_generated_from(_, _)
then result = getFullyTemplatedFunctionNew(f)
else result = getFullyTemplatedFunctionOld(f)
}
/** Prefixes `const` to `s` if `t` is const, or returns `s` otherwise. */
bindingset[s, t]
private string withConst(string s, Type t) {
if t.isConst() then result = "const " + s else result = s
}
/** Prefixes `volatile` to `s` if `t` is const, or returns `s` otherwise. */
/** Prefixes `volatile` to `s` if `t` is volatile, or returns `s` otherwise. */
bindingset[s, t]
private string withVolatile(string s, Type t) {
if t.isVolatile() then result = "volatile " + s else result = s
@@ -490,7 +562,7 @@ pragma[nomagic]
private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) {
// If there is a declaring type then we start by expanding the function templates
exists(Class template |
isClassConstructedFrom(f.getDeclaringType(), template) and
template = getFullyTemplatedClass(f.getDeclaringType()) and
remaining = getNumberOfSupportedClassTemplateArguments(template) and
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
)
@@ -502,7 +574,7 @@ private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining
or
exists(string mid, TypeTemplateParameter tp, Class template |
mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and
isClassConstructedFrom(f.getDeclaringType(), template) and
template = getFullyTemplatedClass(f.getDeclaringType()) and
tp = getSupportedClassTemplateArgument(template, remaining)
|
result = mid.replaceAll(tp.getName(), "class:" + remaining.toString())

View File

@@ -1,59 +1,5 @@
import semmle.code.cpp.Type
/** For upgraded databases without mangled name info. */
pragma[noinline]
private string getTopLevelClassName(@usertype c) {
not mangled_name(_, _, _) and
isClass(c) and
usertypes(c, result, _) and
not namespacembrs(_, c) and // not in a namespace
not member(_, _, c) and // not in some structure
not class_instantiation(c, _) // not a template instantiation
}
/**
* For upgraded databases without mangled name info.
* Holds if `d` is a unique complete class named `name`.
*/
pragma[noinline]
private predicate existsCompleteWithName(string name, @usertype d) {
not mangled_name(_, _, _) and
is_complete(d) and
name = getTopLevelClassName(d) and
onlyOneCompleteClassExistsWithName(name)
}
/** For upgraded databases without mangled name info. */
pragma[noinline]
private predicate onlyOneCompleteClassExistsWithName(string name) {
not mangled_name(_, _, _) and
strictcount(@usertype c | is_complete(c) and getTopLevelClassName(c) = name) = 1
}
/**
* For upgraded databases without mangled name info.
* Holds if `c` is an incomplete class named `name`.
*/
pragma[noinline]
private predicate existsIncompleteWithName(string name, @usertype c) {
not mangled_name(_, _, _) and
not is_complete(c) and
name = getTopLevelClassName(c)
}
/**
* For upgraded databases without mangled name info.
* Holds if `c` is an incomplete class, and there exists a unique complete class `d`
* with the same name.
*/
private predicate oldHasCompleteTwin(@usertype c, @usertype d) {
not mangled_name(_, _, _) and
exists(string name |
existsIncompleteWithName(name, c) and
existsCompleteWithName(name, d)
)
}
pragma[noinline]
private @mangledname getClassMangledName(@usertype c) {
isClass(c) and
@@ -103,10 +49,7 @@ private module Cached {
@usertype resolveClass(@usertype c) {
hasCompleteTwin(c, result)
or
oldHasCompleteTwin(c, result)
or
not hasCompleteTwin(c, _) and
not oldHasCompleteTwin(c, _) and
result = c
}

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.6.4
version: 1.6.5-dev
groups:
- cpp
- queries

View File

@@ -51,13 +51,16 @@ models
| 50 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
| 51 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
| 52 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
| 53 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual |
| 54 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual |
| 55 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual |
| 56 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual |
| 57 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
| 53 | Summary: ; TemplateClass1; true; templateFunction2<U,V>; (U,V); ; Argument[1]; ReturnValue; value; manual |
| 54 | Summary: ; TemplateClass1<T>; false; templateFunction<U>; (T,U); ; Argument[0]; ReturnValue; value; manual |
| 55 | Summary: ; TemplateClass2<T,U>; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual |
| 56 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual |
| 57 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual |
| 58 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual |
| 59 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual |
| 60 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
edges
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:57 |
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:60 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:32 |
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:32 Sink:MaD:2 |
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
@@ -66,24 +69,24 @@ edges
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:57 |
| azure.cpp:62:10:62:14 | [summary param] this in Value | azure.cpp:62:10:62:14 | [summary] to write: ReturnValue[*] in Value | provenance | MaD:56 |
| azure.cpp:113:16:113:19 | [summary param] this in Read | azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | provenance | MaD:53 |
| azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | azure.cpp:114:16:114:26 | [summary param] *0 in ReadToCount [Return] | provenance | MaD:54 |
| azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | provenance | MaD:55 |
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:60 |
| azure.cpp:62:10:62:14 | [summary param] this in Value | azure.cpp:62:10:62:14 | [summary] to write: ReturnValue[*] in Value | provenance | MaD:59 |
| azure.cpp:113:16:113:19 | [summary param] this in Read | azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | provenance | MaD:56 |
| azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | azure.cpp:114:16:114:26 | [summary param] *0 in ReadToCount [Return] | provenance | MaD:57 |
| azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | provenance | MaD:58 |
| azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue in ReadToEnd [element] | provenance | |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:29 |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | |
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | |
| azure.cpp:257:5:257:8 | *resp | azure.cpp:113:16:113:19 | [summary param] this in Read | provenance | |
| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:53 |
| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:56 |
| azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | |
| azure.cpp:262:5:262:8 | *resp | azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | provenance | |
| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:54 |
| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:57 |
| azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | |
| azure.cpp:266:38:266:41 | *resp | azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | provenance | |
| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:55 |
| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:58 |
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | |
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | |
| azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | |
@@ -100,11 +103,11 @@ edges
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:26 |
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | |
| azure.cpp:282:21:282:23 | *call to get | azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | provenance | |
| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:55 |
| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:58 |
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | |
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | |
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:62:10:62:14 | [summary param] this in Value | provenance | |
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:56 |
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:59 |
| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | |
| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:30 |
| azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | |
@@ -180,6 +183,39 @@ edges
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 |
| test.cpp:118:44:118:44 | *x | test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | provenance | |
| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:48 |
| test.cpp:125:5:125:20 | [summary param] 0 in templateFunction | test.cpp:125:5:125:20 | [summary] to write: ReturnValue in templateFunction | provenance | MaD:54 |
| test.cpp:128:5:128:21 | [summary param] 1 in templateFunction2 | test.cpp:128:5:128:21 | [summary] to write: ReturnValue in templateFunction2 | provenance | MaD:53 |
| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | |
| test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | |
| test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 |
| test.cpp:134:45:134:45 | x | test.cpp:125:5:125:20 | [summary param] 0 in templateFunction | provenance | |
| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:54 |
| test.cpp:140:4:140:11 | [summary param] 1 in function | test.cpp:140:4:140:11 | [summary] to write: ReturnValue in function | provenance | MaD:55 |
| test.cpp:140:4:140:11 | [summary param] 1 in function | test.cpp:140:4:140:11 | [summary] to write: ReturnValue in function | provenance | MaD:55 |
| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | |
| test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | |
| test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 |
| test.cpp:148:26:148:26 | x | test.cpp:140:4:140:11 | [summary param] 1 in function | provenance | |
| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:55 |
| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | |
| test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | |
| test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 |
| test.cpp:157:26:157:26 | x | test.cpp:140:4:140:11 | [summary param] 1 in function | provenance | |
| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:55 |
| test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | |
| test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | |
| test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | |
| test.cpp:165:69:165:69 | x | test.cpp:128:5:128:21 | [summary param] 1 in templateFunction2 | provenance | |
| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:53 |
| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:25 |
| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | |
| test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | |
| test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 |
| test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | |
| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:53 |
| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:33 |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:24:8:24:11 | * ... | provenance | |
@@ -483,6 +519,43 @@ nodes
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | semmle.label | call to callWithNonTypeTemplate |
| test.cpp:118:44:118:44 | *x | semmle.label | *x |
| test.cpp:119:10:119:11 | y2 | semmle.label | y2 |
| test.cpp:125:5:125:20 | [summary param] 0 in templateFunction | semmle.label | [summary param] 0 in templateFunction |
| test.cpp:125:5:125:20 | [summary] to write: ReturnValue in templateFunction | semmle.label | [summary] to write: ReturnValue in templateFunction |
| test.cpp:128:5:128:21 | [summary param] 1 in templateFunction2 | semmle.label | [summary param] 1 in templateFunction2 |
| test.cpp:128:5:128:21 | [summary] to write: ReturnValue in templateFunction2 | semmle.label | [summary] to write: ReturnValue in templateFunction2 |
| test.cpp:133:10:133:18 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:133:10:133:18 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:134:13:134:43 | call to templateFunction | semmle.label | call to templateFunction |
| test.cpp:134:13:134:43 | call to templateFunction | semmle.label | call to templateFunction |
| test.cpp:134:45:134:45 | x | semmle.label | x |
| test.cpp:135:10:135:10 | y | semmle.label | y |
| test.cpp:140:4:140:11 | [summary param] 1 in function | semmle.label | [summary param] 1 in function |
| test.cpp:140:4:140:11 | [summary param] 1 in function | semmle.label | [summary param] 1 in function |
| test.cpp:140:4:140:11 | [summary] to write: ReturnValue in function | semmle.label | [summary] to write: ReturnValue in function |
| test.cpp:140:4:140:11 | [summary] to write: ReturnValue in function | semmle.label | [summary] to write: ReturnValue in function |
| test.cpp:146:10:146:18 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:146:10:146:18 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:148:10:148:27 | call to function | semmle.label | call to function |
| test.cpp:148:10:148:27 | call to function | semmle.label | call to function |
| test.cpp:148:26:148:26 | x | semmle.label | x |
| test.cpp:149:10:149:10 | z | semmle.label | z |
| test.cpp:155:10:155:18 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:155:10:155:18 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:157:13:157:20 | call to function | semmle.label | call to function |
| test.cpp:157:13:157:20 | call to function | semmle.label | call to function |
| test.cpp:157:26:157:26 | x | semmle.label | x |
| test.cpp:158:10:158:10 | z | semmle.label | z |
| test.cpp:164:7:164:7 | *templateFunction3 | semmle.label | *templateFunction3 |
| test.cpp:164:34:164:34 | x | semmle.label | x |
| test.cpp:165:12:165:64 | call to templateFunction2 | semmle.label | call to templateFunction2 |
| test.cpp:165:12:165:64 | call to templateFunction2 | semmle.label | call to templateFunction2 |
| test.cpp:165:69:165:69 | x | semmle.label | x |
| test.cpp:170:10:170:18 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:170:10:170:18 | call to ymlSource | semmle.label | call to ymlSource |
| test.cpp:172:13:172:44 | call to templateFunction3 | semmle.label | call to templateFunction3 |
| test.cpp:172:13:172:44 | call to templateFunction3 | semmle.label | call to templateFunction3 |
| test.cpp:172:51:172:51 | x | semmle.label | x |
| test.cpp:173:10:173:10 | y | semmle.label | y |
| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | semmle.label | [summary param] *0 in CommandLineToArgvA |
| windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | semmle.label | [summary] to write: ReturnValue[**] in CommandLineToArgvA |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA |
@@ -688,6 +761,11 @@ subpaths
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body |
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body |
| test.cpp:118:44:118:44 | *x | test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | test.cpp:111:3:111:25 | [summary] to write: ReturnValue in callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate |
| test.cpp:134:45:134:45 | x | test.cpp:125:5:125:20 | [summary param] 0 in templateFunction | test.cpp:125:5:125:20 | [summary] to write: ReturnValue in templateFunction | test.cpp:134:13:134:43 | call to templateFunction |
| test.cpp:148:26:148:26 | x | test.cpp:140:4:140:11 | [summary param] 1 in function | test.cpp:140:4:140:11 | [summary] to write: ReturnValue in function | test.cpp:148:10:148:27 | call to function |
| test.cpp:157:26:157:26 | x | test.cpp:140:4:140:11 | [summary param] 1 in function | test.cpp:140:4:140:11 | [summary] to write: ReturnValue in function | test.cpp:157:13:157:20 | call to function |
| test.cpp:165:69:165:69 | x | test.cpp:128:5:128:21 | [summary param] 1 in templateFunction2 | test.cpp:128:5:128:21 | [summary] to write: ReturnValue in templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 |
| test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 |
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA |
| windows.cpp:537:40:537:41 | *& ... | windows.cpp:473:17:473:37 | [summary param] *1 in RtlCopyVolatileMemory | windows.cpp:473:17:473:37 | [summary param] *0 in RtlCopyVolatileMemory [Return] | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument |
| windows.cpp:542:38:542:39 | *& ... | windows.cpp:479:17:479:35 | [summary param] *1 in RtlCopyDeviceMemory | windows.cpp:479:17:479:35 | [summary param] *0 in RtlCopyDeviceMemory [Return] | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument |

View File

@@ -18,4 +18,7 @@ extensions:
- ["", "", False, "ymlStepManual_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["", "", False, "ymlStepGenerated_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["", "", False, "callWithArgument", "", "", "Argument[1]", "Argument[0].Parameter[0]", "value", "manual"]
- ["", "", False, "callWithNonTypeTemplate<T>", "(const T &)", "", "Argument[*0]", "ReturnValue", "value", "manual"]
- ["", "", False, "callWithNonTypeTemplate<T>", "(const T &)", "", "Argument[*0]", "ReturnValue", "value", "manual"]
- ["", "TemplateClass1<T>", False, "templateFunction<U>", "(T,U)", "", "Argument[0]", "ReturnValue", "value", "manual"]
- ["", "TemplateClass1", True, "templateFunction2<U,V>", "(U,V)", "", "Argument[1]", "ReturnValue", "value", "manual"]
- ["", "TemplateClass2<T,U>", True, "function", "(U,T)", "", "Argument[1]", "ReturnValue", "value", "manual"]

View File

@@ -15,3 +15,7 @@
| test.cpp:89:11:89:11 | y | test-sink |
| test.cpp:116:10:116:11 | y1 | test-sink |
| test.cpp:119:10:119:11 | y2 | test-sink |
| test.cpp:135:10:135:10 | y | test-sink |
| test.cpp:149:10:149:10 | z | test-sink |
| test.cpp:158:10:158:10 | z | test-sink |
| test.cpp:173:10:173:10 | y | test-sink |

View File

@@ -9,6 +9,10 @@
| test.cpp:56:8:56:16 | call to ymlSource | local |
| test.cpp:94:10:94:18 | call to ymlSource | local |
| test.cpp:114:10:114:18 | call to ymlSource | local |
| test.cpp:133:10:133:18 | call to ymlSource | local |
| test.cpp:146:10:146:18 | call to ymlSource | local |
| test.cpp:155:10:155:18 | call to ymlSource | local |
| test.cpp:170:10:170:18 | call to ymlSource | local |
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | local |
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | local |
| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | local |

View File

@@ -118,3 +118,57 @@ void test_callWithNonTypeTemplate() {
int y2 = callWithNonTypeTemplate<int, 10>(x);
ymlSink(y2); // $ ir
}
template<class T>
struct TemplateClass1 {
template<class U>
U templateFunction(T, U);
template<class U, class V>
V templateFunction2(U, V);
};
void test_template_function_in_template_class() {
TemplateClass1<int> b;
int x = ymlSource();
auto y = b.templateFunction<unsigned long>(x, 0UL);
ymlSink(y); // $ ir
}
template<class S, class T>
struct TemplateClass2 {
T function(T, S);
};
template<class V> using PartialInstantiationOfTemplateClass2 = TemplateClass2<int, V>;
void test_partial_class_instantiation() {
int x = ymlSource();
PartialInstantiationOfTemplateClass2<unsigned long> y;
int z = y.function(0UL, x);
ymlSink(z); // $ ir
}
template<class V> struct DeriveFromFromPartialTemplateInstantiation : TemplateClass2<int, V> { };
void test_inheritance() {
int x = ymlSource();
DeriveFromFromPartialTemplateInstantiation<long> y;
auto z = y.function(0L, x);
ymlSink(z); // $ ir
}
template<class T>
struct Class1 : TemplateClass1<T> {
template<class U>
int templateFunction3(U u, int x) {
return TemplateClass1<T>::template templateFunction2<U, int>(u, x);
}
};
void test_class1() {
int x = ymlSource();
Class1<int> c;
auto y = c.templateFunction3<unsigned long>(0UL, x);
ymlSink(y); // $ ir
}

View File

@@ -27383,54 +27383,55 @@ getParameterTypeName
| stl.h:91:24:91:33 | operator++ | 0 | int |
| stl.h:95:44:95:44 | back_inserter | 0 | func:0 & |
| stl.h:95:44:95:44 | back_inserter | 0 | func:0 & |
| stl.h:148:3:148:14 | basic_string | 0 | const class:2 & |
| stl.h:149:33:149:44 | basic_string | 0 | const class:0 * |
| stl.h:149:33:149:44 | basic_string | 1 | const class:2 & |
| stl.h:151:16:151:20 | c_str | 0 | func:0 |
| stl.h:151:16:151:20 | c_str | 1 | func:0 |
| stl.h:151:16:151:20 | c_str | 2 | const class:2 & |
| stl.h:147:12:147:23 | basic_string | 0 | const class:2 & |
| stl.h:148:3:148:14 | basic_string | 0 | const class:0 * |
| stl.h:148:3:148:14 | basic_string | 1 | const class:2 & |
| stl.h:149:33:149:44 | basic_string | 0 | func:0 |
| stl.h:149:33:149:44 | basic_string | 1 | func:0 |
| stl.h:149:33:149:44 | basic_string | 2 | const class:2 & |
| stl.h:165:8:165:16 | push_back | 0 | class:0 |
| stl.h:173:13:173:22 | operator[] | 0 | size_type |
| stl.h:175:13:175:14 | at | 0 | size_type |
| stl.h:176:35:176:44 | operator+= | 0 | size_type |
| stl.h:176:35:176:44 | operator+= | 0 | size_type |
| stl.h:177:17:177:26 | operator+= | 0 | const func:0 & |
| stl.h:178:17:178:22 | append | 0 | const class:0 * |
| stl.h:179:17:179:22 | append | 0 | const basic_string & |
| stl.h:180:17:180:22 | append | 0 | const class:0 * |
| stl.h:181:47:181:52 | append | 0 | size_type |
| stl.h:181:47:181:52 | append | 1 | class:0 |
| stl.h:182:17:182:22 | assign | 0 | func:0 |
| stl.h:182:17:182:22 | assign | 1 | func:0 |
| stl.h:183:17:183:22 | assign | 0 | const basic_string & |
| stl.h:184:47:184:52 | assign | 0 | size_type |
| stl.h:184:47:184:52 | assign | 1 | class:0 |
| stl.h:185:17:185:22 | insert | 0 | func:0 |
| stl.h:185:17:185:22 | insert | 1 | func:0 |
| stl.h:176:35:176:44 | operator+= | 0 | const func:0 & |
| stl.h:176:35:176:44 | operator+= | 0 | const func:0 & |
| stl.h:177:17:177:26 | operator+= | 0 | const class:0 * |
| stl.h:178:17:178:22 | append | 0 | const basic_string & |
| stl.h:179:17:179:22 | append | 0 | const class:0 * |
| stl.h:180:17:180:22 | append | 0 | size_type |
| stl.h:180:17:180:22 | append | 1 | class:0 |
| stl.h:181:47:181:52 | append | 0 | func:0 |
| stl.h:181:47:181:52 | append | 1 | func:0 |
| stl.h:182:17:182:22 | assign | 0 | const basic_string & |
| stl.h:183:17:183:22 | assign | 0 | size_type |
| stl.h:183:17:183:22 | assign | 1 | class:0 |
| stl.h:184:47:184:52 | assign | 0 | func:0 |
| stl.h:184:47:184:52 | assign | 1 | func:0 |
| stl.h:185:17:185:22 | insert | 0 | size_type |
| stl.h:185:17:185:22 | insert | 1 | const basic_string & |
| stl.h:186:17:186:22 | insert | 0 | size_type |
| stl.h:186:17:186:22 | insert | 1 | const basic_string & |
| stl.h:186:17:186:22 | insert | 1 | size_type |
| stl.h:186:17:186:22 | insert | 2 | class:0 |
| stl.h:187:17:187:22 | insert | 0 | size_type |
| stl.h:187:17:187:22 | insert | 1 | size_type |
| stl.h:187:17:187:22 | insert | 2 | class:0 |
| stl.h:188:12:188:17 | insert | 0 | size_type |
| stl.h:188:12:188:17 | insert | 1 | const class:0 * |
| stl.h:187:17:187:22 | insert | 1 | const class:0 * |
| stl.h:188:12:188:17 | insert | 0 | const_iterator |
| stl.h:188:12:188:17 | insert | 1 | size_type |
| stl.h:188:12:188:17 | insert | 2 | class:0 |
| stl.h:189:42:189:47 | insert | 0 | const_iterator |
| stl.h:189:42:189:47 | insert | 1 | size_type |
| stl.h:189:42:189:47 | insert | 2 | class:0 |
| stl.h:190:17:190:23 | replace | 0 | const_iterator |
| stl.h:190:17:190:23 | replace | 1 | func:0 |
| stl.h:190:17:190:23 | replace | 2 | func:0 |
| stl.h:189:42:189:47 | insert | 1 | func:0 |
| stl.h:189:42:189:47 | insert | 2 | func:0 |
| stl.h:190:17:190:23 | replace | 0 | size_type |
| stl.h:190:17:190:23 | replace | 1 | size_type |
| stl.h:190:17:190:23 | replace | 2 | const basic_string & |
| stl.h:191:17:191:23 | replace | 0 | size_type |
| stl.h:191:17:191:23 | replace | 1 | size_type |
| stl.h:191:17:191:23 | replace | 2 | const basic_string & |
| stl.h:192:13:192:16 | copy | 0 | size_type |
| stl.h:191:17:191:23 | replace | 2 | size_type |
| stl.h:191:17:191:23 | replace | 3 | class:0 |
| stl.h:192:13:192:16 | copy | 0 | class:0 * |
| stl.h:192:13:192:16 | copy | 1 | size_type |
| stl.h:192:13:192:16 | copy | 2 | size_type |
| stl.h:192:13:192:16 | copy | 3 | class:0 |
| stl.h:193:8:193:12 | clear | 0 | class:0 * |
| stl.h:193:8:193:12 | clear | 1 | size_type |
| stl.h:193:8:193:12 | clear | 2 | size_type |
| stl.h:195:8:195:11 | swap | 0 | size_type |
| stl.h:195:8:195:11 | swap | 1 | size_type |
| stl.h:194:16:194:21 | substr | 0 | size_type |
| stl.h:194:16:194:21 | substr | 1 | size_type |
| stl.h:195:8:195:11 | swap | 0 | basic_string & |
| stl.h:198:94:198:102 | operator+ | 0 | const basic_string & |
| stl.h:198:94:198:102 | operator+ | 1 | const basic_string & |
| stl.h:199:94:199:102 | operator+ | 0 | const basic_string & |

View File

@@ -1,14 +1,14 @@
| file://:0:0:0:0 | E<C>'s friend | loop.cpp:5:26:5:26 | E<D> |
| file://:0:0:0:0 | E<C>'s friend | loop.cpp:5:26:5:26 | E<T> |
| file://:0:0:0:0 | E<C>'s friend | loop.cpp:10:26:10:26 | F<D> |
| file://:0:0:0:0 | E<C>'s friend | loop.cpp:5:26:5:29 | E<D> |
| file://:0:0:0:0 | E<C>'s friend | loop.cpp:10:26:10:26 | F<T> |
| file://:0:0:0:0 | E<D>'s friend | loop.cpp:5:26:5:26 | E<C> |
| file://:0:0:0:0 | E<C>'s friend | loop.cpp:10:26:10:29 | F<D> |
| file://:0:0:0:0 | E<D>'s friend | loop.cpp:5:26:5:26 | E<T> |
| file://:0:0:0:0 | E<D>'s friend | loop.cpp:10:26:10:26 | F<D> |
| file://:0:0:0:0 | E<D>'s friend | loop.cpp:5:26:5:29 | E<C> |
| file://:0:0:0:0 | E<D>'s friend | loop.cpp:10:26:10:26 | F<T> |
| file://:0:0:0:0 | F<D>'s friend | loop.cpp:5:26:5:26 | E<C> |
| file://:0:0:0:0 | F<D>'s friend | loop.cpp:5:26:5:26 | E<D> |
| file://:0:0:0:0 | E<D>'s friend | loop.cpp:10:26:10:29 | F<D> |
| file://:0:0:0:0 | F<D>'s friend | loop.cpp:5:26:5:26 | E<T> |
| file://:0:0:0:0 | F<D>'s friend | loop.cpp:5:26:5:29 | E<C> |
| file://:0:0:0:0 | F<D>'s friend | loop.cpp:5:26:5:29 | E<D> |
| loop.cpp:6:5:6:5 | E<T>'s friend | loop.cpp:5:26:5:26 | E<T> |
| loop.cpp:7:5:7:5 | E<T>'s friend | loop.cpp:7:36:7:36 | F<U> |
| loop.cpp:11:5:11:5 | F<T>'s friend | loop.cpp:11:36:11:36 | E<U> |

View File

@@ -664,7 +664,7 @@ namespace Semmle.Extraction.CSharp
// Find the (possibly unbound) original extension method that maps to this implementation (if any).
var unboundDeclaration = extensions.SelectMany(e => e.GetMembers())
.OfType<IMethodSymbol>()
.FirstOrDefault(m => SymbolEqualityComparer.Default.Equals(m.AssociatedExtensionImplementation, method.ConstructedFrom));
.FirstOrDefault(m => SymbolEqualityComparer.Default.Equals(m.AssociatedExtensionImplementation?.ConstructedFrom, method.ConstructedFrom));
var isFullyConstructed = method.IsBoundGenericMethod();
if (isFullyConstructed && unboundDeclaration?.ContainingType is INamedTypeSymbol extensionType)

View File

@@ -69,6 +69,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
Overrides(trapFile);
ExtractRefReturn(trapFile, Symbol, this);
if (Symbol.FromSource() && !HasBody)
{

View File

@@ -4,7 +4,7 @@ source https://api.nuget.org/v3/index.json
# behave like nuget in choosing transitive dependency versions
strategy: max
nuget Basic.CompilerLog.Util 0.9.25
nuget Basic.CompilerLog.Util 0.9.39
nuget Mono.Posix.NETStandard
nuget Newtonsoft.Json
nuget NuGet.Versioning
@@ -12,7 +12,7 @@ nuget xunit
nuget xunit.runner.visualstudio
nuget xunit.runner.utility
nuget Microsoft.NET.Test.Sdk
nuget Microsoft.CodeAnalysis.CSharp 5.0.0
nuget Microsoft.CodeAnalysis 5.0.0
nuget Microsoft.Build 18.0.2
nuget Microsoft.CodeAnalysis.CSharp 5.3.0
nuget Microsoft.CodeAnalysis 5.3.0
nuget Microsoft.Build 18.6.3
nuget Microsoft.VisualStudio.SolutionPersistence

100
csharp/paket.lock generated
View File

@@ -3,45 +3,42 @@ STRATEGY: MAX
RESTRICTION: == net10.0
NUGET
remote: https://api.nuget.org/v3/index.json
Basic.CompilerLog.Util (0.9.25)
Basic.CompilerLog.Util (0.9.39)
MessagePack (>= 3.1.4)
Microsoft.Bcl.Memory (>= 9.0.10)
Microsoft.Bcl.Memory (>= 10.0.7)
Microsoft.CodeAnalysis (>= 4.8)
Microsoft.CodeAnalysis.CSharp (>= 4.8)
Microsoft.CodeAnalysis.VisualBasic (>= 4.8)
Microsoft.Extensions.ObjectPool (>= 9.0.10)
MSBuild.StructuredLogger (>= 2.3.71)
NaturalSort.Extension (>= 4.4)
NuGet.Versioning (>= 6.14)
Microsoft.Extensions.ObjectPool (>= 10.0.7)
MSBuild.StructuredLogger (>= 2.3.178)
Humanizer.Core (3.0.10)
MessagePack (3.1.4)
MessagePack.Annotations (>= 3.1.4)
MessagePackAnalyzer (>= 3.1.4)
MessagePack (3.1.6)
MessagePack.Annotations (>= 3.1.6)
MessagePackAnalyzer (>= 3.1.6)
Microsoft.NET.StringTools (>= 17.11.4)
MessagePack.Annotations (3.1.4)
MessagePackAnalyzer (3.1.4)
MessagePack.Annotations (3.1.6)
MessagePackAnalyzer (3.1.6)
Microsoft.Bcl.AsyncInterfaces (10.0.8)
Microsoft.Bcl.Memory (10.0.8)
Microsoft.Build (18.0.2)
Microsoft.Build.Framework (>= 18.0.2)
Microsoft.NET.StringTools (>= 18.0.2)
System.Configuration.ConfigurationManager (>= 9.0)
System.Diagnostics.EventLog (>= 9.0)
System.Reflection.MetadataLoadContext (>= 9.0)
System.Security.Cryptography.ProtectedData (>= 9.0.6)
Microsoft.Build.Framework (18.4)
Microsoft.Build.Utilities.Core (18.4)
Microsoft.Build.Framework (>= 18.4)
Microsoft.NET.StringTools (>= 18.4)
System.Configuration.ConfigurationManager (>= 10.0.1)
System.Diagnostics.EventLog (>= 10.0.1)
System.Security.Cryptography.ProtectedData (>= 10.0.1)
Microsoft.CodeAnalysis (5.0)
Microsoft.Build (18.6.3)
Microsoft.Build.Framework (>= 18.6.3)
System.Configuration.ConfigurationManager (>= 10.0.3)
System.Diagnostics.EventLog (>= 10.0.3)
System.Reflection.MetadataLoadContext (>= 10.0.3)
System.Security.Cryptography.ProtectedData (>= 10.0.3)
Microsoft.Build.Framework (18.6.3)
Microsoft.NET.StringTools (>= 18.6.3)
Microsoft.Build.Utilities.Core (18.6.3)
Microsoft.Build.Framework (>= 18.6.3)
System.Configuration.ConfigurationManager (>= 10.0.3)
System.Diagnostics.EventLog (>= 10.0.3)
System.Security.Cryptography.ProtectedData (>= 10.0.3)
Microsoft.CodeAnalysis (5.3)
Humanizer.Core (>= 2.14.1)
Microsoft.Bcl.AsyncInterfaces (>= 9.0)
Microsoft.CodeAnalysis.Analyzers (>= 3.11)
Microsoft.CodeAnalysis.CSharp.Workspaces (5.0)
Microsoft.CodeAnalysis.VisualBasic.Workspaces (5.0)
Microsoft.CodeAnalysis.Analyzers (>= 5.3.0-2.25625.1)
Microsoft.CodeAnalysis.CSharp.Workspaces (5.3)
Microsoft.CodeAnalysis.VisualBasic.Workspaces (5.3)
System.Buffers (>= 4.6)
System.Collections.Immutable (>= 9.0)
System.Composition (>= 9.0)
@@ -54,36 +51,36 @@ NUGET
System.Threading.Channels (>= 8.0)
System.Threading.Tasks.Extensions (>= 4.6)
Microsoft.CodeAnalysis.Analyzers (5.3)
Microsoft.CodeAnalysis.Common (5.0)
Microsoft.CodeAnalysis.Analyzers (>= 3.11)
Microsoft.CodeAnalysis.CSharp (5.0)
Microsoft.CodeAnalysis.Analyzers (>= 3.11)
Microsoft.CodeAnalysis.Common (5.0)
Microsoft.CodeAnalysis.CSharp.Workspaces (5.0)
Microsoft.CodeAnalysis.Common (5.3)
Microsoft.CodeAnalysis.Analyzers (>= 5.3.0-2.25625.1)
Microsoft.CodeAnalysis.CSharp (5.3)
Microsoft.CodeAnalysis.Analyzers (>= 5.3.0-2.25625.1)
Microsoft.CodeAnalysis.Common (5.3)
Microsoft.CodeAnalysis.CSharp.Workspaces (5.3)
Humanizer.Core (>= 2.14.1)
Microsoft.CodeAnalysis.Analyzers (>= 3.11)
Microsoft.CodeAnalysis.Common (5.0)
Microsoft.CodeAnalysis.CSharp (5.0)
Microsoft.CodeAnalysis.Workspaces.Common (5.0)
Microsoft.CodeAnalysis.Analyzers (>= 5.3.0-2.25625.1)
Microsoft.CodeAnalysis.Common (5.3)
Microsoft.CodeAnalysis.CSharp (5.3)
Microsoft.CodeAnalysis.Workspaces.Common (5.3)
System.Composition (>= 9.0)
Microsoft.CodeAnalysis.VisualBasic (5.0)
Microsoft.CodeAnalysis.Analyzers (>= 3.11)
Microsoft.CodeAnalysis.Common (5.0)
Microsoft.CodeAnalysis.VisualBasic.Workspaces (5.0)
Microsoft.CodeAnalysis.VisualBasic (5.3)
Microsoft.CodeAnalysis.Analyzers (>= 5.3.0-2.25625.1)
Microsoft.CodeAnalysis.Common (5.3)
Microsoft.CodeAnalysis.VisualBasic.Workspaces (5.3)
Humanizer.Core (>= 2.14.1)
Microsoft.CodeAnalysis.Analyzers (>= 3.11)
Microsoft.CodeAnalysis.Common (5.0)
Microsoft.CodeAnalysis.VisualBasic (5.0)
Microsoft.CodeAnalysis.Workspaces.Common (5.0)
Microsoft.CodeAnalysis.Analyzers (>= 5.3.0-2.25625.1)
Microsoft.CodeAnalysis.Common (5.3)
Microsoft.CodeAnalysis.VisualBasic (5.3)
Microsoft.CodeAnalysis.Workspaces.Common (5.3)
System.Composition (>= 9.0)
Microsoft.CodeAnalysis.Workspaces.Common (5.0)
Microsoft.CodeAnalysis.Workspaces.Common (5.3)
Humanizer.Core (>= 2.14.1)
Microsoft.CodeAnalysis.Analyzers (>= 3.11)
Microsoft.CodeAnalysis.Common (5.0)
Microsoft.CodeAnalysis.Analyzers (>= 5.3.0-2.25625.1)
Microsoft.CodeAnalysis.Common (5.3)
System.Composition (>= 9.0)
Microsoft.CodeCoverage (18.5.1)
Microsoft.Extensions.ObjectPool (10.0.8)
Microsoft.NET.StringTools (18.4)
Microsoft.NET.StringTools (18.6.3)
Microsoft.NET.Test.Sdk (18.5.1)
Microsoft.CodeCoverage (>= 18.5.1)
Microsoft.TestPlatform.TestHost (>= 18.5.1)
@@ -97,7 +94,6 @@ NUGET
MSBuild.StructuredLogger (2.3.204)
Microsoft.Build.Framework (>= 17.5)
Microsoft.Build.Utilities.Core (>= 17.5)
NaturalSort.Extension (4.4.1)
Newtonsoft.Json (13.0.4)
NuGet.Versioning (7.6)
System.Buffers (4.6.1)

31
csharp/paket.main.bzl generated

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@@ -22,7 +22,6 @@
| [...]/csharp/tools/[...]/Microsoft.Win32.Primitives.dll |
| [...]/csharp/tools/[...]/Microsoft.Win32.Registry.dll |
| [...]/csharp/tools/[...]/Mono.Posix.NETStandard.dll |
| [...]/csharp/tools/[...]/NaturalSort.Extension.dll |
| [...]/csharp/tools/[...]/Newtonsoft.Json.dll |
| [...]/csharp/tools/[...]/NuGet.Versioning.dll |
| [...]/csharp/tools/[...]/StructuredLogger.dll |

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Improved call target resolution for ref-return properties and indexers.

View File

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

View File

@@ -766,7 +766,16 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr {
}
override Accessor getWriteTarget() {
this instanceof AssignableWrite and result = this.getProperty().getSetter()
this instanceof AssignableWrite and
exists(Property p | p = this.getProperty() |
result = p.getSetter()
or
result =
any(Getter g |
g = p.getGetter() and
g.getAnnotatedReturnType().isRef()
)
)
}
override Expr getArgument(int i) {
@@ -801,7 +810,16 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr {
}
override Accessor getWriteTarget() {
this instanceof AssignableWrite and result = this.getIndexer().getSetter()
this instanceof AssignableWrite and
exists(Indexer i | i = this.getIndexer() |
result = i.getSetter()
or
result =
any(Getter g |
g = i.getGetter() and
g.getAnnotatedReturnType().isRef()
)
)
}
override Expr getArgument(int i) {

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries
version: 1.7.4
version: 1.7.5-dev
groups:
- csharp
- queries

View File

@@ -227,7 +227,7 @@ returnTypes
| NullableRefTypes.cs:107:26:107:36 | ReturnsRef5 | readonly MyClass! |
| NullableRefTypes.cs:108:26:108:36 | ReturnsRef6 | readonly MyClass! |
| NullableRefTypes.cs:110:10:110:20 | Parameters1 | Void! |
| NullableRefTypes.cs:113:32:113:44 | get_RefProperty | MyClass! |
| NullableRefTypes.cs:113:32:113:44 | get_RefProperty | ref MyClass! |
| NullableRefTypes.cs:116:7:116:23 | <object initializer> | Void |
| NullableRefTypes.cs:116:7:116:23 | ToStringWithTypes | Void! |
| NullableRefTypes.cs:136:7:136:24 | <object initializer> | Void |

View File

@@ -1,4 +1,4 @@
class SBCS
class SBCS
{
string sbcs = "<22>";
string sbcs = "<22>";
}

View File

@@ -0,0 +1,4 @@
| indexers.cs:24:21:24:24 | Item | indexers.cs:62:22:62:29 | access to indexer | indexers.cs:26:13:26:15 | get_Item |
| indexers.cs:24:21:24:24 | Item | indexers.cs:65:25:65:32 | access to indexer | indexers.cs:34:13:34:15 | set_Item |
| indexers.cs:143:24:143:27 | Item | indexers.cs:156:13:156:16 | access to indexer | indexers.cs:145:13:145:15 | get_Item |
| indexers.cs:143:24:143:27 | Item | indexers.cs:157:21:157:24 | access to indexer | indexers.cs:145:13:145:15 | get_Item |

View File

@@ -0,0 +1,8 @@
import csharp
from IndexerCall ic, Indexer i, Accessor target
where
ic.getIndexer() = i and
ic.getTarget() = target and
i.fromSource()
select i, ic, target

View File

@@ -360,3 +360,57 @@ indexers.cs:
# 130| 4: [BlockStmt] {...}
# 130| 0: [ReturnStmt] return ...;
# 130| 0: [IntLiteral] 0
# 134| 5: [RefStruct] S
# 136| 6: [Field] x
# 136| -1: [TypeMention] int
# 138| 7: [InstanceConstructor] S
#-----| 2: (Parameters)
# 138| 0: [Parameter] v
# 138| -1: [TypeMention] int
# 139| 4: [BlockStmt] {...}
# 140| 0: [ExprStmt] ...;
# 140| 0: [AssignExpr] ... = ...
# 140| 0: [FieldAccess] access to field x
# 140| 1: [RefExpr] ref ...
# 140| 0: [ParameterAccess] access to parameter v
# 143| 8: [Indexer] Item
# 143| -1: [TypeMention] int
#-----| 1: (Parameters)
# 143| 0: [Parameter] i
# 143| -1: [TypeMention] int
# 145| 3: [Getter] get_Item
#-----| 2: (Parameters)
# 143| 0: [Parameter] i
# 145| 4: [BlockStmt] {...}
# 145| 0: [ReturnStmt] return ...;
# 145| 0: [RefExpr] ref ...
# 145| 0: [FieldAccess] access to field x
# 149| 6: [Class] TestRefReturns
# 151| 6: [Method] M
# 151| -1: [TypeMention] Void
# 152| 4: [BlockStmt] {...}
# 153| 0: [LocalVariableDeclStmt] ... ...;
# 153| 0: [LocalVariableDeclAndInitExpr] Int32 a = ...
# 153| -1: [TypeMention] int
# 153| 0: [LocalVariableAccess] access to local variable a
# 153| 1: [IntLiteral] 0
# 155| 1: [LocalVariableDeclStmt] ... ...;
# 155| 0: [LocalVariableDeclAndInitExpr] S s = ...
# 155| -1: [TypeMention] S
# 155| 0: [LocalVariableAccess] access to local variable s
# 155| 1: [ObjectCreation] object creation of type S
# 155| -1: [TypeMention] S
# 155| 0: [LocalVariableAccess] access to local variable a
# 156| 2: [ExprStmt] ...;
# 156| 0: [AssignExpr] ... = ...
# 156| 0: [IndexerCall] access to indexer
# 156| -1: [LocalVariableAccess] access to local variable s
# 156| 0: [IntLiteral] 0
# 156| 1: [IntLiteral] 1
# 157| 3: [LocalVariableDeclStmt] ... ...;
# 157| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
# 157| -1: [TypeMention] int
# 157| 0: [LocalVariableAccess] access to local variable x
# 157| 1: [IndexerCall] access to indexer
# 157| -1: [LocalVariableAccess] access to local variable s
# 157| 0: [IntLiteral] 0

View File

@@ -130,4 +130,31 @@ namespace Indexers
get { return 0; }
}
}
public ref struct S
{
private ref int x;
public S(ref int v)
{
x = ref v;
}
public ref int this[int i]
{
get { return ref x; }
}
}
public class TestRefReturns
{
public void M()
{
int a = 0;
S s = new S(ref a);
s[0] = 1;
var x = s[0];
}
}
}

View File

@@ -246,3 +246,50 @@ properties.cs:
# 133| 0: [FieldAccess] access to field Prop.field
# 133| 1: [ParameterAccess] access to parameter value
# 130| 7: [Field] Prop.field
# 137| 11: [RefStruct] S
# 139| 6: [Field] x
# 139| -1: [TypeMention] int
# 141| 7: [InstanceConstructor] S
#-----| 2: (Parameters)
# 141| 0: [Parameter] v
# 141| -1: [TypeMention] int
# 142| 4: [BlockStmt] {...}
# 143| 0: [ExprStmt] ...;
# 143| 0: [AssignExpr] ... = ...
# 143| 0: [FieldAccess] access to field x
# 143| 1: [RefExpr] ref ...
# 143| 0: [ParameterAccess] access to parameter v
# 146| 8: [Property] Prop
# 146| -1: [TypeMention] int
# 148| 3: [Getter] get_Prop
# 148| 4: [BlockStmt] {...}
# 148| 0: [ReturnStmt] return ...;
# 148| 0: [RefExpr] ref ...
# 148| 0: [FieldAccess] access to field x
# 152| 12: [Class] TestRefReturns
# 154| 6: [Method] M
# 154| -1: [TypeMention] Void
# 155| 4: [BlockStmt] {...}
# 156| 0: [LocalVariableDeclStmt] ... ...;
# 156| 0: [LocalVariableDeclAndInitExpr] Int32 a = ...
# 156| -1: [TypeMention] int
# 156| 0: [LocalVariableAccess] access to local variable a
# 156| 1: [IntLiteral] 0
# 158| 1: [LocalVariableDeclStmt] ... ...;
# 158| 0: [LocalVariableDeclAndInitExpr] S s = ...
# 158| -1: [TypeMention] S
# 158| 0: [LocalVariableAccess] access to local variable s
# 158| 1: [ObjectCreation] object creation of type S
# 158| -1: [TypeMention] S
# 158| 0: [LocalVariableAccess] access to local variable a
# 159| 2: [ExprStmt] ...;
# 159| 0: [AssignExpr] ... = ...
# 159| 0: [PropertyCall] access to property Prop
# 159| -1: [LocalVariableAccess] access to local variable s
# 159| 1: [IntLiteral] 1
# 160| 3: [LocalVariableDeclStmt] ... ...;
# 160| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
# 160| -1: [TypeMention] int
# 160| 0: [LocalVariableAccess] access to local variable x
# 160| 1: [PropertyCall] access to property Prop
# 160| -1: [LocalVariableAccess] access to local variable s

View File

@@ -1,5 +1,6 @@
| Prop.field |
| caption |
| next |
| x |
| y |
| z |

View File

@@ -0,0 +1,8 @@
| properties.cs:12:23:12:29 | Caption | properties.cs:29:13:29:28 | access to property Caption | properties.cs:17:13:17:15 | set_Caption |
| properties.cs:12:23:12:29 | Caption | properties.cs:30:24:30:39 | access to property Caption | properties.cs:15:13:15:15 | get_Caption |
| properties.cs:57:20:57:20 | X | properties.cs:61:13:61:13 | access to property X | properties.cs:57:37:57:39 | set_X |
| properties.cs:58:20:58:20 | Y | properties.cs:62:13:62:13 | access to property Y | properties.cs:58:37:58:39 | set_Y |
| properties.cs:70:28:70:28 | X | properties.cs:82:46:82:51 | access to property X | properties.cs:70:32:70:34 | get_X |
| properties.cs:71:28:71:28 | Y | properties.cs:83:39:83:44 | access to property Y | properties.cs:74:13:74:15 | set_Y |
| properties.cs:146:24:146:27 | Prop | properties.cs:159:13:159:18 | access to property Prop | properties.cs:148:13:148:15 | get_Prop |
| properties.cs:146:24:146:27 | Prop | properties.cs:160:21:160:26 | access to property Prop | properties.cs:148:13:148:15 | get_Prop |

View File

@@ -0,0 +1,8 @@
import csharp
from PropertyCall pc, Property p, Accessor target
where
pc.getProperty() = p and
pc.getTarget() = target and
p.fromSource()
select p, pc, target

View File

@@ -133,4 +133,31 @@ namespace Properties
set { field = value; }
}
}
public ref struct S
{
private ref int x;
public S(ref int v)
{
x = ref v;
}
public ref int Prop
{
get { return ref x; }
}
}
public class TestRefReturns
{
public void M()
{
int a = 0;
S s = new S(ref a);
s.Prop = 1;
var x = s.Prop;
}
}
}

View File

@@ -1,3 +1,2 @@
| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer |
| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer |
| Quality.cs:32:9:32:21 | access to indexer | Call without target $@. | Quality.cs:32:9:32:21 | access to indexer | access to indexer |

View File

@@ -9,6 +9,5 @@
| Quality.cs:23:9:23:30 | delegate call | Call without target $@. | Quality.cs:23:9:23:30 | delegate call | delegate call |
| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer |
| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer |
| Quality.cs:32:9:32:21 | access to indexer | Call without target $@. | Quality.cs:32:9:32:21 | access to indexer | access to indexer |
| Quality.cs:38:16:38:26 | access to property MyProperty2 | Call without target $@. | Quality.cs:38:16:38:26 | access to property MyProperty2 | access to property MyProperty2 |
| Quality.cs:50:20:50:26 | object creation of type T | Call without target $@. | Quality.cs:50:20:50:26 | object creation of type T | object creation of type T |

View File

@@ -29,7 +29,7 @@ public class Test
var slice = sp[..3]; // TODO: this is not an indexer call, but rather a `sp.Slice(0, 3)` call.
Span<byte> guidBytes = stackalloc byte[16];
guidBytes[08] = 1; // TODO: this indexer call has no target, because the target is a `ref` returning getter.
guidBytes[08] = 1;
new MyList([new(), new Test()]);
}

View File

@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries
version: 1.0.51
version: 1.0.52-dev
groups:
- go
- queries

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/go-queries
version: 1.6.4
version: 1.6.5-dev
groups:
- go
- queries

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/java-queries
version: 1.11.4
version: 1.11.5-dev
groups:
- java
- queries

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-all
version: 2.7.2
version: 2.7.3-dev
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-queries
version: 2.3.11
version: 2.3.12-dev
groups:
- javascript
- queries

View File

@@ -1,4 +1,4 @@
name: codeql/suite-helpers
version: 1.0.51
version: 1.0.52-dev
groups: shared
warnOnImplicitThis: true

View File

@@ -213,9 +213,11 @@ class ExprWithPointsTo extends Expr {
* Gets what this expression might "refer-to" in the given `context`.
*/
predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) {
this.getAFlowNode()
.(ControlFlowNodeWithPointsTo)
.refersTo(context, obj, cls, origin.getAFlowNode())
exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).refersTo(context, obj, cls, origin_)
)
}
/**
@@ -226,7 +228,11 @@ class ExprWithPointsTo extends Expr {
*/
pragma[nomagic]
predicate refersTo(Object obj, AstNode origin) {
this.getAFlowNode().(ControlFlowNodeWithPointsTo).refersTo(obj, origin.getAFlowNode())
exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).refersTo(obj, origin_)
)
}
/**
@@ -240,16 +246,22 @@ class ExprWithPointsTo extends Expr {
* in the given `context`.
*/
predicate pointsTo(Context context, Value value, AstNode origin) {
this.getAFlowNode()
.(ControlFlowNodeWithPointsTo)
.pointsTo(context, value, origin.getAFlowNode())
exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).pointsTo(context, value, origin_)
)
}
/**
* Holds if this expression might "point-to" to `value` which is from `origin`.
*/
predicate pointsTo(Value value, AstNode origin) {
this.getAFlowNode().(ControlFlowNodeWithPointsTo).pointsTo(value, origin.getAFlowNode())
exists(ControlFlowNode this_, ControlFlowNode origin_ |
this_.getNode() = this and origin_.getNode() = origin
|
this_.(ControlFlowNodeWithPointsTo).pointsTo(value, origin_)
)
}
/**
@@ -475,7 +487,10 @@ class FunctionMetricsWithPointsTo extends FunctionMetrics {
not non_coupling_method(result) and
exists(Call call | call.getScope() = this |
exists(FunctionObject callee | callee.getFunction() = result |
call.getAFlowNode().getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee)
exists(CallNode call_ |
call_.getNode() = call and
call_.getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee)
)
)
or
exists(Attribute a | call.getFunc() = a |

View File

@@ -64,7 +64,7 @@ private predicate jump_to_defn(ControlFlowNode use, Definition defn) {
private predicate preferred_jump_to_defn(Expr use, Definition def) {
not use instanceof ClassExpr and
not use instanceof FunctionExpr and
jump_to_defn(use.getAFlowNode(), def)
exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, def))
}
private predicate unique_jump_to_defn(Expr use, Definition def) {
@@ -452,7 +452,7 @@ private predicate self_parameter_jump_to_defn_attribute(
* This exists primarily for testing use `getPreferredDefinition()` instead.
*/
Definition getADefinition(Expr use) {
jump_to_defn(use.getAFlowNode(), result) and
exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, result)) and
not use instanceof Call and
not use.isArtificial() and
// Not the use itself

View File

@@ -0,0 +1,5 @@
---
category: deprecated
---
* The `AstNode.getAFlowNode()` predicate has been deprecated. Use `ControlFlowNode.getNode()` from the other direction instead: replace `e.getAFlowNode() = n` with `n.getNode() = e`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Simplified the internal predicates that detect `@staticmethod`, `@classmethod` and `@property` decorators to match the decorator's AST `Name` directly, rather than going through the CFG and requiring the name to resolve globally. Code that shadows these three builtin decorators at the module-scope will now be classified by the decorator name alone; in practice, shadowing these names is extremely rare and the call-graph results are unchanged.

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `Function.getAReturnValueFlowNode()` predicate has been deprecated. Bind a `Return` node explicitly instead — `exists(Return ret | ret.getScope() = f and n.getNode() = ret.getValue())`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.

View File

@@ -1,5 +1,5 @@
name: codeql/python-all
version: 7.1.2
version: 7.1.3-dev
groups: python
dbscheme: semmlecode.python.dbscheme
extractor: python

View File

@@ -16,21 +16,26 @@ abstract class AstNode extends AstNode_ {
/** Gets the scope that this node occurs in */
abstract Scope getScope();
/**
* Gets a flow node corresponding directly to this node.
* NOTE: For some statements and other purely syntactic elements,
* there may not be a `ControlFlowNode`
*/
cached
ControlFlowNode getAFlowNode() {
Stages::AST::ref() and
py_flow_bb_node(result, this, _, _)
}
/** Gets the location for this AST node */
cached
Location getLocation() { none() }
/**
* DEPRECATED: use `ControlFlowNode.getNode()` from the other direction instead;
* that is, replace `e.getAFlowNode() = n` with `n.getNode() = e`. This API is
* being removed to untangle the AST and CFG hierarchies in preparation for
* migrating the dataflow library off the legacy CFG.
*
* Gets a flow node corresponding directly to this node.
* NOTE: For some statements and other purely syntactic elements,
* there may not be a `ControlFlowNode`.
*/
cached
deprecated ControlFlowNode getAFlowNode() {
Stages::AST::ref() and
py_flow_bb_node(result, this, _, _)
}
/**
* Whether this syntactic element is artificial, that is it is generated
* by the compiler and is not present in the source

View File

@@ -28,7 +28,9 @@ class Expr extends Expr_, AstNode {
/** Whether this expression may have a side effect (as determined purely from its syntax) */
predicate hasSideEffects() {
/* If an exception raised by this expression handled, count that as a side effect */
this.getAFlowNode().getASuccessor().getNode() instanceof ExceptStmt
exists(ControlFlowNode n | n.getNode() = this |
n.getASuccessor().getNode() instanceof ExceptStmt
)
or
this.getASubExpression().hasSideEffects()
}
@@ -68,8 +70,6 @@ class Attribute extends Attribute_ {
/* syntax: Expr.name */
override Expr getASubExpression() { result = this.getObject() }
override AttrNode getAFlowNode() { result = super.getAFlowNode() }
/** Gets the name of this attribute. That is the `name` in `obj.name` */
string getName() { result = Attribute_.super.getAttr() }
@@ -96,8 +96,6 @@ class Subscript extends Subscript_ {
}
Expr getObject() { result = Subscript_.super.getValue() }
override SubscriptNode getAFlowNode() { result = super.getAFlowNode() }
}
/** A call expression, such as `func(...)` */
@@ -113,8 +111,6 @@ class Call extends Call_ {
override string toString() { result = this.getFunc().toString() + "()" }
override CallNode getAFlowNode() { result = super.getAFlowNode() }
/** Gets a tuple (*) argument of this call. */
Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() }
@@ -200,8 +196,6 @@ class IfExp extends IfExp_ {
override Expr getASubExpression() {
result = this.getTest() or result = this.getBody() or result = this.getOrelse()
}
override IfExprNode getAFlowNode() { result = super.getAFlowNode() }
}
/** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */
@@ -410,8 +404,6 @@ class PlaceHolder extends PlaceHolder_ {
override Expr getASubExpression() { none() }
override string toString() { result = "$" + this.getId() }
override NameNode getAFlowNode() { result = super.getAFlowNode() }
}
/** A tuple expression such as `( 1, 3, 5, 7, 9 )` */
@@ -478,8 +470,6 @@ class Name extends Name_ {
override string toString() { result = this.getId() }
override NameNode getAFlowNode() { result = super.getAFlowNode() }
override predicate isArtificial() {
/* Artificial variable names in comprehensions all start with "." */
this.getId().charAt(0) = "."
@@ -585,8 +575,6 @@ abstract class NameConstant extends Name, ImmutableLiteral {
override predicate isConstant() { any() }
override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() }
override predicate isArtificial() { none() }
}

View File

@@ -555,27 +555,27 @@ class DefinitionNode extends ControlFlowNode {
cached
DefinitionNode() {
Stages::AST::ref() and
exists(Assign a | a.getATarget().getAFlowNode() = this)
exists(Assign a | this.getNode() = a.getATarget())
or
exists(AssignExpr a | a.getTarget().getAFlowNode() = this)
exists(AssignExpr a | this.getNode() = a.getTarget())
or
exists(AnnAssign a | a.getTarget().getAFlowNode() = this and exists(a.getValue()))
exists(AnnAssign a | this.getNode() = a.getTarget() and exists(a.getValue()))
or
exists(Alias a | a.getAsname().getAFlowNode() = this)
exists(Alias a | this.getNode() = a.getAsname())
or
augstore(_, this)
or
// `x, y = 1, 2` where LHS is a combination of list or tuples
exists(Assign a | list_or_tuple_nested_element(a.getATarget()).getAFlowNode() = this)
exists(Assign a | this.getNode() = list_or_tuple_nested_element(a.getATarget()))
or
exists(For for | for.getTarget().getAFlowNode() = this)
exists(For for | this.getNode() = for.getTarget())
or
exists(Parameter param | this = param.asName().getAFlowNode() and exists(param.getDefault()))
exists(Parameter param | this.getNode() = param.asName() and exists(param.getDefault()))
}
/** flow node corresponding to the value assigned for the definition corresponding to this flow node */
ControlFlowNode getValue() {
result = assigned_value(this.getNode()).getAFlowNode() and
result.getNode() = assigned_value(this.getNode()) and
(
result.getBasicBlock().dominates(this.getBasicBlock())
or
@@ -584,7 +584,7 @@ class DefinitionNode extends ControlFlowNode {
// since the default value for a parameter is evaluated in the same basic block as
// the function definition, but the parameter belongs to the basic block of the function,
// there is no dominance relationship between the two.
exists(Parameter param | this = param.asName().getAFlowNode())
exists(Parameter param | this.getNode() = param.asName())
)
}
}
@@ -901,7 +901,7 @@ class ExceptFlowNode extends ControlFlowNode {
exists(ExceptStmt ex |
this.getBasicBlock().dominates(result.getBasicBlock()) and
ex = this.getNode() and
result = ex.getType().getAFlowNode()
result.getNode() = ex.getType()
)
}
@@ -913,7 +913,7 @@ class ExceptFlowNode extends ControlFlowNode {
exists(ExceptStmt ex |
this.getBasicBlock().dominates(result.getBasicBlock()) and
ex = this.getNode() and
result = ex.getName().getAFlowNode()
result.getNode() = ex.getName()
)
}
}
@@ -928,7 +928,7 @@ class ExceptGroupFlowNode extends ControlFlowNode {
*/
ControlFlowNode getType() {
this.getBasicBlock().dominates(result.getBasicBlock()) and
result = this.getNode().(ExceptGroupStmt).getType().getAFlowNode()
result.getNode() = this.getNode().(ExceptGroupStmt).getType()
}
/**
@@ -937,7 +937,7 @@ class ExceptGroupFlowNode extends ControlFlowNode {
*/
ControlFlowNode getName() {
this.getBasicBlock().dominates(result.getBasicBlock()) and
result = this.getNode().(ExceptGroupStmt).getName().getAFlowNode()
result.getNode() = this.getNode().(ExceptGroupStmt).getName()
}
}

View File

@@ -153,8 +153,16 @@ class Function extends Function_, Scope, AstNode {
override predicate contains(AstNode inner) { Scope.super.contains(inner) }
/** Gets a control flow node for a return value of this function */
ControlFlowNode getAReturnValueFlowNode() {
/**
* DEPRECATED: bind a `Return` node explicitly instead, e.g.
* `exists(Return ret | ret.getScope() = this and n.getNode() = ret.getValue())`.
* This API is being phased out together with `AstNode.getAFlowNode()` to
* untangle the AST and CFG hierarchies in preparation for migrating the
* dataflow library off the legacy CFG.
*
* Gets a control flow node for a return value of this function.
*/
deprecated ControlFlowNode getAReturnValueFlowNode() {
exists(Return ret |
ret.getScope() = this and
ret.getValue() = result.getNode()

View File

@@ -162,8 +162,6 @@ class ImportMember extends ImportMember_ {
string getImportedModuleName() {
result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName()
}
override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() }
}
/** An import statement */

View File

@@ -46,20 +46,23 @@ class SelfAttributeRead extends SelfAttribute {
}
predicate guardedByHasattr() {
exists(Variable var, ControlFlowNode n |
var.getAUse() = this.getObject().getAFlowNode() and
exists(Variable var, ControlFlowNode n, ControlFlowNode this_, ControlFlowNode obj_ |
this_.getNode() = this and obj_.getNode() = this.getObject()
|
var.getAUse() = obj_ and
hasattr(n, var.getAUse(), this.getName()) and
n.strictlyDominates(this.getAFlowNode())
n.strictlyDominates(this_)
)
}
pragma[noinline]
predicate locallyDefined() {
exists(SelfAttributeStore store |
this.getName() = store.getName() and
this.getScope() = store.getScope()
exists(SelfAttributeStore store, ControlFlowNode store_, ControlFlowNode this_ |
store_.getNode() = store and this_.getNode() = this
|
store.getAFlowNode().strictlyDominates(this.getAFlowNode())
this.getName() = store.getName() and
this.getScope() = store.getScope() and
store_.strictlyDominates(this_)
)
}
}

View File

@@ -5,24 +5,30 @@ private import semmle.python.dataflow.new.DataFlow
private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
exists(CompareNode cn | cn = g |
exists(ImmutableLiteral const, Cmpop op |
op = any(Eq eq) and branch = true
or
op = any(NotEq ne) and branch = false
exists(ImmutableLiteral const, Cmpop op, ControlFlowNode c |
c.getNode() = const and
(
op = any(Eq eq) and branch = true
or
op = any(NotEq ne) and branch = false
)
|
cn.operands(const.getAFlowNode(), op, node)
cn.operands(c, op, node)
or
cn.operands(node, op, const.getAFlowNode())
cn.operands(node, op, c)
)
or
exists(NameConstant const, Cmpop op |
op = any(Is is_) and branch = true
or
op = any(IsNot isn) and branch = false
exists(NameConstant const, Cmpop op, ControlFlowNode c |
c.getNode() = const and
(
op = any(Is is_) and branch = true
or
op = any(IsNot isn) and branch = false
)
|
cn.operands(const.getAFlowNode(), op, node)
cn.operands(c, op, node)
or
cn.operands(node, op, const.getAFlowNode())
cn.operands(node, op, c)
)
or
exists(IterableNode const_iterable, Cmpop op |

View File

@@ -228,7 +228,7 @@ private class ClassDefinitionAsAttrWrite extends AttrWrite, CfgNode {
override Node getValue() { result.asCfgNode() = node.getValue() }
override Node getObject() { result.asCfgNode() = cls.getAFlowNode() }
override Node getObject() { result.asCfgNode().getNode() = cls }
override ExprNode getAttributeNameExpr() { none() }

View File

@@ -256,9 +256,12 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
*/
overlay[local]
predicate isStaticmethod(Function func) {
exists(NameNode id | id.getId() = "staticmethod" and id.isGlobal() |
func.getADecorator() = id.getNode()
)
// The decorator is *syntactically* a `Name` "staticmethod" — we don't
// care which variable it resolves to. `staticmethod` is a builtin and
// is almost never shadowed in a module-level scope; even if a class
// redefines `staticmethod` in its body, the class body has not started
// executing yet at the decorator position, so Python uses the builtin.
func.getADecorator().(Name).getId() = "staticmethod"
}
/**
@@ -268,9 +271,9 @@ predicate isStaticmethod(Function func) {
*/
overlay[local]
predicate isClassmethod(Function func) {
exists(NameNode id | id.getId() = "classmethod" and id.isGlobal() |
func.getADecorator() = id.getNode()
)
// See `isStaticmethod` for the rationale for matching on the AST `Name`
// rather than going via the CFG and `isGlobal()`.
func.getADecorator().(Name).getId() = "classmethod"
or
exists(Class cls |
cls.getAMethod() = func and
@@ -285,9 +288,8 @@ predicate isClassmethod(Function func) {
/** Holds if the function `func` has a `property` decorator. */
overlay[local]
predicate hasPropertyDecorator(Function func) {
exists(NameNode id | id.getId() = "property" and id.isGlobal() |
func.getADecorator() = id.getNode()
)
// See `isStaticmethod` for the rationale for matching on the AST `Name`.
func.getADecorator().(Name).getId() = "property"
}
/**
@@ -1911,8 +1913,8 @@ abstract class ReturnNode extends Node {
class ExtractedReturnNode extends ReturnNode, CfgNode {
// See `TaintTrackingImplementation::returnFlowStep`
ExtractedReturnNode() {
node = any(Return ret).getValue().getAFlowNode() or
node = any(Yield yield).getAFlowNode()
node.getNode() = any(Return ret).getValue() or
node.getNode() = any(Yield yield)
}
override ReturnKind getKind() { any() }
@@ -1930,7 +1932,7 @@ class ExtractedReturnNode extends ReturnNode, CfgNode {
class YieldNodeInContextManagerFunction extends ReturnNode, CfgNode {
YieldNodeInContextManagerFunction() {
hasContextmanagerDecorator(node.getScope()) and
node = any(Yield yield).getValue().getAFlowNode()
node.getNode() = any(Yield yield).getValue()
}
override ReturnKind getKind() { any() }

View File

@@ -185,8 +185,8 @@ private predicate synthDictSplatArgumentNodeStoreStep(
*/
predicate yieldStoreStep(Node nodeFrom, Content c, Node nodeTo) {
exists(Yield yield |
nodeTo.asCfgNode() = yield.getAFlowNode() and
nodeFrom.asCfgNode() = yield.getValue().getAFlowNode() and
nodeTo.asCfgNode().getNode() = yield and
nodeFrom.asCfgNode().getNode() = yield.getValue() and
// TODO: Consider if this will also need to transfer dictionary content
// once dictionary comprehensions are supported.
c instanceof ListElementContent

View File

@@ -485,7 +485,7 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
/** Gets a node that reads this variable, excluding reads that happen through `from ... import *`. */
Node getALocalRead() {
result.asCfgNode() = var.getALoad().getAFlowNode() and
result.asCfgNode().getNode() = var.getALoad() and
not result.getScope() = mod
}

View File

@@ -9,7 +9,19 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.internal.ImportStar
private import semmle.python.dataflow.new.TypeTracking
private import semmle.python.dataflow.new.internal.DataFlowPrivate
private import semmle.python.essa.SsaDefinitions
/**
* Holds if `init` is a package's `__init__.py` and `var` is a global variable in
* `init` whose name matches a submodule of the package.
*
* Inlined from `SsaSource::init_module_submodule_defn` to avoid pulling
* `semmle.python.essa.SsaDefinitions` into the new dataflow stack.
*/
private predicate initModuleSubmoduleDefn(GlobalVariable var, Module init) {
init.isPackageInit() and
exists(init.getPackage().getSubModule(var.getId())) and
var.getScope() = init
}
/**
* Python modules and the way imports are resolved are... complicated. Here's a crash course in how
@@ -326,7 +338,7 @@ module ImportResolution {
// imported yet.
exists(string submodule, Module package, EssaVariable var |
submodule = var.getName() and
SsaSource::init_module_submodule_defn(var.getSourceVariable(), package.getEntryNode()) and
initModuleSubmoduleDefn(var.getSourceVariable(), package) and
m = getModuleFromName(package.getPackageName() + "." + submodule) and
result.asCfgNode() = var.getDefinition().(EssaNodeDefinition).getDefiningNode()
)

View File

@@ -94,8 +94,10 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
Node returnOf(Node callable, SummaryComponent return) {
return = FlowSummaryImpl::Private::SummaryComponent::return() and
// `result` should be the return value of a callable expression (lambda or function) referenced by `callable`
result.asCfgNode() =
callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getAReturnValueFlowNode()
exists(Return ret |
ret.getScope() = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope() and
result.asCfgNode().getNode() = ret.getValue()
)
}
// Relating callables to nodes

View File

@@ -61,7 +61,7 @@ private module CaptureInput implements Shared::InputSig<Location, Cfg::BasicBloc
class VariableWrite extends ControlFlowNode {
CapturedVariable v;
VariableWrite() { this = v.getAStore().getAFlowNode().(DefinitionNode).getValue() }
VariableWrite() { exists(DefinitionNode d | d.getNode() = v.getAStore() | this = d.getValue()) }
CapturedVariable getVariable() { result = v }
@@ -71,7 +71,7 @@ private module CaptureInput implements Shared::InputSig<Location, Cfg::BasicBloc
class VariableRead extends Expr {
CapturedVariable v;
VariableRead() { this = v.getALoad().getAFlowNode() }
VariableRead() { this.getNode() = v.getALoad() }
CapturedVariable getVariable() { result = v }
}

View File

@@ -448,8 +448,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
context = TNoParam() and
src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and
node.asCfgNode() = call and
retval.asCfgNode() =
any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue()
) and
edgeLabel = "return"
}
@@ -471,8 +470,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
this.callContexts(call, src, pyfunc, context, callee) and
retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and
node.asCfgNode() = call and
retval.asCfgNode() =
any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue()
) and
edgeLabel = "call"
}
@@ -716,8 +714,10 @@ private class EssaTaintTracking extends string instanceof TaintTracking::Configu
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
path.noAttribute()
|
assign.getValue().getAFlowNode() = srcnode.asCfgNode() and
depth = iterable_unpacking_descent(assign.getATarget().getAFlowNode(), defn.getDefiningNode()) and
srcnode.asCfgNode().getNode() = assign.getValue() and
exists(SequenceNode left_parent | left_parent.getNode() = assign.getATarget() |
depth = iterable_unpacking_descent(left_parent, defn.getDefiningNode())
) and
kind = taint_at_depth(srckind, depth)
)
}
@@ -964,7 +964,7 @@ private TaintKind taint_at_depth(SequenceKind parent_kind, int depth) {
* - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1
*/
int iterable_unpacking_descent(SequenceNode left_parent, ControlFlowNode left_defn) {
exists(Assign a | a.getATarget().getASubExpression*().getAFlowNode() = left_parent) and
exists(Assign a | left_parent.getNode() = a.getATarget().getASubExpression*()) and
left_parent.getAnElement() = left_defn and
// Handle `a, *b = some_iterable`
if left_defn instanceof StarredNode then result = 0 else result = 1

View File

@@ -56,7 +56,7 @@ module SsaSource {
predicate with_definition(Variable v, ControlFlowNode defn) {
exists(With with, Name var |
with.getOptionalVars() = var and
var.getAFlowNode() = defn
defn.getNode() = var
|
var = v.getAStore()
)
@@ -67,7 +67,7 @@ module SsaSource {
predicate pattern_capture_definition(Variable v, ControlFlowNode defn) {
exists(MatchCapturePattern capture, Name var |
capture.getVariable() = var and
var.getAFlowNode() = defn
defn.getNode() = var
|
var = v.getAStore()
)
@@ -78,7 +78,7 @@ module SsaSource {
predicate pattern_alias_definition(Variable v, ControlFlowNode defn) {
exists(MatchAsPattern pattern, Name var |
pattern.getAlias() = var and
var.getAFlowNode() = defn
defn.getNode() = var
|
var = v.getAStore()
)

View File

@@ -59,7 +59,7 @@ module Bottle {
override Parameter getARoutedParameter() { none() }
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node }
override Function getARequestHandler() { node.getNode() = result.getADecorator() }
}
}
@@ -73,7 +73,10 @@ module Bottle {
/** A response returned by a view callable. */
class BottleReturnResponse extends Http::Server::HttpResponse::Range {
BottleReturnResponse() {
this.asCfgNode() = any(View::ViewCallable vc).getAReturnValueFlowNode()
exists(Return ret |
ret.getScope() = any(View::ViewCallable vc) and
this.asCfgNode().getNode() = ret.getValue()
)
}
override DataFlow::Node getBody() { result = this }

View File

@@ -2872,7 +2872,10 @@ module PrivateDjango {
DataFlow::CfgNode
{
DjangoRedirectViewGetRedirectUrlReturn() {
node = any(GetRedirectUrlFunction f).getAReturnValueFlowNode()
exists(Return ret |
ret.getScope() = any(GetRedirectUrlFunction f) and
node.getNode() = ret.getValue()
)
}
override DataFlow::Node getRedirectLocation() { result = this }

View File

@@ -129,7 +129,7 @@ module FastApi {
result in [this.getArg(0), this.getArgByName("path")]
}
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node }
override Function getARequestHandler() { node.getNode() = result.getADecorator() }
override string getFramework() { result = "FastAPI" }
@@ -309,7 +309,10 @@ module FastApi {
FastApiRouteSetup routeSetup;
FastApiRequestHandlerReturn() {
node = routeSetup.getARequestHandler().getAReturnValueFlowNode()
exists(Return ret |
ret.getScope() = routeSetup.getARequestHandler() and
node.getNode() = ret.getValue()
)
}
override DataFlow::Node getBody() { result = this }

View File

@@ -371,7 +371,7 @@ module Flask {
result in [this.getArg(0), this.getArgByName("rule")]
}
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node }
override Function getARequestHandler() { node.getNode() = result.getADecorator() }
}
/**
@@ -536,7 +536,7 @@ module Flask {
FlaskRouteHandlerReturn() {
exists(Function routeHandler |
routeHandler = any(FlaskRouteSetup rs).getARequestHandler() and
node = routeHandler.getAReturnValueFlowNode() and
exists(Return ret | ret.getScope() = routeHandler and node.getNode() = ret.getValue()) and
not this instanceof Flask::Response::InstanceSource
)
}

View File

@@ -38,7 +38,7 @@ private module FlaskAdmin {
result in [this.getArg(0), this.getArgByName("url")]
}
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node }
override Function getARequestHandler() { node.getNode() = result.getADecorator() }
}
/**
@@ -71,7 +71,7 @@ private module FlaskAdmin {
override Function getARequestHandler() {
exists(Flask::FlaskViewClass cls |
cls.getADecorator().getAFlowNode() = node and
node.getNode() = cls.getADecorator() and
result = cls.getARequestHandler()
)
}

View File

@@ -166,7 +166,10 @@ module Pyramid {
/** A response returned by a view callable. */
private class PyramidReturnResponse extends Http::Server::HttpResponse::Range {
PyramidReturnResponse() {
this.asCfgNode() = any(View::ViewCallable vc).getAReturnValueFlowNode() and
exists(Return ret |
ret.getScope() = any(View::ViewCallable vc) and
this.asCfgNode().getNode() = ret.getValue()
) and
not this = instance()
}

View File

@@ -2254,8 +2254,9 @@ module StdlibPrivate {
DataFlow::CfgNode
{
WsgirefSimpleServerApplicationReturn() {
exists(WsgirefSimpleServerApplication requestHandler |
node = requestHandler.getAReturnValueFlowNode()
exists(WsgirefSimpleServerApplication requestHandler, Return ret |
ret.getScope() = requestHandler and
node.getNode() = ret.getValue()
)
}

View File

@@ -182,7 +182,10 @@ private module Twisted {
DataFlow::CfgNode
{
TwistedResourceRenderMethodReturn() {
this.asCfgNode() = any(TwistedResourceRenderMethod meth).getAReturnValueFlowNode()
exists(Return ret |
ret.getScope() = any(TwistedResourceRenderMethod meth) and
this.asCfgNode().getNode() = ret.getValue()
)
}
override DataFlow::Node getBody() { result = this }

View File

@@ -77,7 +77,7 @@ module Stages {
or
exists(any(AstExtended::AstNode n).getParentNode())
or
exists(any(AstExtended::AstNode n).getAFlowNode())
exists(PyFlow::ControlFlowNode cfg, AstExtended::AstNode n | cfg.getNode() = n)
or
exists(any(PyFlow::BasicBlock b).getImmediateDominator())
or

View File

@@ -56,8 +56,9 @@ abstract class CallableObjectInternal extends ObjectInternal {
/** A Python function. */
class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFunctionObject {
override Function getScope() {
exists(CallableExpr expr |
this = TPythonFunctionObject(expr.getAFlowNode()) and
exists(CallableExpr expr, ControlFlowNode exprCfg |
exprCfg.getNode() = expr and
this = TPythonFunctionObject(exprCfg) and
result = expr.getInnerScope()
)
}
@@ -80,11 +81,12 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
pragma[nomagic]
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
exists(Function func, ControlFlowNode rval, ControlFlowNode forigin |
exists(Function func, Return ret, ControlFlowNode rval, ControlFlowNode forigin |
func = this.getScope() and
callee.appliesToScope(func)
|
rval = func.getAReturnValueFlowNode() and
ret.getScope() = func and
rval.getNode() = ret.getValue() and
PointsToInternal::pointsTo(rval, callee, obj, forigin) and
origin = CfgOrigin::fromCfgNode(forigin)
)
@@ -160,10 +162,11 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
}
private BasicBlock blockReturningNone(Function func) {
exists(Return ret |
exists(Return ret, ControlFlowNode ret_ |
not exists(ret.getValue()) and
ret.getScope() = func and
result = ret.getAFlowNode().getBasicBlock()
ret_.getNode() = ret and
result = ret_.getBasicBlock()
)
}

View File

@@ -113,8 +113,9 @@ abstract class ClassObjectInternal extends ObjectInternal {
class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject {
/** Gets the scope for this Python class */
Class getScope() {
exists(ClassExpr expr |
this = TPythonClassObject(expr.getAFlowNode()) and
exists(ClassExpr expr, ControlFlowNode exprCfg |
exprCfg.getNode() = expr and
this = TPythonClassObject(exprCfg) and
result = expr.getInnerScope()
)
}

View File

@@ -745,7 +745,12 @@ class PythonFunctionValue extends FunctionValue {
override int maxParameters() { result = this.getScope().getMaxPositionalArguments() }
/** Gets a control flow node corresponding to a return statement in this function */
ControlFlowNode getAReturnedNode() { result = this.getScope().getAReturnValueFlowNode() }
ControlFlowNode getAReturnedNode() {
exists(Return ret |
ret.getScope() = this.getScope() and
result.getNode() = ret.getValue()
)
}
override ClassValue getARaisedType() { scope_raises(result, this.getScope()) }

View File

@@ -387,7 +387,7 @@ private PythonClassObjectInternal abcMetaClassObject() {
private predicate neither_class_nor_static_method(Function f) {
not exists(f.getADecorator())
or
exists(ControlFlowNode deco | deco = f.getADecorator().getAFlowNode() |
exists(ControlFlowNode deco | deco.getNode() = f.getADecorator() |
exists(ObjectInternal o | PointsToInternal::pointsTo(deco, _, o, _) |
o != ObjectInternal::staticMethod() and
o != ObjectInternal::classMethod()

View File

@@ -711,7 +711,7 @@ private module InterModulePointsTo {
ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin
) {
exists(string name, ImportExpr i |
i.getAFlowNode() = f and
f.getNode() = i and
i.getImportedModuleName() = name and
PointsToInternal::module_imported_as(value, name) and
origin = f and
@@ -2118,8 +2118,9 @@ module Types {
result.getBuiltin() = cls.getBuiltin().getBaseClass() and n = 0
or
exists(Class pycls | pycls = cls.(PythonClassObjectInternal).getScope() |
exists(ObjectInternal base |
PointsToInternal::pointsTo(pycls.getBase(n).getAFlowNode(), _, base, _)
exists(ObjectInternal base, ControlFlowNode baseNode |
baseNode.getNode() = pycls.getBase(n) and
PointsToInternal::pointsTo(baseNode, _, base, _)
|
result = base and base != ObjectInternal::unknown()
or
@@ -2223,7 +2224,10 @@ module Types {
}
private ControlFlowNode decorator_call_callee(PythonClassObjectInternal cls) {
result = cls.getScope().getADecorator().getAFlowNode().(CallNode).getFunction()
exists(CallNode deco |
deco.getNode() = cls.getScope().getADecorator() and
result = deco.getFunction()
)
}
private boolean has_six_add_metaclass(PythonClassObjectInternal cls) {
@@ -2262,7 +2266,7 @@ module Types {
}
private EssaVariable metaclass_var(Class cls) {
result.getASourceUse() = cls.getMetaClass().getAFlowNode()
result.getASourceUse().getNode() = cls.getMetaClass()
or
major_version() = 2 and
not exists(cls.getMetaClass()) and

View File

@@ -181,7 +181,7 @@ class ClassObject extends Object {
)
}
ControlFlowNode declaredMetaClass() { result = this.getPyClass().getMetaClass().getAFlowNode() }
ControlFlowNode declaredMetaClass() { result.getNode() = this.getPyClass().getMetaClass() }
/** Has type inference failed to compute the full class hierarchy for this class for the reason given. */
predicate failedInference(string reason) { Types::failedInference(this.theClass(), reason) }
@@ -195,8 +195,9 @@ class ClassObject extends Object {
* It is guaranteed that getProbableSingletonInstance() returns at most one Object for each ClassObject.
*/
Object getProbableSingletonInstance() {
exists(ControlFlowNodeWithPointsTo use, Expr origin |
use.refersTo(result, this, origin.getAFlowNode())
exists(ControlFlowNodeWithPointsTo use, Expr origin, ControlFlowNode origin_ |
origin_.getNode() = origin and
use.refersTo(result, this, origin_)
|
this.hasStaticallyUniqueInstance() and
/* Ensure that original expression will be executed only one. */

View File

@@ -427,7 +427,7 @@ class ExceptFlowNodeWithPointsTo extends ExceptFlowNode {
}
private ControlFlowNodeWithPointsTo element_from_tuple_objectapi(Object tuple) {
exists(Tuple t | t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode())
exists(Tuple t | t = tuple.getOrigin() and result.getNode() = t.getAnElt())
}
/**

View File

@@ -36,8 +36,8 @@ class RangeIterationVariableFact extends PointsToExtension {
RangeIterationVariableFact() {
exists(For f, ControlFlowNode iterable |
iterable.getBasicBlock().dominates(this.(ControlFlowNode).getBasicBlock()) and
f.getIter().getAFlowNode() = iterable and
f.getTarget().getAFlowNode() = this and
iterable.getNode() = f.getIter() and
this.(ControlFlowNode).getNode() = f.getTarget() and
exists(ObjectInternal range |
PointsTo::pointsTo(iterable, _, range, _) and
range.getClass() = ObjectInternal::builtin("range")

View File

@@ -137,7 +137,10 @@ class PyFunctionObject extends FunctionObject {
/** Gets a control flow node corresponding to the value of a return statement */
ControlFlowNodeWithPointsTo getAReturnedNode() {
result = this.getFunction().getAReturnValueFlowNode()
exists(Return ret |
ret.getScope() = this.getFunction() and
result.getNode() = ret.getValue()
)
}
override string descriptiveString() {
@@ -170,7 +173,7 @@ class PyFunctionObject extends FunctionObject {
predicate unconditionallyReturnsParameter(int n) {
exists(SsaVariable pvar |
exists(Parameter p | p = this.getFunction().getArg(n) |
p.asName().getAFlowNode() = pvar.getDefinition()
pvar.getDefinition().getNode() = p.asName()
) and
exists(NameNode rval |
rval = pvar.getAUse() and

View File

@@ -337,7 +337,7 @@ class TupleObject extends SequenceObject {
or
this instanceof TupleNode
or
exists(Function func | func.getVararg().getAFlowNode() = this)
exists(Function func | this.(ControlFlowNode).getNode() = func.getVararg())
}
}
@@ -352,7 +352,9 @@ module TupleObject {
}
class NonEmptyTupleObject extends TupleObject {
NonEmptyTupleObject() { exists(Function func | func.getVararg().getAFlowNode() = this) }
NonEmptyTupleObject() {
exists(Function func | this.(ControlFlowNode).getNode() = func.getVararg())
}
override boolean booleanValue() { result = true }
}

View File

@@ -48,9 +48,11 @@ class CheckClass extends ClassObject {
self_dict = sub.getObject()
or
/* Indirect assignment via temporary variable */
exists(SsaVariable v |
v.getAUse() = sub.getObject().getAFlowNode() and
v.getDefinition().(DefinitionNode).getValue() = self_dict.getAFlowNode()
exists(SsaVariable v, ControlFlowNode subObjCfg, ControlFlowNode selfDictCfg |
subObjCfg.getNode() = sub.getObject() and selfDictCfg.getNode() = self_dict
|
v.getAUse() = subObjCfg and
v.getDefinition().(DefinitionNode).getValue() = selfDictCfg
)
) and
a.getATarget() = sub and
@@ -62,9 +64,10 @@ class CheckClass extends ClassObject {
pragma[nomagic]
private predicate monkeyPatched(string name) {
exists(Attribute a |
exists(Attribute a, ControlFlowNode objCfg |
objCfg.getNode() = a.getObject() and
a.getCtx() instanceof Store and
PointsTo::points_to(a.getObject().getAFlowNode(), _, this, _, _) and
PointsTo::points_to(objCfg, _, this, _, _) and
a.getName() = name
)
}
@@ -84,9 +87,9 @@ class CheckClass extends ClassObject {
}
predicate interestingUndefined(SelfAttributeRead a) {
exists(string name | name = a.getName() |
exists(string name, ControlFlowNode aCfg | name = a.getName() and aCfg.getNode() = a |
this.interestingContext(a, name) and
not this.definedInBlock(a.getAFlowNode().getBasicBlock(), name)
not this.definedInBlock(aCfg.getBasicBlock(), name)
)
}
@@ -109,8 +112,9 @@ class CheckClass extends ClassObject {
pragma[nomagic]
private predicate definitionInBlock(BasicBlock b, string name) {
exists(SelfAttributeStore sa |
sa.getAFlowNode().getBasicBlock() = b and
exists(SelfAttributeStore sa, ControlFlowNode saCfg |
saCfg.getNode() = sa and
saCfg.getBasicBlock() = b and
sa.getName() = name and
sa.getClass() = this.getPyClass()
)

View File

@@ -15,7 +15,9 @@
import python
import semmle.python.ApiGraphs
predicate doesnt_reraise(ExceptStmt ex) { ex.getAFlowNode().getBasicBlock().reachesExit() }
predicate doesnt_reraise(ExceptStmt ex) {
exists(ControlFlowNode exCfg | exCfg.getNode() = ex | exCfg.getBasicBlock().reachesExit())
}
predicate catches_base_exception(ExceptStmt ex) {
ex.getType() = API::builtin("BaseException").getAValueReachableFromSource().asExpr()

View File

@@ -116,7 +116,7 @@ FunctionValue get_function_or_initializer(Value func_or_cls) {
predicate illegally_named_parameter_objectapi(Call call, Object func, string name) {
not func.isC() and
name = call.getANamedArgumentName() and
call.getAFlowNode() = get_a_call_objectapi(func) and
exists(ControlFlowNode callCfg | callCfg.getNode() = call | callCfg = get_a_call_objectapi(func)) and
not get_function_or_initializer_objectapi(func).isLegalArgumentName(name)
}
@@ -124,7 +124,7 @@ predicate illegally_named_parameter_objectapi(Call call, Object func, string nam
predicate illegally_named_parameter(Call call, Value func, string name) {
not func.isBuiltin() and
name = call.getANamedArgumentName() and
call.getAFlowNode() = get_a_call(func) and
exists(ControlFlowNode callCfg | callCfg.getNode() = call | callCfg = get_a_call(func)) and
not get_function_or_initializer(func).isLegalArgumentName(name)
}
@@ -146,7 +146,9 @@ predicate too_few_args_objectapi(Call call, Object callable, int limit) {
call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
or
callable instanceof ClassObject and
call.getAFlowNode() = get_a_call_objectapi(callable) and
exists(ControlFlowNode callCfg | callCfg.getNode() = call |
callCfg = get_a_call_objectapi(callable)
) and
limit = func.minParameters() - 1
)
}
@@ -172,7 +174,7 @@ predicate too_few_args(Call call, Value callable, int limit) {
call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
or
callable instanceof ClassValue and
call.getAFlowNode() = get_a_call(callable) and
exists(ControlFlowNode callCfg | callCfg.getNode() = call | callCfg = get_a_call(callable)) and
limit = func.minParameters() - 1
)
}
@@ -191,7 +193,9 @@ predicate too_many_args_objectapi(Call call, Object callable, int limit) {
call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1
or
callable instanceof ClassObject and
call.getAFlowNode() = get_a_call_objectapi(callable) and
exists(ControlFlowNode callCfg | callCfg.getNode() = call |
callCfg = get_a_call_objectapi(callable)
) and
limit = func.maxParameters() - 1
) and
positional_arg_count_for_call_objectapi(call, callable) > limit
@@ -211,7 +215,7 @@ predicate too_many_args(Call call, Value callable, int limit) {
call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1
or
callable instanceof ClassValue and
call.getAFlowNode() = get_a_call(callable) and
exists(ControlFlowNode callCfg | callCfg.getNode() = call | callCfg = get_a_call(callable)) and
limit = func.maxParameters() - 1
) and
positional_arg_count_for_call(call, callable) > limit

View File

@@ -36,11 +36,15 @@ where
exists(string s | dict_key(d, k1, s) and dict_key(d, k2, s) and k1 != k2) and
(
exists(BasicBlock b, int i1, int i2 |
k1.getAFlowNode() = b.getNode(i1) and
k2.getAFlowNode() = b.getNode(i2) and
b.getNode(i1).getNode() = k1 and
b.getNode(i2).getNode() = k2 and
i1 < i2
)
or
k1.getAFlowNode().getBasicBlock().strictlyDominates(k2.getAFlowNode().getBasicBlock())
exists(ControlFlowNode k1Cfg, ControlFlowNode k2Cfg |
k1Cfg.getNode() = k1 and k2Cfg.getNode() = k2
|
k1Cfg.getBasicBlock().strictlyDominates(k2Cfg.getBasicBlock())
)
)
select k1, "Dictionary key " + repr(k1) + " is subsequently $@.", k2, "overwritten"

View File

@@ -98,16 +98,18 @@ private predicate brace_pair(PossibleAdvancedFormatString fmt, int start, int en
}
private predicate advanced_format_call(Call format_expr, PossibleAdvancedFormatString fmt, int args) {
exists(CallNode call | call = format_expr.getAFlowNode() |
exists(CallNode call, ControlFlowNode fmtCfg |
call.getNode() = format_expr and fmtCfg.getNode() = fmt
|
call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(Value::named("format")) and
call.getArg(0).(ControlFlowNodeWithPointsTo).pointsTo(_, fmt.getAFlowNode()) and
call.getArg(0).(ControlFlowNodeWithPointsTo).pointsTo(_, fmtCfg) and
args = count(format_expr.getAnArg()) - 1
or
call.getFunction()
.(AttrNode)
.getObject("format")
.(ControlFlowNodeWithPointsTo)
.pointsTo(_, fmt.getAFlowNode()) and
.pointsTo(_, fmtCfg) and
args = count(format_expr.getAnArg())
)
}

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