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 name: codeql/actions-all
version: 0.4.37 version: 0.4.38-dev
library: true library: true
warnOnImplicitThis: true warnOnImplicitThis: true
dependencies: dependencies:

View File

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

View File

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

View File

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

View File

@@ -148,28 +148,3 @@ class UnknownLocation extends Location {
this.getFile().getAbsolutePath() = "" and locations_default(this, _, 0, 0, 0, 0) 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" } 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. * 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 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 if `f` is an instantiation of a function template `templateFunc`, or
* holds with `f = templateFunc` if `f` is not an instantiation of any function * 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`. */ /** Gets the fully templated version of `f`. */
Function getFullyTemplatedFunction(Function f) { private Function getFullyTemplatedFunctionOld(Function f) {
not f.isFromUninstantiatedTemplate(_) and not f.isFromUninstantiatedTemplate(_) and
( (
exists(Class c, Class templateClass, int i | 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. */ /** Prefixes `const` to `s` if `t` is const, or returns `s` otherwise. */
bindingset[s, t] bindingset[s, t]
private string withConst(string s, Type t) { private string withConst(string s, Type t) {
if t.isConst() then result = "const " + s else result = s 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] bindingset[s, t]
private string withVolatile(string s, Type t) { private string withVolatile(string s, Type t) {
if t.isVolatile() then result = "volatile " + s else result = s 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) { private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) {
// If there is a declaring type then we start by expanding the function templates // If there is a declaring type then we start by expanding the function templates
exists(Class template | exists(Class template |
isClassConstructedFrom(f.getDeclaringType(), template) and template = getFullyTemplatedClass(f.getDeclaringType()) and
remaining = getNumberOfSupportedClassTemplateArguments(template) and remaining = getNumberOfSupportedClassTemplateArguments(template) and
result = getTypeNameWithoutFunctionTemplates(f, n, 0) result = getTypeNameWithoutFunctionTemplates(f, n, 0)
) )
@@ -502,7 +574,7 @@ private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining
or or
exists(string mid, TypeTemplateParameter tp, Class template | exists(string mid, TypeTemplateParameter tp, Class template |
mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and
isClassConstructedFrom(f.getDeclaringType(), template) and template = getFullyTemplatedClass(f.getDeclaringType()) and
tp = getSupportedClassTemplateArgument(template, remaining) tp = getSupportedClassTemplateArgument(template, remaining)
| |
result = mid.replaceAll(tp.getName(), "class:" + remaining.toString()) result = mid.replaceAll(tp.getName(), "class:" + remaining.toString())

View File

@@ -1,59 +1,5 @@
import semmle.code.cpp.Type 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] pragma[noinline]
private @mangledname getClassMangledName(@usertype c) { private @mangledname getClassMangledName(@usertype c) {
isClass(c) and isClass(c) and
@@ -103,10 +49,7 @@ private module Cached {
@usertype resolveClass(@usertype c) { @usertype resolveClass(@usertype c) {
hasCompleteTwin(c, result) hasCompleteTwin(c, result)
or or
oldHasCompleteTwin(c, result)
or
not hasCompleteTwin(c, _) and not hasCompleteTwin(c, _) and
not oldHasCompleteTwin(c, _) and
result = c result = c
} }

View File

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

View File

@@ -51,13 +51,16 @@ models
| 50 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | | 50 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
| 51 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | | 51 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
| 52 | Summary: ; ; false; ymlStepManual_with_body; ; ; 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 | | 53 | Summary: ; TemplateClass1; true; templateFunction2<U,V>; (U,V); ; Argument[1]; ReturnValue; value; manual |
| 54 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | | 54 | Summary: ; TemplateClass1<T>; false; templateFunction<U>; (T,U); ; Argument[0]; ReturnValue; value; manual |
| 55 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | | 55 | Summary: ; TemplateClass2<T,U>; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual |
| 56 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | | 56 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual |
| 57 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; 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 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: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: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 | | 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: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: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: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 | | 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:56 | | 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:53 | | 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:54 | | 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:55 | | 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: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: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: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: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: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: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: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: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: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: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: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: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 | | | 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: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: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: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: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: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: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: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: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 | | | 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: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: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: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: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: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 | | | 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:11:118:42 | call to callWithNonTypeTemplate | semmle.label | call to callWithNonTypeTemplate |
| test.cpp:118:44:118:44 | *x | semmle.label | *x | | test.cpp:118:44:118:44 | *x | semmle.label | *x |
| test.cpp:119:10:119:11 | y2 | semmle.label | y2 | | 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 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: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 | | 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: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: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: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: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: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 | | 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

@@ -19,3 +19,6 @@ extensions:
- ["", "", False, "ymlStepGenerated_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] - ["", "", False, "ymlStepGenerated_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["", "", False, "callWithArgument", "", "", "Argument[1]", "Argument[0].Parameter[0]", "value", "manual"] - ["", "", 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:89:11:89:11 | y | test-sink |
| test.cpp:116:10:116:11 | y1 | test-sink | | test.cpp:116:10:116:11 | y1 | test-sink |
| test.cpp:119:10:119:11 | y2 | 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:56:8:56:16 | call to ymlSource | local |
| test.cpp:94:10:94:18 | 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: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:22:15:22:29 | *call to GetCommandLineA | local |
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | local | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | local |
| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | 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); int y2 = callWithNonTypeTemplate<int, 10>(x);
ymlSink(y2); // $ ir 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: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: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:147:12:147:23 | basic_string | 0 | const class:2 & |
| stl.h:149:33:149:44 | basic_string | 0 | const class:0 * | | stl.h:148:3:148:14 | basic_string | 0 | const class:0 * |
| stl.h:149:33:149:44 | basic_string | 1 | const class:2 & | | stl.h:148:3:148:14 | basic_string | 1 | const class:2 & |
| stl.h:151:16:151:20 | c_str | 0 | func:0 | | stl.h:149:33:149:44 | basic_string | 0 | func:0 |
| stl.h:151:16:151:20 | c_str | 1 | func:0 | | stl.h:149:33:149:44 | basic_string | 1 | func:0 |
| stl.h:151:16:151:20 | c_str | 2 | const class:2 & | | 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:173:13:173:22 | operator[] | 0 | size_type |
| stl.h:175:13:175:14 | at | 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 | const func:0 & |
| stl.h:176:35:176:44 | operator+= | 0 | size_type | | stl.h:176:35:176:44 | operator+= | 0 | const func:0 & |
| stl.h:177:17:177:26 | 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 class:0 * | | stl.h:178:17:178:22 | append | 0 | const basic_string & |
| stl.h:179:17:179: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 | const class:0 * | | stl.h:180:17:180:22 | append | 0 | size_type |
| stl.h:181:47:181:52 | append | 0 | size_type | | stl.h:180:17:180:22 | append | 1 | class:0 |
| stl.h:181:47:181:52 | append | 1 | class:0 | | stl.h:181:47:181:52 | append | 0 | func:0 |
| stl.h:182:17:182:22 | assign | 0 | func:0 | | stl.h:181:47:181:52 | append | 1 | func:0 |
| stl.h:182:17:182:22 | assign | 1 | func:0 | | stl.h:182:17:182:22 | assign | 0 | const basic_string & |
| stl.h:183:17:183:22 | assign | 0 | const basic_string & | | stl.h:183:17:183:22 | assign | 0 | size_type |
| stl.h:184:47:184:52 | assign | 0 | size_type | | stl.h:183:17:183:22 | assign | 1 | class:0 |
| stl.h:184:47:184:52 | assign | 1 | class:0 | | stl.h:184:47:184:52 | assign | 0 | func:0 |
| stl.h:185:17:185:22 | insert | 0 | func:0 | | stl.h:184:47:184:52 | assign | 1 | func:0 |
| stl.h:185:17:185:22 | insert | 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 | 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 | 0 | size_type |
| stl.h:187:17:187:22 | insert | 1 | size_type | | stl.h:187:17:187:22 | insert | 1 | const class:0 * |
| stl.h:187:17:187:22 | insert | 2 | class:0 | | stl.h:188:12:188:17 | insert | 0 | const_iterator |
| stl.h:188:12:188:17 | insert | 0 | size_type | | stl.h:188:12:188:17 | insert | 1 | size_type |
| stl.h:188:12:188:17 | insert | 1 | const class:0 * | | 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 | 0 | const_iterator |
| stl.h:189:42:189:47 | insert | 1 | size_type | | stl.h:189:42:189:47 | insert | 1 | func:0 |
| stl.h:189:42:189:47 | insert | 2 | class:0 | | stl.h:189:42:189:47 | insert | 2 | func:0 |
| stl.h:190:17:190:23 | replace | 0 | const_iterator | | stl.h:190:17:190:23 | replace | 0 | size_type |
| stl.h:190:17:190:23 | replace | 1 | func:0 | | stl.h:190:17:190:23 | replace | 1 | size_type |
| stl.h:190:17:190:23 | replace | 2 | func:0 | | 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 | 0 | size_type |
| stl.h:191:17:191:23 | replace | 1 | 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:191:17:191:23 | replace | 2 | size_type |
| stl.h:192:13:192:16 | copy | 0 | 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 | 1 | size_type |
| stl.h:192:13:192:16 | copy | 2 | size_type | | stl.h:192:13:192:16 | copy | 2 | size_type |
| stl.h:192:13:192:16 | copy | 3 | class:0 | | stl.h:194:16:194:21 | substr | 0 | size_type |
| stl.h:193:8:193:12 | clear | 0 | class:0 * | | stl.h:194:16:194:21 | substr | 1 | size_type |
| stl.h:193:8:193:12 | clear | 1 | size_type | | stl.h:195:8:195:11 | swap | 0 | basic_string & |
| 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:198:94:198:102 | operator+ | 0 | const 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:198:94:198:102 | operator+ | 1 | const basic_string & |
| stl.h:199:94:199:102 | operator+ | 0 | 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: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<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: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 | 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 | 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<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: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: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: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> | | 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). // Find the (possibly unbound) original extension method that maps to this implementation (if any).
var unboundDeclaration = extensions.SelectMany(e => e.GetMembers()) var unboundDeclaration = extensions.SelectMany(e => e.GetMembers())
.OfType<IMethodSymbol>() .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(); var isFullyConstructed = method.IsBoundGenericMethod();
if (isFullyConstructed && unboundDeclaration?.ContainingType is INamedTypeSymbol extensionType) if (isFullyConstructed && unboundDeclaration?.ContainingType is INamedTypeSymbol extensionType)

View File

@@ -69,6 +69,7 @@ namespace Semmle.Extraction.CSharp.Entities
} }
Overrides(trapFile); Overrides(trapFile);
ExtractRefReturn(trapFile, Symbol, this);
if (Symbol.FromSource() && !HasBody) 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 # behave like nuget in choosing transitive dependency versions
strategy: max strategy: max
nuget Basic.CompilerLog.Util 0.9.25 nuget Basic.CompilerLog.Util 0.9.39
nuget Mono.Posix.NETStandard nuget Mono.Posix.NETStandard
nuget Newtonsoft.Json nuget Newtonsoft.Json
nuget NuGet.Versioning nuget NuGet.Versioning
@@ -12,7 +12,7 @@ nuget xunit
nuget xunit.runner.visualstudio nuget xunit.runner.visualstudio
nuget xunit.runner.utility nuget xunit.runner.utility
nuget Microsoft.NET.Test.Sdk nuget Microsoft.NET.Test.Sdk
nuget Microsoft.CodeAnalysis.CSharp 5.0.0 nuget Microsoft.CodeAnalysis.CSharp 5.3.0
nuget Microsoft.CodeAnalysis 5.0.0 nuget Microsoft.CodeAnalysis 5.3.0
nuget Microsoft.Build 18.0.2 nuget Microsoft.Build 18.6.3
nuget Microsoft.VisualStudio.SolutionPersistence nuget Microsoft.VisualStudio.SolutionPersistence

100
csharp/paket.lock generated
View File

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

View File

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

View File

@@ -22,7 +22,6 @@
| [...]/csharp/tools/[...]/Microsoft.Win32.Primitives.dll | | [...]/csharp/tools/[...]/Microsoft.Win32.Primitives.dll |
| [...]/csharp/tools/[...]/Microsoft.Win32.Registry.dll | | [...]/csharp/tools/[...]/Microsoft.Win32.Registry.dll |
| [...]/csharp/tools/[...]/Mono.Posix.NETStandard.dll | | [...]/csharp/tools/[...]/Mono.Posix.NETStandard.dll |
| [...]/csharp/tools/[...]/NaturalSort.Extension.dll |
| [...]/csharp/tools/[...]/Newtonsoft.Json.dll | | [...]/csharp/tools/[...]/Newtonsoft.Json.dll |
| [...]/csharp/tools/[...]/NuGet.Versioning.dll | | [...]/csharp/tools/[...]/NuGet.Versioning.dll |
| [...]/csharp/tools/[...]/StructuredLogger.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 name: codeql/csharp-all
version: 6.0.2 version: 6.0.3-dev
groups: csharp groups: csharp
dbscheme: semmlecode.csharp.dbscheme dbscheme: semmlecode.csharp.dbscheme
extractor: csharp extractor: csharp

View File

@@ -766,7 +766,16 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr {
} }
override Accessor getWriteTarget() { 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) { override Expr getArgument(int i) {
@@ -801,7 +810,16 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr {
} }
override Accessor getWriteTarget() { 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) { override Expr getArgument(int i) {

View File

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

View File

@@ -227,7 +227,7 @@ returnTypes
| NullableRefTypes.cs:107:26:107:36 | ReturnsRef5 | readonly MyClass! | | NullableRefTypes.cs:107:26:107:36 | ReturnsRef5 | readonly MyClass! |
| NullableRefTypes.cs:108:26:108:36 | ReturnsRef6 | readonly MyClass! | | NullableRefTypes.cs:108:26:108:36 | ReturnsRef6 | readonly MyClass! |
| NullableRefTypes.cs:110:10:110:20 | Parameters1 | Void! | | 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 | <object initializer> | Void |
| NullableRefTypes.cs:116:7:116:23 | ToStringWithTypes | Void! | | NullableRefTypes.cs:116:7:116:23 | ToStringWithTypes | Void! |
| NullableRefTypes.cs:136:7:136:24 | <object initializer> | 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| 4: [BlockStmt] {...}
# 130| 0: [ReturnStmt] return ...; # 130| 0: [ReturnStmt] return ...;
# 130| 0: [IntLiteral] 0 # 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; } 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| 0: [FieldAccess] access to field Prop.field
# 133| 1: [ParameterAccess] access to parameter value # 133| 1: [ParameterAccess] access to parameter value
# 130| 7: [Field] Prop.field # 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 | | Prop.field |
| caption | | caption |
| next | | next |
| x |
| y | | y |
| z | | 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; } 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: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: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: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: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: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: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 | | 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. 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]; 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()]); new MyList([new(), new Test()]);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -213,9 +213,11 @@ class ExprWithPointsTo extends Expr {
* Gets what this expression might "refer-to" in the given `context`. * Gets what this expression might "refer-to" in the given `context`.
*/ */
predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) { predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) {
this.getAFlowNode() exists(ControlFlowNode this_, ControlFlowNode origin_ |
.(ControlFlowNodeWithPointsTo) this_.getNode() = this and origin_.getNode() = origin
.refersTo(context, obj, cls, origin.getAFlowNode()) |
this_.(ControlFlowNodeWithPointsTo).refersTo(context, obj, cls, origin_)
)
} }
/** /**
@@ -226,7 +228,11 @@ class ExprWithPointsTo extends Expr {
*/ */
pragma[nomagic] pragma[nomagic]
predicate refersTo(Object obj, AstNode origin) { 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`. * in the given `context`.
*/ */
predicate pointsTo(Context context, Value value, AstNode origin) { predicate pointsTo(Context context, Value value, AstNode origin) {
this.getAFlowNode() exists(ControlFlowNode this_, ControlFlowNode origin_ |
.(ControlFlowNodeWithPointsTo) this_.getNode() = this and origin_.getNode() = origin
.pointsTo(context, value, origin.getAFlowNode()) |
this_.(ControlFlowNodeWithPointsTo).pointsTo(context, value, origin_)
)
} }
/** /**
* Holds if this expression might "point-to" to `value` which is from `origin`. * Holds if this expression might "point-to" to `value` which is from `origin`.
*/ */
predicate pointsTo(Value value, AstNode 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 not non_coupling_method(result) and
exists(Call call | call.getScope() = this | exists(Call call | call.getScope() = this |
exists(FunctionObject callee | callee.getFunction() = result | 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 or
exists(Attribute a | call.getFunc() = a | 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) { private predicate preferred_jump_to_defn(Expr use, Definition def) {
not use instanceof ClassExpr and not use instanceof ClassExpr and
not use instanceof FunctionExpr 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) { 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. * This exists primarily for testing use `getPreferredDefinition()` instead.
*/ */
Definition getADefinition(Expr use) { 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 instanceof Call and
not use.isArtificial() and not use.isArtificial() and
// Not the use itself // 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 name: codeql/python-all
version: 7.1.2 version: 7.1.3-dev
groups: python groups: python
dbscheme: semmlecode.python.dbscheme dbscheme: semmlecode.python.dbscheme
extractor: python extractor: python

View File

@@ -16,21 +16,26 @@ abstract class AstNode extends AstNode_ {
/** Gets the scope that this node occurs in */ /** Gets the scope that this node occurs in */
abstract Scope getScope(); 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 */ /** Gets the location for this AST node */
cached cached
Location getLocation() { none() } 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 * Whether this syntactic element is artificial, that is it is generated
* by the compiler and is not present in the source * 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) */ /** Whether this expression may have a side effect (as determined purely from its syntax) */
predicate hasSideEffects() { predicate hasSideEffects() {
/* If an exception raised by this expression handled, count that as a side effect */ /* 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 or
this.getASubExpression().hasSideEffects() this.getASubExpression().hasSideEffects()
} }
@@ -68,8 +70,6 @@ class Attribute extends Attribute_ {
/* syntax: Expr.name */ /* syntax: Expr.name */
override Expr getASubExpression() { result = this.getObject() } 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` */ /** Gets the name of this attribute. That is the `name` in `obj.name` */
string getName() { result = Attribute_.super.getAttr() } string getName() { result = Attribute_.super.getAttr() }
@@ -96,8 +96,6 @@ class Subscript extends Subscript_ {
} }
Expr getObject() { result = Subscript_.super.getValue() } Expr getObject() { result = Subscript_.super.getValue() }
override SubscriptNode getAFlowNode() { result = super.getAFlowNode() }
} }
/** A call expression, such as `func(...)` */ /** A call expression, such as `func(...)` */
@@ -113,8 +111,6 @@ class Call extends Call_ {
override string toString() { result = this.getFunc().toString() + "()" } override string toString() { result = this.getFunc().toString() + "()" }
override CallNode getAFlowNode() { result = super.getAFlowNode() }
/** Gets a tuple (*) argument of this call. */ /** Gets a tuple (*) argument of this call. */
Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() } Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() }
@@ -200,8 +196,6 @@ class IfExp extends IfExp_ {
override Expr getASubExpression() { override Expr getASubExpression() {
result = this.getTest() or result = this.getBody() or result = this.getOrelse() 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` */ /** 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 Expr getASubExpression() { none() }
override string toString() { result = "$" + this.getId() } override string toString() { result = "$" + this.getId() }
override NameNode getAFlowNode() { result = super.getAFlowNode() }
} }
/** A tuple expression such as `( 1, 3, 5, 7, 9 )` */ /** 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 string toString() { result = this.getId() }
override NameNode getAFlowNode() { result = super.getAFlowNode() }
override predicate isArtificial() { override predicate isArtificial() {
/* Artificial variable names in comprehensions all start with "." */ /* Artificial variable names in comprehensions all start with "." */
this.getId().charAt(0) = "." this.getId().charAt(0) = "."
@@ -585,8 +575,6 @@ abstract class NameConstant extends Name, ImmutableLiteral {
override predicate isConstant() { any() } override predicate isConstant() { any() }
override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() }
override predicate isArtificial() { none() } override predicate isArtificial() { none() }
} }

View File

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

View File

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

View File

@@ -46,20 +46,23 @@ class SelfAttributeRead extends SelfAttribute {
} }
predicate guardedByHasattr() { predicate guardedByHasattr() {
exists(Variable var, ControlFlowNode n | exists(Variable var, ControlFlowNode n, ControlFlowNode this_, ControlFlowNode obj_ |
var.getAUse() = this.getObject().getAFlowNode() and this_.getNode() = this and obj_.getNode() = this.getObject()
|
var.getAUse() = obj_ and
hasattr(n, var.getAUse(), this.getName()) and hasattr(n, var.getAUse(), this.getName()) and
n.strictlyDominates(this.getAFlowNode()) n.strictlyDominates(this_)
) )
} }
pragma[noinline] pragma[noinline]
predicate locallyDefined() { predicate locallyDefined() {
exists(SelfAttributeStore store | exists(SelfAttributeStore store, ControlFlowNode store_, ControlFlowNode this_ |
this.getName() = store.getName() and store_.getNode() = store and this_.getNode() = this
this.getScope() = store.getScope()
| |
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) { private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
exists(CompareNode cn | cn = g | exists(CompareNode cn | cn = g |
exists(ImmutableLiteral const, Cmpop op | exists(ImmutableLiteral const, Cmpop op, ControlFlowNode c |
op = any(Eq eq) and branch = true c.getNode() = const and
or (
op = any(NotEq ne) and branch = false 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 or
cn.operands(node, op, const.getAFlowNode()) cn.operands(node, op, c)
) )
or or
exists(NameConstant const, Cmpop op | exists(NameConstant const, Cmpop op, ControlFlowNode c |
op = any(Is is_) and branch = true c.getNode() = const and
or (
op = any(IsNot isn) and branch = false 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 or
cn.operands(node, op, const.getAFlowNode()) cn.operands(node, op, c)
) )
or or
exists(IterableNode const_iterable, Cmpop op | 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 getValue() { result.asCfgNode() = node.getValue() }
override Node getObject() { result.asCfgNode() = cls.getAFlowNode() } override Node getObject() { result.asCfgNode().getNode() = cls }
override ExprNode getAttributeNameExpr() { none() } override ExprNode getAttributeNameExpr() { none() }

View File

@@ -256,9 +256,12 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
*/ */
overlay[local] overlay[local]
predicate isStaticmethod(Function func) { predicate isStaticmethod(Function func) {
exists(NameNode id | id.getId() = "staticmethod" and id.isGlobal() | // The decorator is *syntactically* a `Name` "staticmethod" — we don't
func.getADecorator() = id.getNode() // 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] overlay[local]
predicate isClassmethod(Function func) { predicate isClassmethod(Function func) {
exists(NameNode id | id.getId() = "classmethod" and id.isGlobal() | // See `isStaticmethod` for the rationale for matching on the AST `Name`
func.getADecorator() = id.getNode() // rather than going via the CFG and `isGlobal()`.
) func.getADecorator().(Name).getId() = "classmethod"
or or
exists(Class cls | exists(Class cls |
cls.getAMethod() = func and cls.getAMethod() = func and
@@ -285,9 +288,8 @@ predicate isClassmethod(Function func) {
/** Holds if the function `func` has a `property` decorator. */ /** Holds if the function `func` has a `property` decorator. */
overlay[local] overlay[local]
predicate hasPropertyDecorator(Function func) { predicate hasPropertyDecorator(Function func) {
exists(NameNode id | id.getId() = "property" and id.isGlobal() | // See `isStaticmethod` for the rationale for matching on the AST `Name`.
func.getADecorator() = id.getNode() func.getADecorator().(Name).getId() = "property"
)
} }
/** /**
@@ -1911,8 +1913,8 @@ abstract class ReturnNode extends Node {
class ExtractedReturnNode extends ReturnNode, CfgNode { class ExtractedReturnNode extends ReturnNode, CfgNode {
// See `TaintTrackingImplementation::returnFlowStep` // See `TaintTrackingImplementation::returnFlowStep`
ExtractedReturnNode() { ExtractedReturnNode() {
node = any(Return ret).getValue().getAFlowNode() or node.getNode() = any(Return ret).getValue() or
node = any(Yield yield).getAFlowNode() node.getNode() = any(Yield yield)
} }
override ReturnKind getKind() { any() } override ReturnKind getKind() { any() }
@@ -1930,7 +1932,7 @@ class ExtractedReturnNode extends ReturnNode, CfgNode {
class YieldNodeInContextManagerFunction extends ReturnNode, CfgNode { class YieldNodeInContextManagerFunction extends ReturnNode, CfgNode {
YieldNodeInContextManagerFunction() { YieldNodeInContextManagerFunction() {
hasContextmanagerDecorator(node.getScope()) and hasContextmanagerDecorator(node.getScope()) and
node = any(Yield yield).getValue().getAFlowNode() node.getNode() = any(Yield yield).getValue()
} }
override ReturnKind getKind() { any() } override ReturnKind getKind() { any() }

View File

@@ -185,8 +185,8 @@ private predicate synthDictSplatArgumentNodeStoreStep(
*/ */
predicate yieldStoreStep(Node nodeFrom, Content c, Node nodeTo) { predicate yieldStoreStep(Node nodeFrom, Content c, Node nodeTo) {
exists(Yield yield | exists(Yield yield |
nodeTo.asCfgNode() = yield.getAFlowNode() and nodeTo.asCfgNode().getNode() = yield and
nodeFrom.asCfgNode() = yield.getValue().getAFlowNode() and nodeFrom.asCfgNode().getNode() = yield.getValue() and
// TODO: Consider if this will also need to transfer dictionary content // TODO: Consider if this will also need to transfer dictionary content
// once dictionary comprehensions are supported. // once dictionary comprehensions are supported.
c instanceof ListElementContent 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 *`. */ /** Gets a node that reads this variable, excluding reads that happen through `from ... import *`. */
Node getALocalRead() { Node getALocalRead() {
result.asCfgNode() = var.getALoad().getAFlowNode() and result.asCfgNode().getNode() = var.getALoad() and
not result.getScope() = mod 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.internal.ImportStar
private import semmle.python.dataflow.new.TypeTracking private import semmle.python.dataflow.new.TypeTracking
private import semmle.python.dataflow.new.internal.DataFlowPrivate 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 * 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. // imported yet.
exists(string submodule, Module package, EssaVariable var | exists(string submodule, Module package, EssaVariable var |
submodule = var.getName() and 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 m = getModuleFromName(package.getPackageName() + "." + submodule) and
result.asCfgNode() = var.getDefinition().(EssaNodeDefinition).getDefiningNode() result.asCfgNode() = var.getDefinition().(EssaNodeDefinition).getDefiningNode()
) )

View File

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

View File

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

View File

@@ -448,8 +448,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
context = TNoParam() and context = TNoParam() and
src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and
node.asCfgNode() = call and node.asCfgNode() = call and
retval.asCfgNode() = retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue()
any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
) and ) and
edgeLabel = "return" edgeLabel = "return"
} }
@@ -471,8 +470,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi
this.callContexts(call, src, pyfunc, context, callee) and this.callContexts(call, src, pyfunc, context, callee) and
retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and
node.asCfgNode() = call and node.asCfgNode() = call and
retval.asCfgNode() = retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue()
any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
) and ) and
edgeLabel = "call" edgeLabel = "call"
} }
@@ -716,8 +714,10 @@ private class EssaTaintTracking extends string instanceof TaintTracking::Configu
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
path.noAttribute() path.noAttribute()
| |
assign.getValue().getAFlowNode() = srcnode.asCfgNode() and srcnode.asCfgNode().getNode() = assign.getValue() and
depth = iterable_unpacking_descent(assign.getATarget().getAFlowNode(), defn.getDefiningNode()) 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) 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 * - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1
*/ */
int iterable_unpacking_descent(SequenceNode left_parent, ControlFlowNode left_defn) { 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 left_parent.getAnElement() = left_defn and
// Handle `a, *b = some_iterable` // Handle `a, *b = some_iterable`
if left_defn instanceof StarredNode then result = 0 else result = 1 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) { predicate with_definition(Variable v, ControlFlowNode defn) {
exists(With with, Name var | exists(With with, Name var |
with.getOptionalVars() = var and with.getOptionalVars() = var and
var.getAFlowNode() = defn defn.getNode() = var
| |
var = v.getAStore() var = v.getAStore()
) )
@@ -67,7 +67,7 @@ module SsaSource {
predicate pattern_capture_definition(Variable v, ControlFlowNode defn) { predicate pattern_capture_definition(Variable v, ControlFlowNode defn) {
exists(MatchCapturePattern capture, Name var | exists(MatchCapturePattern capture, Name var |
capture.getVariable() = var and capture.getVariable() = var and
var.getAFlowNode() = defn defn.getNode() = var
| |
var = v.getAStore() var = v.getAStore()
) )
@@ -78,7 +78,7 @@ module SsaSource {
predicate pattern_alias_definition(Variable v, ControlFlowNode defn) { predicate pattern_alias_definition(Variable v, ControlFlowNode defn) {
exists(MatchAsPattern pattern, Name var | exists(MatchAsPattern pattern, Name var |
pattern.getAlias() = var and pattern.getAlias() = var and
var.getAFlowNode() = defn defn.getNode() = var
| |
var = v.getAStore() var = v.getAStore()
) )

View File

@@ -59,7 +59,7 @@ module Bottle {
override Parameter getARoutedParameter() { none() } 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. */ /** A response returned by a view callable. */
class BottleReturnResponse extends Http::Server::HttpResponse::Range { class BottleReturnResponse extends Http::Server::HttpResponse::Range {
BottleReturnResponse() { 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 } override DataFlow::Node getBody() { result = this }

View File

@@ -2872,7 +2872,10 @@ module PrivateDjango {
DataFlow::CfgNode DataFlow::CfgNode
{ {
DjangoRedirectViewGetRedirectUrlReturn() { 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 } override DataFlow::Node getRedirectLocation() { result = this }

View File

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

View File

@@ -371,7 +371,7 @@ module Flask {
result in [this.getArg(0), this.getArgByName("rule")] 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() { FlaskRouteHandlerReturn() {
exists(Function routeHandler | exists(Function routeHandler |
routeHandler = any(FlaskRouteSetup rs).getARequestHandler() and 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 not this instanceof Flask::Response::InstanceSource
) )
} }

View File

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

View File

@@ -166,7 +166,10 @@ module Pyramid {
/** A response returned by a view callable. */ /** A response returned by a view callable. */
private class PyramidReturnResponse extends Http::Server::HttpResponse::Range { private class PyramidReturnResponse extends Http::Server::HttpResponse::Range {
PyramidReturnResponse() { 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() not this = instance()
} }

View File

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

View File

@@ -182,7 +182,10 @@ private module Twisted {
DataFlow::CfgNode DataFlow::CfgNode
{ {
TwistedResourceRenderMethodReturn() { 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 } override DataFlow::Node getBody() { result = this }

View File

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

View File

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

View File

@@ -745,7 +745,12 @@ class PythonFunctionValue extends FunctionValue {
override int maxParameters() { result = this.getScope().getMaxPositionalArguments() } override int maxParameters() { result = this.getScope().getMaxPositionalArguments() }
/** Gets a control flow node corresponding to a return statement in this function */ /** 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()) } 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) { private predicate neither_class_nor_static_method(Function f) {
not exists(f.getADecorator()) not exists(f.getADecorator())
or or
exists(ControlFlowNode deco | deco = f.getADecorator().getAFlowNode() | exists(ControlFlowNode deco | deco.getNode() = f.getADecorator() |
exists(ObjectInternal o | PointsToInternal::pointsTo(deco, _, o, _) | exists(ObjectInternal o | PointsToInternal::pointsTo(deco, _, o, _) |
o != ObjectInternal::staticMethod() and o != ObjectInternal::staticMethod() and
o != ObjectInternal::classMethod() o != ObjectInternal::classMethod()

View File

@@ -711,7 +711,7 @@ private module InterModulePointsTo {
ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin
) { ) {
exists(string name, ImportExpr i | exists(string name, ImportExpr i |
i.getAFlowNode() = f and f.getNode() = i and
i.getImportedModuleName() = name and i.getImportedModuleName() = name and
PointsToInternal::module_imported_as(value, name) and PointsToInternal::module_imported_as(value, name) and
origin = f and origin = f and
@@ -2118,8 +2118,9 @@ module Types {
result.getBuiltin() = cls.getBuiltin().getBaseClass() and n = 0 result.getBuiltin() = cls.getBuiltin().getBaseClass() and n = 0
or or
exists(Class pycls | pycls = cls.(PythonClassObjectInternal).getScope() | exists(Class pycls | pycls = cls.(PythonClassObjectInternal).getScope() |
exists(ObjectInternal base | exists(ObjectInternal base, ControlFlowNode baseNode |
PointsToInternal::pointsTo(pycls.getBase(n).getAFlowNode(), _, base, _) baseNode.getNode() = pycls.getBase(n) and
PointsToInternal::pointsTo(baseNode, _, base, _)
| |
result = base and base != ObjectInternal::unknown() result = base and base != ObjectInternal::unknown()
or or
@@ -2223,7 +2224,10 @@ module Types {
} }
private ControlFlowNode decorator_call_callee(PythonClassObjectInternal cls) { 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) { private boolean has_six_add_metaclass(PythonClassObjectInternal cls) {
@@ -2262,7 +2266,7 @@ module Types {
} }
private EssaVariable metaclass_var(Class cls) { private EssaVariable metaclass_var(Class cls) {
result.getASourceUse() = cls.getMetaClass().getAFlowNode() result.getASourceUse().getNode() = cls.getMetaClass()
or or
major_version() = 2 and major_version() = 2 and
not exists(cls.getMetaClass()) 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. */ /** 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) } 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. * It is guaranteed that getProbableSingletonInstance() returns at most one Object for each ClassObject.
*/ */
Object getProbableSingletonInstance() { Object getProbableSingletonInstance() {
exists(ControlFlowNodeWithPointsTo use, Expr origin | exists(ControlFlowNodeWithPointsTo use, Expr origin, ControlFlowNode origin_ |
use.refersTo(result, this, origin.getAFlowNode()) origin_.getNode() = origin and
use.refersTo(result, this, origin_)
| |
this.hasStaticallyUniqueInstance() and this.hasStaticallyUniqueInstance() and
/* Ensure that original expression will be executed only one. */ /* 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) { 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() { RangeIterationVariableFact() {
exists(For f, ControlFlowNode iterable | exists(For f, ControlFlowNode iterable |
iterable.getBasicBlock().dominates(this.(ControlFlowNode).getBasicBlock()) and iterable.getBasicBlock().dominates(this.(ControlFlowNode).getBasicBlock()) and
f.getIter().getAFlowNode() = iterable and iterable.getNode() = f.getIter() and
f.getTarget().getAFlowNode() = this and this.(ControlFlowNode).getNode() = f.getTarget() and
exists(ObjectInternal range | exists(ObjectInternal range |
PointsTo::pointsTo(iterable, _, range, _) and PointsTo::pointsTo(iterable, _, range, _) and
range.getClass() = ObjectInternal::builtin("range") 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 */ /** Gets a control flow node corresponding to the value of a return statement */
ControlFlowNodeWithPointsTo getAReturnedNode() { ControlFlowNodeWithPointsTo getAReturnedNode() {
result = this.getFunction().getAReturnValueFlowNode() exists(Return ret |
ret.getScope() = this.getFunction() and
result.getNode() = ret.getValue()
)
} }
override string descriptiveString() { override string descriptiveString() {
@@ -170,7 +173,7 @@ class PyFunctionObject extends FunctionObject {
predicate unconditionallyReturnsParameter(int n) { predicate unconditionallyReturnsParameter(int n) {
exists(SsaVariable pvar | exists(SsaVariable pvar |
exists(Parameter p | p = this.getFunction().getArg(n) | exists(Parameter p | p = this.getFunction().getArg(n) |
p.asName().getAFlowNode() = pvar.getDefinition() pvar.getDefinition().getNode() = p.asName()
) and ) and
exists(NameNode rval | exists(NameNode rval |
rval = pvar.getAUse() and rval = pvar.getAUse() and

View File

@@ -337,7 +337,7 @@ class TupleObject extends SequenceObject {
or or
this instanceof TupleNode this instanceof TupleNode
or 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 { 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 } override boolean booleanValue() { result = true }
} }

View File

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

View File

@@ -15,7 +15,9 @@
import python import python
import semmle.python.ApiGraphs 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) { predicate catches_base_exception(ExceptStmt ex) {
ex.getType() = API::builtin("BaseException").getAValueReachableFromSource().asExpr() 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) { predicate illegally_named_parameter_objectapi(Call call, Object func, string name) {
not func.isC() and not func.isC() and
name = call.getANamedArgumentName() 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) 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) { predicate illegally_named_parameter(Call call, Value func, string name) {
not func.isBuiltin() and not func.isBuiltin() and
name = call.getANamedArgumentName() 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) 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 call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
or or
callable instanceof ClassObject and 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 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 call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1
or or
callable instanceof ClassValue and 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 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 call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1
or or
callable instanceof ClassObject and 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 limit = func.maxParameters() - 1
) and ) and
positional_arg_count_for_call_objectapi(call, callable) > limit 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 call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1
or or
callable instanceof ClassValue and 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 limit = func.maxParameters() - 1
) and ) and
positional_arg_count_for_call(call, callable) > limit 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(string s | dict_key(d, k1, s) and dict_key(d, k2, s) and k1 != k2) and
( (
exists(BasicBlock b, int i1, int i2 | exists(BasicBlock b, int i1, int i2 |
k1.getAFlowNode() = b.getNode(i1) and b.getNode(i1).getNode() = k1 and
k2.getAFlowNode() = b.getNode(i2) and b.getNode(i2).getNode() = k2 and
i1 < i2 i1 < i2
) )
or 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" 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) { 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.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 args = count(format_expr.getAnArg()) - 1
or or
call.getFunction() call.getFunction()
.(AttrNode) .(AttrNode)
.getObject("format") .getObject("format")
.(ControlFlowNodeWithPointsTo) .(ControlFlowNodeWithPointsTo)
.pointsTo(_, fmt.getAFlowNode()) and .pointsTo(_, fmtCfg) and
args = count(format_expr.getAnArg()) args = count(format_expr.getAnArg())
) )
} }

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