mirror of
https://github.com/github/codeql.git
synced 2026-05-16 12:17:07 +02:00
Compare commits
370 Commits
dbartol/ja
...
codeql-cli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3990d0e11a | ||
|
|
aaf220d41e | ||
|
|
ca0345324e | ||
|
|
7c15be1f02 | ||
|
|
eb515f884b | ||
|
|
8cb339aa93 | ||
|
|
30e5a12230 | ||
|
|
30053da70d | ||
|
|
5b2eb88672 | ||
|
|
af6fc676ce | ||
|
|
15bc417a17 | ||
|
|
9ba8045837 | ||
|
|
255f55cf1a | ||
|
|
1626af0ae1 | ||
|
|
7d9a3e1399 | ||
|
|
508e8157b3 | ||
|
|
5e33d9a145 | ||
|
|
8169ccd21e | ||
|
|
cc1e33fb64 | ||
|
|
57875554f4 | ||
|
|
e5885f65db | ||
|
|
528641c55a | ||
|
|
134539060d | ||
|
|
25b592fc89 | ||
|
|
5115216c2d | ||
|
|
da5e9ac18c | ||
|
|
ade5686e52 | ||
|
|
96ea9507a4 | ||
|
|
9d8d7ab237 | ||
|
|
ae7afa7aff | ||
|
|
867c8a7fa6 | ||
|
|
ef1592fe32 | ||
|
|
493a68a232 | ||
|
|
22261c1480 | ||
|
|
d0f978d937 | ||
|
|
de612963de | ||
|
|
3402a729d0 | ||
|
|
e83f1d17bf | ||
|
|
8e4e663739 | ||
|
|
2f07f1c730 | ||
|
|
23ee7b955c | ||
|
|
1456ec2119 | ||
|
|
6290be2922 | ||
|
|
b0ea175021 | ||
|
|
8f681154ce | ||
|
|
c4256f21c7 | ||
|
|
5b57826915 | ||
|
|
2af60f1390 | ||
|
|
fc298b23c9 | ||
|
|
5f45402cf7 | ||
|
|
5650694313 | ||
|
|
e2eb08b543 | ||
|
|
22588c9f85 | ||
|
|
c013d4a59c | ||
|
|
4a291147e0 | ||
|
|
bb78c2a67e | ||
|
|
e91efaa92e | ||
|
|
ac8b9739c5 | ||
|
|
ffd6b9864c | ||
|
|
659ce6f1ca | ||
|
|
b4bb24aa43 | ||
|
|
6ade2a8054 | ||
|
|
854d7660eb | ||
|
|
57c6e4d9cb | ||
|
|
f3bf347bd6 | ||
|
|
9fad5410c0 | ||
|
|
c66bd72620 | ||
|
|
575eb24073 | ||
|
|
d013c8940d | ||
|
|
756affa4aa | ||
|
|
2f14ec9f2a | ||
|
|
f6f54c6e3b | ||
|
|
665da3958a | ||
|
|
f1a350c96a | ||
|
|
d0f73acc25 | ||
|
|
5f353b72cd | ||
|
|
1398575b97 | ||
|
|
04c7319b6b | ||
|
|
7420d07935 | ||
|
|
e7da53d838 | ||
|
|
6d43eed1e6 | ||
|
|
3ef49f31aa | ||
|
|
f97a159163 | ||
|
|
88e5ce3cf8 | ||
|
|
ca27785ace | ||
|
|
db28f1b29e | ||
|
|
8372a2e562 | ||
|
|
58d2c71c20 | ||
|
|
f70f8a3536 | ||
|
|
1135bf6bcd | ||
|
|
3e877ffaac | ||
|
|
ae19b2fd89 | ||
|
|
faa168993c | ||
|
|
0c10f083cb | ||
|
|
796da126b8 | ||
|
|
0b3b95ab54 | ||
|
|
cad2b74137 | ||
|
|
6ede20cccc | ||
|
|
69f0e8bcf7 | ||
|
|
7986fc7036 | ||
|
|
396bf93ac0 | ||
|
|
8a895740ba | ||
|
|
513efe222d | ||
|
|
6f6b4a0bfe | ||
|
|
d295cac697 | ||
|
|
89f43fb917 | ||
|
|
6015524589 | ||
|
|
c364fd7e56 | ||
|
|
32e9881cfb | ||
|
|
30034b4254 | ||
|
|
b80b6aafdd | ||
|
|
4df9cd88ef | ||
|
|
0c9a2896d8 | ||
|
|
b18f8d3935 | ||
|
|
6322270926 | ||
|
|
3711a7e3e6 | ||
|
|
25b3d76f71 | ||
|
|
09c2f901f4 | ||
|
|
6a87eb0c73 | ||
|
|
acac3a06ad | ||
|
|
719cef8298 | ||
|
|
5ac9c2db74 | ||
|
|
0abc0d1a67 | ||
|
|
aa7215bbd5 | ||
|
|
dfeb35fe1a | ||
|
|
8352d17e2c | ||
|
|
f171eeb229 | ||
|
|
6bd46148e7 | ||
|
|
a66f31d844 | ||
|
|
6965cf7246 | ||
|
|
4de0fefe86 | ||
|
|
b087fdecfe | ||
|
|
918e435a48 | ||
|
|
04d1c82005 | ||
|
|
954235ecdd | ||
|
|
338e82064e | ||
|
|
201842d2f9 | ||
|
|
61a012fc6c | ||
|
|
c883aa09f8 | ||
|
|
79871aa51e | ||
|
|
4c21444dd5 | ||
|
|
ed39c465a6 | ||
|
|
5d4ceeebb5 | ||
|
|
f3d727fadc | ||
|
|
fa1c92dbe7 | ||
|
|
0ac4a10345 | ||
|
|
494b8bd7e1 | ||
|
|
073189ed6b | ||
|
|
7a6eabc8a3 | ||
|
|
6ffdf576d0 | ||
|
|
0b0e8a4bf5 | ||
|
|
58fd1a2241 | ||
|
|
ad630bc6ff | ||
|
|
4d251b96a6 | ||
|
|
bdb793ba92 | ||
|
|
3a098d7449 | ||
|
|
5d925d36d3 | ||
|
|
3d95369608 | ||
|
|
11016e193c | ||
|
|
41218fb89f | ||
|
|
5afd2d5bf0 | ||
|
|
a3a0c2b269 | ||
|
|
9952997b48 | ||
|
|
f3cbf86c43 | ||
|
|
723236d15b | ||
|
|
c90d0faaf6 | ||
|
|
837387aeae | ||
|
|
629a7a601d | ||
|
|
d401891d30 | ||
|
|
c79da8b2b5 | ||
|
|
ed9a6bd820 | ||
|
|
bf5ba33c2e | ||
|
|
365ccf4903 | ||
|
|
36a031833f | ||
|
|
ab99509a11 | ||
|
|
0f95a8d724 | ||
|
|
288e0ec565 | ||
|
|
c1a1edf24e | ||
|
|
74cba9056b | ||
|
|
d04a0f4b87 | ||
|
|
1511927a2b | ||
|
|
fd615fb7a3 | ||
|
|
442e58188b | ||
|
|
e1963a5fcd | ||
|
|
7a7ff4a91e | ||
|
|
5d14070cd4 | ||
|
|
22ed2f9ae3 | ||
|
|
9bb2a4bfce | ||
|
|
dcbb66d366 | ||
|
|
f1e22687ab | ||
|
|
1f1b1b7aab | ||
|
|
3c1a19c5ab | ||
|
|
92bca9c268 | ||
|
|
98f52589b0 | ||
|
|
fcf1b6d6f5 | ||
|
|
08d6d54961 | ||
|
|
70d530a49c | ||
|
|
a7dbe29448 | ||
|
|
7235ba8f91 | ||
|
|
3b1d917c2b | ||
|
|
cb1ca4c75c | ||
|
|
4ab925507d | ||
|
|
6bde26d9fd | ||
|
|
5d7a92cf13 | ||
|
|
40096ebb62 | ||
|
|
9e3f4cd183 | ||
|
|
483370d5f4 | ||
|
|
f084bb7bcf | ||
|
|
36937a0988 | ||
|
|
51d189d30d | ||
|
|
3d6965a550 | ||
|
|
b00c545799 | ||
|
|
d6618edf01 | ||
|
|
f7392d6498 | ||
|
|
6ca978e1cc | ||
|
|
823d5acd69 | ||
|
|
8bb21e1b49 | ||
|
|
a2cdb9c173 | ||
|
|
c3d9ea1820 | ||
|
|
afb5e4f841 | ||
|
|
f6f5f5d4b4 | ||
|
|
c9bd9e9303 | ||
|
|
61c3aa6288 | ||
|
|
328f322692 | ||
|
|
26ac84aa6e | ||
|
|
96dda8808c | ||
|
|
5a4cd1c578 | ||
|
|
ed266dac5f | ||
|
|
1ce0ba5083 | ||
|
|
9bfd461fad | ||
|
|
26f8e64a35 | ||
|
|
770774ed52 | ||
|
|
c15749f342 | ||
|
|
6196fd2cc1 | ||
|
|
c04315a7cf | ||
|
|
16feaf15e2 | ||
|
|
f1afa2bf59 | ||
|
|
927b402a3a | ||
|
|
d24bdbb4e4 | ||
|
|
6bb98b02a8 | ||
|
|
b8eb2ab100 | ||
|
|
6f5b949ec8 | ||
|
|
04a4fb2143 | ||
|
|
a4c1a622b7 | ||
|
|
50c2d108ca | ||
|
|
306b087b6e | ||
|
|
977767b0d6 | ||
|
|
201c4aad13 | ||
|
|
c064a9e092 | ||
|
|
db5e452178 | ||
|
|
c629867191 | ||
|
|
d0ca39fb03 | ||
|
|
b3b9406e45 | ||
|
|
953461d1aa | ||
|
|
bf0675e5ba | ||
|
|
2832318711 | ||
|
|
aa5e0c39ba | ||
|
|
a9cf33ce18 | ||
|
|
8542992b0d | ||
|
|
05f85497ed | ||
|
|
d4414dabff | ||
|
|
86cc2dc5a1 | ||
|
|
1ea94faccf | ||
|
|
4c7ec59306 | ||
|
|
321eb34eff | ||
|
|
2e772a80c4 | ||
|
|
64720adccb | ||
|
|
7600c243de | ||
|
|
369241e1ea | ||
|
|
ccaf2dd9ea | ||
|
|
88b3d1ffd7 | ||
|
|
cd04500dd9 | ||
|
|
3c777b7605 | ||
|
|
32dbdb3913 | ||
|
|
da84889242 | ||
|
|
9902874ddd | ||
|
|
0304aa846c | ||
|
|
777279dc29 | ||
|
|
821398715c | ||
|
|
768d866e72 | ||
|
|
0462809edc | ||
|
|
5c68bad2f1 | ||
|
|
91f1cf10a7 | ||
|
|
97c2387904 | ||
|
|
56d0affe38 | ||
|
|
6d486f9931 | ||
|
|
9e808c17af | ||
|
|
0dc036abd1 | ||
|
|
98d587c482 | ||
|
|
569b650916 | ||
|
|
fe54961b84 | ||
|
|
b16ba61fcb | ||
|
|
88abc8f72f | ||
|
|
a4c06b2bbc | ||
|
|
12fbd18f3a | ||
|
|
ad7c96554f | ||
|
|
f30a642c8f | ||
|
|
ba9c2f1e3a | ||
|
|
05d2e16de3 | ||
|
|
6da3972433 | ||
|
|
1266f9757d | ||
|
|
000dedf3e8 | ||
|
|
51623c3837 | ||
|
|
104d448b16 | ||
|
|
2458d16426 | ||
|
|
f8335e6163 | ||
|
|
91b7a6cbd8 | ||
|
|
1f932d407f | ||
|
|
26b49dd0df | ||
|
|
d80a1487be | ||
|
|
e18389718c | ||
|
|
e8dd6a88e7 | ||
|
|
6ef2aed3aa | ||
|
|
9a82ea48f2 | ||
|
|
315890680c | ||
|
|
38b1eb7c71 | ||
|
|
f39dc41903 | ||
|
|
05910de8d1 | ||
|
|
cef8744a37 | ||
|
|
7816f34d75 | ||
|
|
64890a1a6b | ||
|
|
2b6aab108d | ||
|
|
2eac11edd6 | ||
|
|
62509a10c2 | ||
|
|
e0a3c8a1c4 | ||
|
|
bd68986fa4 | ||
|
|
9357762e06 | ||
|
|
dacc0ab8fe | ||
|
|
438e664116 | ||
|
|
a22ea6c1c8 | ||
|
|
7392d186bc | ||
|
|
fb07a56de6 | ||
|
|
ded39749a7 | ||
|
|
f9f46f0f98 | ||
|
|
3ef05a628f | ||
|
|
310819d392 | ||
|
|
d4ea62edec | ||
|
|
7c6239b077 | ||
|
|
72530a8312 | ||
|
|
294092b671 | ||
|
|
fc2dc28f87 | ||
|
|
112e7c95fa | ||
|
|
e7f9b5bbbc | ||
|
|
f95926e1a8 | ||
|
|
3e0d30f13a | ||
|
|
58b9355c69 | ||
|
|
1eaa998648 | ||
|
|
e7e0c6bf12 | ||
|
|
35378aa714 | ||
|
|
3434c38da7 | ||
|
|
e30f725e71 | ||
|
|
e40ae2e52d | ||
|
|
77a00873a9 | ||
|
|
5ddfe75a0d | ||
|
|
59f953269a | ||
|
|
bbc3ff2dfe | ||
|
|
a3076f4f72 | ||
|
|
b261145f43 | ||
|
|
571be8be3e | ||
|
|
eb32cbe8a5 | ||
|
|
bdc48088e6 | ||
|
|
bc551174f9 | ||
|
|
501cda4e8c | ||
|
|
2118f233b9 | ||
|
|
b80a711b27 | ||
|
|
1e97600c4a | ||
|
|
d410136852 | ||
|
|
c004ffaca8 | ||
|
|
281ac05868 | ||
|
|
df406b4fca |
1
.bazelrc
1
.bazelrc
@@ -25,5 +25,6 @@ common --registry=https://bcr.bazel.build
|
||||
|
||||
common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
common --experimental_isolated_extension_usages
|
||||
common --incompatible_use_plus_in_repo_names
|
||||
|
||||
try-import %workspace%/local.bazelrc
|
||||
|
||||
22
Cargo.lock
generated
22
Cargo.lock
generated
@@ -112,6 +112,16 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "ast-generator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"ungrammar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.6.0"
|
||||
@@ -380,11 +390,13 @@ dependencies = [
|
||||
"ra_ap_base_db",
|
||||
"ra_ap_hir",
|
||||
"ra_ap_hir_def",
|
||||
"ra_ap_hir_expand",
|
||||
"ra_ap_ide_db",
|
||||
"ra_ap_load-cargo",
|
||||
"ra_ap_parser",
|
||||
"ra_ap_paths",
|
||||
"ra_ap_project_model",
|
||||
"ra_ap_span",
|
||||
"ra_ap_syntax",
|
||||
"ra_ap_vfs",
|
||||
"rust-extractor-macros",
|
||||
@@ -681,16 +693,6 @@ version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
|
||||
|
||||
[[package]]
|
||||
name = "generate-schema"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"ungrammar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
|
||||
@@ -7,7 +7,7 @@ members = [
|
||||
"ruby/extractor",
|
||||
"rust/extractor",
|
||||
"rust/extractor/macros",
|
||||
"rust/generate-schema",
|
||||
"rust/ast-generator",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
|
||||
@@ -23,11 +23,11 @@ bazel_dep(name = "bazel_skylib", version = "1.6.1")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.0.0-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.38.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.15.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.50.0")
|
||||
bazel_dep(name = "rules_rust", version = "0.52.2")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
@@ -61,7 +61,7 @@ r.from_cargo(
|
||||
"//ruby/extractor:Cargo.toml",
|
||||
"//rust/extractor:Cargo.toml",
|
||||
"//rust/extractor/macros:Cargo.toml",
|
||||
"//rust/generate-schema:Cargo.toml",
|
||||
"//rust/ast-generator:Cargo.toml",
|
||||
"//shared/tree-sitter-extractor:Cargo.toml",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isExprRequires(Expr expr) { exists(int kind | exprs(expr, kind, _) | kind = 390) }
|
||||
|
||||
from Expr expr, int kind, int kind_new, Location location
|
||||
where
|
||||
exprs(expr, kind, location) and
|
||||
if isExprRequires(expr) then kind_new = 1 else kind_new = kind
|
||||
select expr, kind_new, location
|
||||
2316
cpp/downgrades/6f5d51e89e762fe4609fd4ac8ee3afb04221e873/old.dbscheme
Normal file
2316
cpp/downgrades/6f5d51e89e762fe4609fd4ac8ee3afb04221e873/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Add requires expr
|
||||
compatibility: partial
|
||||
exprs.rel: run exprs.qlo
|
||||
@@ -1,3 +1,10 @@
|
||||
## 2.0.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added taint flow model for `fopen` and related functions.
|
||||
* The `SimpleRangeAnalysis` library (`semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`) now generates more precise ranges for calls to `fgetc` and `getc`.
|
||||
|
||||
## 2.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
6
cpp/ql/lib/change-notes/released/2.0.2.md
Normal file
6
cpp/ql/lib/change-notes/released/2.0.2.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## 2.0.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added taint flow model for `fopen` and related functions.
|
||||
* The `SimpleRangeAnalysis` library (`semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`) now generates more precise ranges for calls to `fgetc` and `getc`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.1
|
||||
lastReleaseVersion: 2.0.2
|
||||
|
||||
@@ -17,6 +17,7 @@ import semmle.code.cpp.File
|
||||
import semmle.code.cpp.Linkage
|
||||
import semmle.code.cpp.Location
|
||||
import semmle.code.cpp.Compilation
|
||||
import semmle.code.cpp.Concept
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Namespace
|
||||
import semmle.code.cpp.Specifier
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 2.0.2-dev
|
||||
version: 2.0.2
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
14
cpp/ql/lib/semmle/code/cpp/Concept.qll
Normal file
14
cpp/ql/lib/semmle/code/cpp/Concept.qll
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Provides classes for working with C++ concepts.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
* A C++ requires expression.
|
||||
*/
|
||||
class RequiresExpr extends Expr, @requires_expr {
|
||||
override string toString() { result = "requires ..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RequiresExpr" }
|
||||
}
|
||||
@@ -80,6 +80,8 @@ private Declaration getAnEnclosingDeclaration(Locatable ast) {
|
||||
or
|
||||
result = ast.(Parameter).getFunction()
|
||||
or
|
||||
result = ast.(Parameter).getCatchBlock().getEnclosingFunction()
|
||||
or
|
||||
result = ast.(Expr).getEnclosingDeclaration()
|
||||
or
|
||||
result = ast.(Initializer).getDeclaration()
|
||||
@@ -510,6 +512,22 @@ class DeclStmtNode extends StmtNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Handler`.
|
||||
*/
|
||||
class HandlerNode extends ChildStmtNode {
|
||||
Handler handler;
|
||||
|
||||
HandlerNode() { handler = stmt }
|
||||
|
||||
override BaseAstNode getChildInternal(int childIndex) {
|
||||
result = super.getChildInternal(childIndex)
|
||||
or
|
||||
childIndex = -1 and
|
||||
result.getAst() = handler.getParameter()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Parameter`.
|
||||
*/
|
||||
@@ -754,6 +772,8 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
|
||||
or
|
||||
s.(ConstexprIfStmt).getElse() = e and pred = "getElse()"
|
||||
or
|
||||
s.(Handler).getParameter() = e and pred = "getParameter()"
|
||||
or
|
||||
s.(IfStmt).getInitialization() = e and pred = "getInitialization()"
|
||||
or
|
||||
s.(IfStmt).getCondition() = e and pred = "getCondition()"
|
||||
|
||||
@@ -6,6 +6,112 @@
|
||||
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*
|
||||
* Anatomy of a printed IR instruction
|
||||
*
|
||||
* An instruction:
|
||||
*
|
||||
* ```
|
||||
* # 2281| v2281_19(void) = Call[~String] : func:r2281_18, this:r2281_17
|
||||
* ```
|
||||
*
|
||||
* The prefix `# 2281|` specifies that this instruction was generated by the C++ source code on line 2281.
|
||||
* Scrolling up in the printed output, one will eventually find the name of the file to which the line
|
||||
* belongs.
|
||||
*
|
||||
* `v2281_19(void)` is the result of the instruction. Here, `v` means this is a void result or operand (so
|
||||
* there should be no later uses of the result; see below for other possible values). The `2281_19` is a
|
||||
* unique ID for the result. This is usually just the line number plus a small integer suffix to make it
|
||||
* unique within the function. The type of the result is `void`. In this case, it is `void`, because
|
||||
* `~String` returns `void`. The type of the result is usually just the name of the appropriate C++ type,
|
||||
* but it will sometimes be a type like `glval<int>`, which means result holds a glvalue, which at the
|
||||
* IR level works like a pointer. In other words, in the source code the type was `int`, but it is really
|
||||
* more like an `int*`. We see this, for example, in `x = y;`, where `x` is a glvalue.
|
||||
*
|
||||
* `Call` is the opcode of the instruction. Common opcodes include:
|
||||
*
|
||||
* * Arithmetic operations: `Add`, `Sub`, `Mul`, etc.
|
||||
* * Memory access operations: `Load`, `Store`.
|
||||
* * Function calls: `Call`.
|
||||
* * Literals: `Constant`.
|
||||
* * Variable addresses: `VariableAddress`.
|
||||
* * Function entry points: `EnterFunction`.
|
||||
* * Return from a function: `Return`, `ReturnVoid`. Note that the value being returned is set separately by a
|
||||
* `Store` to a special `#return` variable.
|
||||
* * Stack unwinding for C++ function that throw and where the exception escapes the function: `Unwind`.
|
||||
* * Common exit point for `Unwind` and `Return`: `ExitFunction`.
|
||||
* * SSA-related opcodes: `Phi`, `Chi`.
|
||||
*
|
||||
* `[~String]` denotes additional information. The information might be present earlier in the IR, as is the case
|
||||
* for `Call`, where it is the name of the called function. This is also the case for `Load` and `Store`, where it
|
||||
* is the name of the variable that loaded or stored (if known). In the case of `Constant`, `FieldAddress`, and
|
||||
* `VariableAddress`, the information between brackets does not occur earlier.
|
||||
*
|
||||
* `func:r2281_18` and `this:r28281_17` are the operands of the instruction. The `func:` prefix denotes the operand
|
||||
* that holds the address of the called function. The `this:` prefix denotes the argument to the special `this`
|
||||
* parameter of an instance member function. `r2281_18`, `r2281_17` are the unique IDs of the operands. Each of these
|
||||
* matches the ID of a previously seen result, showing where that value came from. The `r` means that these are
|
||||
* "register" operands (see below).
|
||||
*
|
||||
* Result and operand kinds:
|
||||
*
|
||||
* Every result and operand is one of these three kinds:
|
||||
*
|
||||
* * `r` "register". These operands are not stored in any particular memory location. We can think of them as
|
||||
* temporary values created during the evaluation of an expression. A register operand almost always has one
|
||||
* use, often in the same block as its definition.
|
||||
* * `m` "memory". These operands represents accesses to a specific memory location. The location could be a
|
||||
* local variable, a global variable, a field of an object, an element of an array, or any memory that we happen
|
||||
* to have a pointer to. These only occur as the result of a `Store`, the source operand of a `Load` or on the
|
||||
* SSA instructions (`Phi`, `Chi`).
|
||||
* * `v` "void". Really just a register operand, but we mark register operands of type void with this special prefix
|
||||
* so we know that there is no actual value there.
|
||||
*
|
||||
* Branches in the IR:
|
||||
*
|
||||
* The IR is divided into basic blocks. At the end of each block, there are one or more edges showing the possible
|
||||
* control flow successors of the block.
|
||||
*
|
||||
* ```
|
||||
* # 44| v44_3(void) = ConditionalBranch : r44_2
|
||||
* #-----| False -> Block 4
|
||||
* #-----| True -> Block 3
|
||||
* ```
|
||||
* Here we have a block that ends with a conditional branch. The two edges show where the control flows to depending
|
||||
* on whether the condition is true or false.
|
||||
*
|
||||
* SSA instructions:
|
||||
*
|
||||
* We use `Phi` instructions in SSA to create a single definition for a variable that might be assigned on multiple
|
||||
* control flow paths. The `Phi` instruction merges the potential values of that variable from each predecessor edge,
|
||||
* and the resulting definition is then used wherever that variable is accessed later on.
|
||||
*
|
||||
* When dealing with aliased memory, we use the `Chi` instruction to create a single definition for memory that might
|
||||
* or might not have been updated by a store, depending on the actual address that was written to. For example, take:
|
||||
*
|
||||
* ```cpp
|
||||
* int x = 5;
|
||||
* int y = 7;
|
||||
* int* p = condition ? &x : &y;
|
||||
* *p = 6;
|
||||
* return x;
|
||||
* ```
|
||||
*
|
||||
* At the point where we store to `*p`, we do not know whether `p` points to `x` or `y`. Thus, we do not know whether
|
||||
* `return x;` is going to return the value that `x` was originally initialized to (5), or whether it will return 6,
|
||||
* because it was overwritten by `*p = 6;`. We insert a `Chi` instruction immediately after the store to `*p`:
|
||||
*
|
||||
* ```
|
||||
* r2(int) = Constant[6]
|
||||
* r3(int*) = <<value of p>>
|
||||
* m4(int) = Store : &r3, r2 // Stores the constant 6 to *p
|
||||
* m5(unknown) = Chi : total:m1, partial:m4
|
||||
* ```
|
||||
* The `partial:` operand represents the memory that was just stored. The `total:` operand represents the previous
|
||||
* contents of all of the memory that `p` might have pointed to (in this case, both `x` and `y`). The result of the
|
||||
* `Chi` represents the new contents of whatever memory the `total:` operand referred to. We usually do not know exactly
|
||||
* which parts of that memory were overwritten, but it does model that any of that memory could have been modified, so
|
||||
* that later instructions do not assume that the memory was unchanged.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
|
||||
@@ -6,6 +6,112 @@
|
||||
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*
|
||||
* Anatomy of a printed IR instruction
|
||||
*
|
||||
* An instruction:
|
||||
*
|
||||
* ```
|
||||
* # 2281| v2281_19(void) = Call[~String] : func:r2281_18, this:r2281_17
|
||||
* ```
|
||||
*
|
||||
* The prefix `# 2281|` specifies that this instruction was generated by the C++ source code on line 2281.
|
||||
* Scrolling up in the printed output, one will eventually find the name of the file to which the line
|
||||
* belongs.
|
||||
*
|
||||
* `v2281_19(void)` is the result of the instruction. Here, `v` means this is a void result or operand (so
|
||||
* there should be no later uses of the result; see below for other possible values). The `2281_19` is a
|
||||
* unique ID for the result. This is usually just the line number plus a small integer suffix to make it
|
||||
* unique within the function. The type of the result is `void`. In this case, it is `void`, because
|
||||
* `~String` returns `void`. The type of the result is usually just the name of the appropriate C++ type,
|
||||
* but it will sometimes be a type like `glval<int>`, which means result holds a glvalue, which at the
|
||||
* IR level works like a pointer. In other words, in the source code the type was `int`, but it is really
|
||||
* more like an `int*`. We see this, for example, in `x = y;`, where `x` is a glvalue.
|
||||
*
|
||||
* `Call` is the opcode of the instruction. Common opcodes include:
|
||||
*
|
||||
* * Arithmetic operations: `Add`, `Sub`, `Mul`, etc.
|
||||
* * Memory access operations: `Load`, `Store`.
|
||||
* * Function calls: `Call`.
|
||||
* * Literals: `Constant`.
|
||||
* * Variable addresses: `VariableAddress`.
|
||||
* * Function entry points: `EnterFunction`.
|
||||
* * Return from a function: `Return`, `ReturnVoid`. Note that the value being returned is set separately by a
|
||||
* `Store` to a special `#return` variable.
|
||||
* * Stack unwinding for C++ function that throw and where the exception escapes the function: `Unwind`.
|
||||
* * Common exit point for `Unwind` and `Return`: `ExitFunction`.
|
||||
* * SSA-related opcodes: `Phi`, `Chi`.
|
||||
*
|
||||
* `[~String]` denotes additional information. The information might be present earlier in the IR, as is the case
|
||||
* for `Call`, where it is the name of the called function. This is also the case for `Load` and `Store`, where it
|
||||
* is the name of the variable that loaded or stored (if known). In the case of `Constant`, `FieldAddress`, and
|
||||
* `VariableAddress`, the information between brackets does not occur earlier.
|
||||
*
|
||||
* `func:r2281_18` and `this:r28281_17` are the operands of the instruction. The `func:` prefix denotes the operand
|
||||
* that holds the address of the called function. The `this:` prefix denotes the argument to the special `this`
|
||||
* parameter of an instance member function. `r2281_18`, `r2281_17` are the unique IDs of the operands. Each of these
|
||||
* matches the ID of a previously seen result, showing where that value came from. The `r` means that these are
|
||||
* "register" operands (see below).
|
||||
*
|
||||
* Result and operand kinds:
|
||||
*
|
||||
* Every result and operand is one of these three kinds:
|
||||
*
|
||||
* * `r` "register". These operands are not stored in any particular memory location. We can think of them as
|
||||
* temporary values created during the evaluation of an expression. A register operand almost always has one
|
||||
* use, often in the same block as its definition.
|
||||
* * `m` "memory". These operands represents accesses to a specific memory location. The location could be a
|
||||
* local variable, a global variable, a field of an object, an element of an array, or any memory that we happen
|
||||
* to have a pointer to. These only occur as the result of a `Store`, the source operand of a `Load` or on the
|
||||
* SSA instructions (`Phi`, `Chi`).
|
||||
* * `v` "void". Really just a register operand, but we mark register operands of type void with this special prefix
|
||||
* so we know that there is no actual value there.
|
||||
*
|
||||
* Branches in the IR:
|
||||
*
|
||||
* The IR is divided into basic blocks. At the end of each block, there are one or more edges showing the possible
|
||||
* control flow successors of the block.
|
||||
*
|
||||
* ```
|
||||
* # 44| v44_3(void) = ConditionalBranch : r44_2
|
||||
* #-----| False -> Block 4
|
||||
* #-----| True -> Block 3
|
||||
* ```
|
||||
* Here we have a block that ends with a conditional branch. The two edges show where the control flows to depending
|
||||
* on whether the condition is true or false.
|
||||
*
|
||||
* SSA instructions:
|
||||
*
|
||||
* We use `Phi` instructions in SSA to create a single definition for a variable that might be assigned on multiple
|
||||
* control flow paths. The `Phi` instruction merges the potential values of that variable from each predecessor edge,
|
||||
* and the resulting definition is then used wherever that variable is accessed later on.
|
||||
*
|
||||
* When dealing with aliased memory, we use the `Chi` instruction to create a single definition for memory that might
|
||||
* or might not have been updated by a store, depending on the actual address that was written to. For example, take:
|
||||
*
|
||||
* ```cpp
|
||||
* int x = 5;
|
||||
* int y = 7;
|
||||
* int* p = condition ? &x : &y;
|
||||
* *p = 6;
|
||||
* return x;
|
||||
* ```
|
||||
*
|
||||
* At the point where we store to `*p`, we do not know whether `p` points to `x` or `y`. Thus, we do not know whether
|
||||
* `return x;` is going to return the value that `x` was originally initialized to (5), or whether it will return 6,
|
||||
* because it was overwritten by `*p = 6;`. We insert a `Chi` instruction immediately after the store to `*p`:
|
||||
*
|
||||
* ```
|
||||
* r2(int) = Constant[6]
|
||||
* r3(int*) = <<value of p>>
|
||||
* m4(int) = Store : &r3, r2 // Stores the constant 6 to *p
|
||||
* m5(unknown) = Chi : total:m1, partial:m4
|
||||
* ```
|
||||
* The `partial:` operand represents the memory that was just stored. The `total:` operand represents the previous
|
||||
* contents of all of the memory that `p` might have pointed to (in this case, both `x` and `y`). The result of the
|
||||
* `Chi` represents the new contents of whatever memory the `total:` operand referred to. We usually do not know exactly
|
||||
* which parts of that memory were overwritten, but it does model that any of that memory could have been modified, so
|
||||
* that later instructions do not assume that the memory was unchanged.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
|
||||
@@ -6,6 +6,112 @@
|
||||
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*
|
||||
* Anatomy of a printed IR instruction
|
||||
*
|
||||
* An instruction:
|
||||
*
|
||||
* ```
|
||||
* # 2281| v2281_19(void) = Call[~String] : func:r2281_18, this:r2281_17
|
||||
* ```
|
||||
*
|
||||
* The prefix `# 2281|` specifies that this instruction was generated by the C++ source code on line 2281.
|
||||
* Scrolling up in the printed output, one will eventually find the name of the file to which the line
|
||||
* belongs.
|
||||
*
|
||||
* `v2281_19(void)` is the result of the instruction. Here, `v` means this is a void result or operand (so
|
||||
* there should be no later uses of the result; see below for other possible values). The `2281_19` is a
|
||||
* unique ID for the result. This is usually just the line number plus a small integer suffix to make it
|
||||
* unique within the function. The type of the result is `void`. In this case, it is `void`, because
|
||||
* `~String` returns `void`. The type of the result is usually just the name of the appropriate C++ type,
|
||||
* but it will sometimes be a type like `glval<int>`, which means result holds a glvalue, which at the
|
||||
* IR level works like a pointer. In other words, in the source code the type was `int`, but it is really
|
||||
* more like an `int*`. We see this, for example, in `x = y;`, where `x` is a glvalue.
|
||||
*
|
||||
* `Call` is the opcode of the instruction. Common opcodes include:
|
||||
*
|
||||
* * Arithmetic operations: `Add`, `Sub`, `Mul`, etc.
|
||||
* * Memory access operations: `Load`, `Store`.
|
||||
* * Function calls: `Call`.
|
||||
* * Literals: `Constant`.
|
||||
* * Variable addresses: `VariableAddress`.
|
||||
* * Function entry points: `EnterFunction`.
|
||||
* * Return from a function: `Return`, `ReturnVoid`. Note that the value being returned is set separately by a
|
||||
* `Store` to a special `#return` variable.
|
||||
* * Stack unwinding for C++ function that throw and where the exception escapes the function: `Unwind`.
|
||||
* * Common exit point for `Unwind` and `Return`: `ExitFunction`.
|
||||
* * SSA-related opcodes: `Phi`, `Chi`.
|
||||
*
|
||||
* `[~String]` denotes additional information. The information might be present earlier in the IR, as is the case
|
||||
* for `Call`, where it is the name of the called function. This is also the case for `Load` and `Store`, where it
|
||||
* is the name of the variable that loaded or stored (if known). In the case of `Constant`, `FieldAddress`, and
|
||||
* `VariableAddress`, the information between brackets does not occur earlier.
|
||||
*
|
||||
* `func:r2281_18` and `this:r28281_17` are the operands of the instruction. The `func:` prefix denotes the operand
|
||||
* that holds the address of the called function. The `this:` prefix denotes the argument to the special `this`
|
||||
* parameter of an instance member function. `r2281_18`, `r2281_17` are the unique IDs of the operands. Each of these
|
||||
* matches the ID of a previously seen result, showing where that value came from. The `r` means that these are
|
||||
* "register" operands (see below).
|
||||
*
|
||||
* Result and operand kinds:
|
||||
*
|
||||
* Every result and operand is one of these three kinds:
|
||||
*
|
||||
* * `r` "register". These operands are not stored in any particular memory location. We can think of them as
|
||||
* temporary values created during the evaluation of an expression. A register operand almost always has one
|
||||
* use, often in the same block as its definition.
|
||||
* * `m` "memory". These operands represents accesses to a specific memory location. The location could be a
|
||||
* local variable, a global variable, a field of an object, an element of an array, or any memory that we happen
|
||||
* to have a pointer to. These only occur as the result of a `Store`, the source operand of a `Load` or on the
|
||||
* SSA instructions (`Phi`, `Chi`).
|
||||
* * `v` "void". Really just a register operand, but we mark register operands of type void with this special prefix
|
||||
* so we know that there is no actual value there.
|
||||
*
|
||||
* Branches in the IR:
|
||||
*
|
||||
* The IR is divided into basic blocks. At the end of each block, there are one or more edges showing the possible
|
||||
* control flow successors of the block.
|
||||
*
|
||||
* ```
|
||||
* # 44| v44_3(void) = ConditionalBranch : r44_2
|
||||
* #-----| False -> Block 4
|
||||
* #-----| True -> Block 3
|
||||
* ```
|
||||
* Here we have a block that ends with a conditional branch. The two edges show where the control flows to depending
|
||||
* on whether the condition is true or false.
|
||||
*
|
||||
* SSA instructions:
|
||||
*
|
||||
* We use `Phi` instructions in SSA to create a single definition for a variable that might be assigned on multiple
|
||||
* control flow paths. The `Phi` instruction merges the potential values of that variable from each predecessor edge,
|
||||
* and the resulting definition is then used wherever that variable is accessed later on.
|
||||
*
|
||||
* When dealing with aliased memory, we use the `Chi` instruction to create a single definition for memory that might
|
||||
* or might not have been updated by a store, depending on the actual address that was written to. For example, take:
|
||||
*
|
||||
* ```cpp
|
||||
* int x = 5;
|
||||
* int y = 7;
|
||||
* int* p = condition ? &x : &y;
|
||||
* *p = 6;
|
||||
* return x;
|
||||
* ```
|
||||
*
|
||||
* At the point where we store to `*p`, we do not know whether `p` points to `x` or `y`. Thus, we do not know whether
|
||||
* `return x;` is going to return the value that `x` was originally initialized to (5), or whether it will return 6,
|
||||
* because it was overwritten by `*p = 6;`. We insert a `Chi` instruction immediately after the store to `*p`:
|
||||
*
|
||||
* ```
|
||||
* r2(int) = Constant[6]
|
||||
* r3(int*) = <<value of p>>
|
||||
* m4(int) = Store : &r3, r2 // Stores the constant 6 to *p
|
||||
* m5(unknown) = Chi : total:m1, partial:m4
|
||||
* ```
|
||||
* The `partial:` operand represents the memory that was just stored. The `total:` operand represents the previous
|
||||
* contents of all of the memory that `p` might have pointed to (in this case, both `x` and `y`). The result of the
|
||||
* `Chi` represents the new contents of whatever memory the `total:` operand referred to. We usually do not know exactly
|
||||
* which parts of that memory were overwritten, but it does model that any of that memory could have been modified, so
|
||||
* that later instructions do not assume that the memory was unchanged.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
|
||||
@@ -7,7 +7,7 @@ import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/** The function `fopen` and friends. */
|
||||
private class Fopen extends Function, AliasFunction, SideEffectFunction {
|
||||
private class Fopen extends Function, AliasFunction, SideEffectFunction, TaintFunction {
|
||||
Fopen() {
|
||||
this.hasGlobalOrStdName(["fopen", "fopen_s", "freopen"])
|
||||
or
|
||||
@@ -47,4 +47,22 @@ private class Fopen extends Function, AliasFunction, SideEffectFunction {
|
||||
i = 0 and
|
||||
buffer = true
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
this.hasGlobalOrStdName(["fopen", "freopen"]) or
|
||||
this.hasGlobalName(["_wfopen", "_fsopen", "_wfsopen"])
|
||||
) and
|
||||
input.isParameterDeref(0) and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// The out parameter is a pointer to a `FILE*`.
|
||||
this.hasGlobalOrStdName("fopen_s") and
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0, 2)
|
||||
or
|
||||
this.hasGlobalName(["_open", "_wopen"]) and
|
||||
input.isParameterDeref(0) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +192,37 @@ private class UnsignedMulExpr extends MulExpr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the `EOF` macro.
|
||||
*
|
||||
* This is typically `"-1"`, but this is not guaranteed to be the case on all
|
||||
* systems.
|
||||
*/
|
||||
private int getEofValue() {
|
||||
exists(MacroInvocation mi |
|
||||
mi.getMacroName() = "EOF" and
|
||||
result = unique( | | mi.getExpr().getValue().toInt())
|
||||
)
|
||||
}
|
||||
|
||||
/** Get standard `getc` function or related variants. */
|
||||
private class Getc extends Function {
|
||||
Getc() { this.hasGlobalOrStdOrBslName(["fgetc", "getc"]) }
|
||||
}
|
||||
|
||||
/** A call to `getc` */
|
||||
private class CallToGetc extends FunctionCall {
|
||||
CallToGetc() { this.getTarget() instanceof Getc }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `getc` that we can analyze because we know
|
||||
* the value of the `EOF` macro.
|
||||
*/
|
||||
private class AnalyzableCallToGetc extends CallToGetc {
|
||||
AnalyzableCallToGetc() { exists(getEofValue()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` is effectively a multiplication of `operand` with the
|
||||
* positive constant `positive`.
|
||||
@@ -287,6 +318,8 @@ private predicate analyzableExpr(Expr e) {
|
||||
or
|
||||
e instanceof RemExpr
|
||||
or
|
||||
e instanceof AnalyzableCallToGetc
|
||||
or
|
||||
// A conversion is analyzable, provided that its child has an arithmetic
|
||||
// type. (Sometimes the child is a reference type, and so does not get
|
||||
// any bounds.) Rather than checking whether the type of the child is
|
||||
@@ -861,6 +894,14 @@ private float getLowerBoundsImpl(Expr expr) {
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(AnalyzableCallToGetc getc |
|
||||
expr = getc and
|
||||
// from https://en.cppreference.com/w/c/io/fgetc:
|
||||
// On success, returns the obtained character as an unsigned char
|
||||
// converted to an int. On failure, returns EOF.
|
||||
result = min([typeLowerBound(any(UnsignedCharType pct)), getEofValue()])
|
||||
)
|
||||
or
|
||||
// If the conversion is to an arithmetic type then we just return the
|
||||
// lower bound of the child. We do not need to handle truncation and
|
||||
// overflow here, because that is done in `getTruncatedLowerBounds`.
|
||||
@@ -1055,6 +1096,14 @@ private float getUpperBoundsImpl(Expr expr) {
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(AnalyzableCallToGetc getc |
|
||||
expr = getc and
|
||||
// from https://en.cppreference.com/w/c/io/fgetc:
|
||||
// On success, returns the obtained character as an unsigned char
|
||||
// converted to an int. On failure, returns EOF.
|
||||
result = max([typeUpperBound(any(UnsignedCharType pct)), getEofValue()])
|
||||
)
|
||||
or
|
||||
// If the conversion is to an arithmetic type then we just return the
|
||||
// upper bound of the child. We do not need to handle truncation and
|
||||
// overflow here, because that is done in `getTruncatedUpperBounds`.
|
||||
|
||||
@@ -1790,6 +1790,7 @@ case @expr.kind of
|
||||
| 387 = @istriviallyrelocatable
|
||||
| 388 = @datasizeof
|
||||
| 389 = @c11_generic
|
||||
| 390 = @requires_expr
|
||||
;
|
||||
|
||||
@var_args_expr = @vastartexpr
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add requires expressions
|
||||
compatibility: full
|
||||
@@ -1,3 +1,12 @@
|
||||
## 1.2.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/unclear-array-index-validation` ("Unclear validation of array index") query has been improved to reduce false positives and increase true positives.
|
||||
* Fixed false positives in the `cpp/uninitialized-local` ("Potentially uninitialized local variable") query if there are extraction errors in the function.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to detect byte arrays.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to recognize dynamic checks prior to possible dangerous widening.
|
||||
|
||||
## 1.2.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -14,102 +14,56 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
import semmle.code.cpp.security.FlowSources as FS
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
import ImproperArrayIndexValidation::PathGraph
|
||||
import semmle.code.cpp.security.Security
|
||||
|
||||
predicate hasUpperBound(VariableAccess offsetExpr) {
|
||||
exists(BasicBlock controlled, StackVariable offsetVar, SsaDefinition def |
|
||||
controlled.contains(offsetExpr) and
|
||||
linearBoundControls(controlled, def, offsetVar) and
|
||||
offsetExpr = def.getAUse(offsetVar)
|
||||
predicate isFlowSource(FS::FlowSource source, string sourceType) {
|
||||
sourceType = source.getSourceType()
|
||||
}
|
||||
|
||||
predicate guardChecks(IRGuardCondition g, Expr e, boolean branch) {
|
||||
exists(Operand op | op.getDef().getConvertedResultExpression() = e |
|
||||
// `op < k` is true and `k > 0`
|
||||
g.comparesLt(op, any(int k | k > 0), true, any(BooleanValue bv | bv.getValue() = branch))
|
||||
or
|
||||
// `op < _ + k` is true and `k > 0`.
|
||||
g.comparesLt(op, _, any(int k | k > 0), true, branch)
|
||||
or
|
||||
// op == k
|
||||
g.comparesEq(op, _, true, any(BooleanValue bv | bv.getValue() = branch))
|
||||
or
|
||||
// op == _ + k
|
||||
g.comparesEq(op, _, _, true, branch)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, StackVariable offsetVar) {
|
||||
exists(GuardCondition guard, boolean branch |
|
||||
guard.controls(controlled, branch) and
|
||||
cmpWithLinearBound(guard, def.getAUse(offsetVar), Lesser(), branch)
|
||||
/**
|
||||
* Holds if `arrayExpr` accesses an `ArrayType` with a constant size `N`, and
|
||||
* the value of `offsetExpr` is known to be smaller than `N`.
|
||||
*/
|
||||
predicate offsetIsAlwaysInBounds(ArrayExpr arrayExpr, VariableAccess offsetExpr) {
|
||||
exists(ArrayType arrayType |
|
||||
arrayType = arrayExpr.getArrayBase().getUnspecifiedType() and
|
||||
arrayType.getArraySize() > upperBound(offsetExpr.getFullyConverted())
|
||||
)
|
||||
}
|
||||
|
||||
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||
}
|
||||
|
||||
predicate hasUpperBoundsCheck(Variable var) {
|
||||
exists(RelationalOperation oper, VariableAccess access |
|
||||
oper.getAnOperand() = access and
|
||||
access.getTarget() = var and
|
||||
// Comparing to 0 is not an upper bound check
|
||||
not oper.getAnOperand().getValue() = "0"
|
||||
)
|
||||
}
|
||||
|
||||
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||
readsVariable(node.asInstruction(), checkedVar) and
|
||||
any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
|
||||
}
|
||||
|
||||
predicate isFlowSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||
|
||||
predicate predictableInstruction(Instruction instr) {
|
||||
instr instanceof ConstantInstruction
|
||||
or
|
||||
instr instanceof StringConstantInstruction
|
||||
or
|
||||
// This could be a conversion on a string literal
|
||||
predictableInstruction(instr.(UnaryInstruction).getUnary())
|
||||
}
|
||||
|
||||
module ImproperArrayIndexValidationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isFlowSource(source, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
hasUpperBound(node.asExpr())
|
||||
or
|
||||
// These barriers are ported from `DefaultTaintTracking` because this query is quite noisy
|
||||
// otherwise.
|
||||
exists(Variable checkedVar |
|
||||
readsVariable(node.asInstruction(), checkedVar) and
|
||||
hasUpperBoundsCheck(checkedVar)
|
||||
)
|
||||
or
|
||||
exists(Variable checkedVar, Operand access |
|
||||
readsVariable(access.getDef(), checkedVar) and
|
||||
nodeIsBarrierEqualityCandidate(node, access, checkedVar)
|
||||
)
|
||||
or
|
||||
// Don't use dataflow into binary instructions if both operands are unpredictable
|
||||
exists(BinaryInstruction iTo |
|
||||
iTo = node.asInstruction() and
|
||||
not predictableInstruction(iTo.getLeft()) and
|
||||
not predictableInstruction(iTo.getRight()) and
|
||||
// propagate taint from either the pointer or the offset, regardless of predictability
|
||||
not iTo instanceof PointerArithmeticInstruction
|
||||
)
|
||||
or
|
||||
// don't use dataflow through calls to pure functions if two or more operands
|
||||
// are unpredictable
|
||||
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
|
||||
iTo = node.asInstruction() and
|
||||
isPureFunction(iTo.getStaticCallTarget().getName()) and
|
||||
iFrom1 = iTo.getAnArgument() and
|
||||
iFrom2 = iTo.getAnArgument() and
|
||||
not predictableInstruction(iFrom1) and
|
||||
not predictableInstruction(iFrom2) and
|
||||
iFrom1 != iFrom2
|
||||
)
|
||||
node = DataFlow::BarrierGuard<guardChecks/3>::getABarrierNode()
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(ArrayExpr arrayExpr, VariableAccess offsetExpr |
|
||||
offsetExpr = arrayExpr.getArrayOffset() and
|
||||
sink.asExpr() = offsetExpr and
|
||||
not hasUpperBound(offsetExpr)
|
||||
not offsetIsAlwaysInBounds(arrayExpr, offsetExpr)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to detect byte arrays.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to recognize dynamic checks prior to possible dangerous widening.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Fixed false positives in the `cpp/uninitialized-local` ("Potentially uninitialized local variable") query if there are extraction errors in the function.
|
||||
8
cpp/ql/src/change-notes/released/1.2.5.md
Normal file
8
cpp/ql/src/change-notes/released/1.2.5.md
Normal file
@@ -0,0 +1,8 @@
|
||||
## 1.2.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/unclear-array-index-validation` ("Unclear validation of array index") query has been improved to reduce false positives and increase true positives.
|
||||
* Fixed false positives in the `cpp/uninitialized-local` ("Potentially uninitialized local variable") query if there are extraction errors in the function.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to detect byte arrays.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to recognize dynamic checks prior to possible dangerous widening.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.2.4
|
||||
lastReleaseVersion: 1.2.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.2.5-dev
|
||||
version: 1.2.5
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -870,6 +870,8 @@ Throw.cpp:
|
||||
# 8| Type = [BoolType] bool
|
||||
# 8| ValueCategory = prvalue
|
||||
# 12| getChild(1): [Handler] <handler>
|
||||
# 12| getParameter(): [Parameter] e
|
||||
# 12| Type = [PointerType] E *
|
||||
# 12| getBlock(): [CatchBlock] { ... }
|
||||
# 13| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 13| getExpr(): [ReThrowExpr] re-throw exception
|
||||
|
||||
@@ -6,7 +6,7 @@ int wprintf (const wchar_t* format, ...);
|
||||
int strlen( const char * string );
|
||||
int checkErrors();
|
||||
|
||||
void goodTest0()
|
||||
static void goodTest0()
|
||||
{
|
||||
char * ptr = "123456789";
|
||||
int ret;
|
||||
@@ -17,7 +17,7 @@ void goodTest0()
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void goodTest1(const char* ptr)
|
||||
static void goodTest1(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -27,7 +27,7 @@ void goodTest1(const char* ptr)
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void goodTest2(char* ptr)
|
||||
static void goodTest2(char* ptr)
|
||||
{
|
||||
int ret;
|
||||
ptr[10]=0;
|
||||
@@ -38,7 +38,7 @@ void goodTest2(char* ptr)
|
||||
}
|
||||
}
|
||||
|
||||
void goodTest3(const char* ptr)
|
||||
static void goodTest3(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -48,7 +48,7 @@ void goodTest3(const char* ptr)
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void goodTest4(const char* ptr)
|
||||
static void goodTest4(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -58,7 +58,7 @@ void goodTest4(const char* ptr)
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void badTest1(const char* ptr)
|
||||
static void badTest1(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -68,7 +68,7 @@ void badTest1(const char* ptr)
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void badTest2(const char* ptr)
|
||||
static void badTest2(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -79,7 +79,7 @@ void badTest2(const char* ptr)
|
||||
}
|
||||
}
|
||||
|
||||
void goodTest5(const char* ptr,wchar_t *wc,int wc_len)
|
||||
static void goodTest5(const char* ptr,wchar_t *wc,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -96,7 +96,7 @@ void goodTest5(const char* ptr,wchar_t *wc,int wc_len)
|
||||
}
|
||||
}
|
||||
|
||||
void badTest3(const char* ptr,int wc_len)
|
||||
static void badTest3(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -113,7 +113,7 @@ void badTest3(const char* ptr,int wc_len)
|
||||
wc++;
|
||||
}
|
||||
}
|
||||
void badTest4(const char* ptr,int wc_len)
|
||||
static void badTest4(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -130,7 +130,7 @@ void badTest4(const char* ptr,int wc_len)
|
||||
wc++;
|
||||
}
|
||||
}
|
||||
void badTest5(const char* ptr,int wc_len)
|
||||
static void badTest5(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -148,7 +148,7 @@ void badTest5(const char* ptr,int wc_len)
|
||||
}
|
||||
}
|
||||
|
||||
void badTest6(const char* ptr,int wc_len)
|
||||
static void badTest6(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -171,7 +171,7 @@ void badTest6(const char* ptr,int wc_len)
|
||||
ptr+=ret;
|
||||
}
|
||||
}
|
||||
void badTest7(const char* ptr,int wc_len)
|
||||
static void badTest7(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -188,7 +188,7 @@ void badTest7(const char* ptr,int wc_len)
|
||||
ptr+=ret;
|
||||
}
|
||||
}
|
||||
void badTest8(const char* ptr,wchar_t *wc)
|
||||
static void badTest8(const char* ptr,wchar_t *wc)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
|
||||
@@ -24,7 +24,7 @@ typedef unsigned int size_t;
|
||||
void* calloc (size_t num, size_t size);
|
||||
void* malloc (size_t size);
|
||||
|
||||
void badTest1(void *src, int size) {
|
||||
static void badTest1(void *src, int size) {
|
||||
WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, (LPSTR)src, size, 0, 0); // BAD
|
||||
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, (LPCWSTR)src, 30); // BAD
|
||||
}
|
||||
@@ -39,43 +39,43 @@ void goodTest2(){
|
||||
}
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest2(){
|
||||
static void badTest2(){
|
||||
wchar_t src[] = L"0123456789ABCDEF";
|
||||
char dst[16];
|
||||
WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, 16, NULL, NULL); // BAD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void goodTest3(){
|
||||
static void goodTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // GOOD
|
||||
}
|
||||
void badTest3(){
|
||||
static void badTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, 1);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // BAD
|
||||
}
|
||||
void goodTest4(){
|
||||
static void goodTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)malloc((size + 1)*sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // GOOD
|
||||
}
|
||||
void badTest4(){
|
||||
static void badTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)malloc(size + 1);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // BAD
|
||||
}
|
||||
int goodTest5(void *src){
|
||||
static int goodTest5(void *src){
|
||||
return WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, 0, 0, 0, 0); // GOOD
|
||||
}
|
||||
int badTest5 (void *src) {
|
||||
static int badTest5 (void *src) {
|
||||
return WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, 0, 3, 0, 0); // BAD
|
||||
}
|
||||
void goodTest6(WCHAR *src)
|
||||
static void goodTest6(WCHAR *src)
|
||||
{
|
||||
int size;
|
||||
char dst[5] ="";
|
||||
@@ -87,7 +87,7 @@ void goodTest6(WCHAR *src)
|
||||
WideCharToMultiByte(CP_ACP, 0, src, -1, dst, sizeof(dst), 0, 0); // GOOD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest6(WCHAR *src)
|
||||
static void badTest6(WCHAR *src)
|
||||
{
|
||||
char dst[5] ="";
|
||||
WideCharToMultiByte(CP_ACP, 0, src, -1, dst, 260, 0, 0); // BAD
|
||||
|
||||
@@ -11,14 +11,14 @@ size_t _mbstowcs_l(wchar_t *wcstr,const char *mbstr,size_t count, _locale_t loca
|
||||
size_t mbsrtowcs(wchar_t *wcstr,const char *mbstr,size_t count, mbstate_t *mbstate);
|
||||
|
||||
|
||||
void badTest1(void *src, int size) {
|
||||
static void badTest1(void *src, int size) {
|
||||
mbstowcs((wchar_t*)src,(char*)src,size); // BAD
|
||||
_locale_t locale;
|
||||
_mbstowcs_l((wchar_t*)src,(char*)src,size,locale); // BAD
|
||||
mbstate_t *mbstate;
|
||||
mbsrtowcs((wchar_t*)src,(char*)src,size,mbstate); // BAD
|
||||
}
|
||||
void goodTest2(){
|
||||
static void goodTest2(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
wchar_t dst[16];
|
||||
int res = mbstowcs(dst, src,16); // GOOD
|
||||
@@ -29,43 +29,43 @@ void goodTest2(){
|
||||
}
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest2(){
|
||||
static void badTest2(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
wchar_t dst[16];
|
||||
mbstowcs(dst, src,16); // BAD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void goodTest3(){
|
||||
static void goodTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, sizeof(wchar_t));
|
||||
mbstowcs(dst, src,size+1); // GOOD
|
||||
}
|
||||
void badTest3(){
|
||||
static void badTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, 1);
|
||||
mbstowcs(dst, src,size+1); // BAD
|
||||
}
|
||||
void goodTest4(){
|
||||
static void goodTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)malloc((size + 1)*sizeof(wchar_t));
|
||||
mbstowcs(dst, src,size+1); // GOOD
|
||||
}
|
||||
void badTest4(){
|
||||
static void badTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)malloc(size + 1);
|
||||
mbstowcs(dst, src,size+1); // BAD
|
||||
}
|
||||
int goodTest5(void *src){
|
||||
static int goodTest5(void *src){
|
||||
return mbstowcs(NULL, (char*)src,NULL); // GOOD
|
||||
}
|
||||
int badTest5 (void *src) {
|
||||
static int badTest5 (void *src) {
|
||||
return mbstowcs(NULL, (char*)src,3); // BAD
|
||||
}
|
||||
void goodTest6(void *src){
|
||||
static void goodTest6(void *src){
|
||||
wchar_t dst[5];
|
||||
int size = mbstowcs(NULL, (char*)src,NULL);
|
||||
if(size>=sizeof(dst)){
|
||||
@@ -75,7 +75,7 @@ void goodTest6(void *src){
|
||||
mbstowcs(dst, (char*)src,sizeof(dst)); // GOOD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest6(void *src){
|
||||
static void badTest6(void *src){
|
||||
wchar_t dst[5];
|
||||
mbstowcs(dst, (char*)src,260); // BAD
|
||||
printf("%s\n", dst);
|
||||
|
||||
@@ -9,14 +9,14 @@ void goodTest1(unsigned char *src){
|
||||
unsigned char dst[50];
|
||||
_mbsnbcpy(dst,src,sizeof(dst)); // GOOD
|
||||
}
|
||||
size_t badTest1(unsigned char *src){
|
||||
static size_t badTest1(unsigned char *src){
|
||||
int cb = 0;
|
||||
unsigned char dst[50];
|
||||
while( cb < sizeof(dst) )
|
||||
dst[cb++]=*src++; // BAD
|
||||
return _mbclen(dst);
|
||||
}
|
||||
void goodTest2(unsigned char *src){
|
||||
static void goodTest2(unsigned char *src){
|
||||
|
||||
int cb = 0;
|
||||
unsigned char dst[50];
|
||||
@@ -27,7 +27,7 @@ void goodTest2(unsigned char *src){
|
||||
src=_mbsinc(src);
|
||||
}
|
||||
}
|
||||
void badTest2(unsigned char *src){
|
||||
static void badTest2(unsigned char *src){
|
||||
|
||||
int cb = 0;
|
||||
unsigned char dst[50];
|
||||
@@ -38,11 +38,11 @@ void badTest2(unsigned char *src){
|
||||
src=_mbsinc(src);
|
||||
}
|
||||
}
|
||||
void goodTest3(){
|
||||
static void goodTest3(){
|
||||
wchar_t name[50];
|
||||
name[sizeof(name) / sizeof(*name) - 1] = L'\0'; // GOOD
|
||||
}
|
||||
void badTest3(){
|
||||
static void badTest3(){
|
||||
wchar_t name[50];
|
||||
name[sizeof(name) - 1] = L'\0'; // BAD
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ int* deref(int** p) { // $ ast-def=p ir-def=*p ir-def=**p
|
||||
return q;
|
||||
}
|
||||
|
||||
void test1() {
|
||||
void flowout_test1() {
|
||||
int x = 0;
|
||||
int* p = &x;
|
||||
deref(&p)[0] = source();
|
||||
@@ -95,7 +95,7 @@ void addtaint2(int** p) { // $ ast-def=p ir-def=*p ir-def=**p
|
||||
addtaint1(q);
|
||||
}
|
||||
|
||||
void test2() {
|
||||
void flowout_test2() {
|
||||
int x = 0;
|
||||
int* p = &x;
|
||||
addtaint2(&p);
|
||||
|
||||
@@ -15,7 +15,7 @@ template<> struct std::iterator_traits<unsigned long>
|
||||
};
|
||||
|
||||
|
||||
int test() {
|
||||
int iterator_test() {
|
||||
unsigned long x = source();
|
||||
sink(x); // $ ast ir
|
||||
}
|
||||
@@ -5,7 +5,7 @@ int source();
|
||||
void sink(...);
|
||||
bool random();
|
||||
|
||||
void test1() {
|
||||
void on_entry_test1() {
|
||||
int x = source();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
x = 0;
|
||||
@@ -13,7 +13,7 @@ void test1() {
|
||||
sink(x); // $ SPURIOUS: ir
|
||||
}
|
||||
|
||||
void test2(int iterations) {
|
||||
void on_entry_test2(int iterations) {
|
||||
int x = source();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
x = 0;
|
||||
@@ -21,7 +21,7 @@ void test2(int iterations) {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test3() {
|
||||
void on_entry_test3() {
|
||||
int x = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
x = source();
|
||||
@@ -29,7 +29,7 @@ void test3() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test4() {
|
||||
void on_entry_test4() {
|
||||
int x = source();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (random())
|
||||
@@ -39,7 +39,7 @@ void test4() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test5() {
|
||||
void on_entry_test5() {
|
||||
int x = source();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (random())
|
||||
@@ -49,7 +49,7 @@ void test5() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test6() {
|
||||
void on_entry_test6() {
|
||||
int y;
|
||||
int x = source();
|
||||
for (int i = 0; i < 10 && (y = 1); i++) {
|
||||
@@ -57,7 +57,7 @@ void test6() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test7() {
|
||||
void on_entry_test7() {
|
||||
int y;
|
||||
int x = source();
|
||||
for (int i = 0; i < 10 && (y = 1); i++) {
|
||||
@@ -66,7 +66,7 @@ void test7() {
|
||||
sink(x); // $ SPURIOUS: ir
|
||||
}
|
||||
|
||||
void test8() {
|
||||
void on_entry_test8() {
|
||||
int x = source();
|
||||
// It appears to the analysis that the condition can exit after `i < 10`
|
||||
// without having assigned to `x`. That is an effect of how the
|
||||
@@ -78,7 +78,7 @@ void test8() {
|
||||
sink(x); // $ SPURIOUS: ast,ir
|
||||
}
|
||||
|
||||
void test9() {
|
||||
void on_entry_test9() {
|
||||
int y;
|
||||
int x = source();
|
||||
for (int i = 0; (y = 1) && i < 10; i++) {
|
||||
@@ -86,14 +86,14 @@ void test9() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test10() {
|
||||
void on_entry_test10() {
|
||||
int x = source();
|
||||
for (int i = 0; (x = 1) && i < 10; i++) {
|
||||
}
|
||||
sink(x); // no flow
|
||||
}
|
||||
|
||||
void test10(int b, int d) {
|
||||
void on_entry_test10(int b, int d) {
|
||||
int i = 0;
|
||||
int x = source();
|
||||
if (b)
|
||||
|
||||
@@ -6584,6 +6584,16 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future
|
||||
| taint.cpp:767:21:767:24 | ref arg path | taint.cpp:768:8:768:11 | path | |
|
||||
| taint.cpp:768:8:768:11 | path | taint.cpp:768:7:768:11 | * ... | |
|
||||
| taint.cpp:778:37:778:42 | call to source | taint.cpp:779:7:779:9 | obj | |
|
||||
| taint.cpp:785:23:785:28 | source | taint.cpp:785:23:785:28 | source | |
|
||||
| taint.cpp:785:23:785:28 | source | taint.cpp:786:18:786:23 | source | |
|
||||
| taint.cpp:785:23:785:28 | source | taint.cpp:790:15:790:20 | source | |
|
||||
| taint.cpp:786:12:786:16 | call to fopen | taint.cpp:787:7:787:7 | f | |
|
||||
| taint.cpp:786:18:786:23 | source | taint.cpp:786:12:786:16 | call to fopen | TAINT |
|
||||
| taint.cpp:789:8:789:9 | f2 | taint.cpp:790:11:790:12 | f2 | |
|
||||
| taint.cpp:789:8:789:9 | f2 | taint.cpp:791:7:791:8 | f2 | |
|
||||
| taint.cpp:790:10:790:12 | ref arg & ... | taint.cpp:790:11:790:12 | f2 [inner post update] | |
|
||||
| taint.cpp:790:10:790:12 | ref arg & ... | taint.cpp:791:7:791:8 | f2 | |
|
||||
| taint.cpp:790:11:790:12 | f2 | taint.cpp:790:10:790:12 | & ... | |
|
||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
|
||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
|
||||
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |
|
||||
|
||||
@@ -777,4 +777,16 @@ TaintInheritingContentObject source(bool);
|
||||
void test_TaintInheritingContent() {
|
||||
TaintInheritingContentObject obj = source(true);
|
||||
sink(obj.flowFromObject); // $ ir MISSING: ast
|
||||
}
|
||||
|
||||
FILE* fopen(const char*, const char*);
|
||||
int fopen_s(FILE** pFile, const char *filename, const char *mode);
|
||||
|
||||
void fopen_test(char* source) {
|
||||
FILE* f = fopen(source, "r");
|
||||
sink(f); // $ ast,ir
|
||||
|
||||
FILE* f2;
|
||||
fopen_s(&f2, source, "r");
|
||||
sink(f2); // $ ast,ir
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
| c.c | library-tests/files/c.c | CFile, MetricFile | C | | |
|
||||
| files1.cpp | library-tests/files/files1.cpp | CppFile, MetricFile | C++ | swap | t |
|
||||
| files1.h | library-tests/files/files1.h | HeaderFile, MetricFile | | swap | |
|
||||
| files2.cpp | library-tests/files/files2.cpp | CppFile, MetricFile | C++ | g | x, y |
|
||||
| c.c | c.c | CFile, MetricFile | C | | |
|
||||
| files1.cpp | files1.cpp | CppFile, MetricFile | C++ | swap | t |
|
||||
| files1.h | files1.h | HeaderFile, MetricFile | | swap | |
|
||||
| files2.cpp | files2.cpp | CppFile, MetricFile | C++ | g | x, y |
|
||||
|
||||
@@ -9055,6 +9055,8 @@ ir.cpp:
|
||||
# 733| Value = [Literal] 7
|
||||
# 733| ValueCategory = prvalue
|
||||
# 735| getChild(1): [Handler] <handler>
|
||||
# 735| getParameter(): [Parameter] s
|
||||
# 735| Type = [PointerType] const char *
|
||||
# 735| getBlock(): [CatchBlock] { ... }
|
||||
# 736| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 736| getExpr(): [ThrowExpr] throw ...
|
||||
@@ -9067,6 +9069,8 @@ ir.cpp:
|
||||
# 736| Type = [PointerType] const char *
|
||||
# 736| ValueCategory = prvalue(load)
|
||||
# 738| getChild(2): [Handler] <handler>
|
||||
# 738| getParameter(): [Parameter] e
|
||||
# 738| Type = [LValueReferenceType] const String &
|
||||
# 738| getBlock(): [CatchBlock] { ... }
|
||||
# 740| getChild(3): [Handler] <handler>
|
||||
# 740| getBlock(): [CatchAnyBlock] { ... }
|
||||
@@ -12852,6 +12856,8 @@ ir.cpp:
|
||||
# 1200| Value = [Literal] 7
|
||||
# 1200| ValueCategory = prvalue
|
||||
# 1202| getChild(1): [Handler] <handler>
|
||||
# 1202| getParameter(): [Parameter] s
|
||||
# 1202| Type = [PointerType] const char *
|
||||
# 1202| getBlock(): [CatchBlock] { ... }
|
||||
# 1203| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 1203| getExpr(): [ThrowExpr] throw ...
|
||||
@@ -12864,6 +12870,8 @@ ir.cpp:
|
||||
# 1203| Type = [PointerType] const char *
|
||||
# 1203| ValueCategory = prvalue(load)
|
||||
# 1205| getChild(2): [Handler] <handler>
|
||||
# 1205| getParameter(): [Parameter] e
|
||||
# 1205| Type = [LValueReferenceType] const String &
|
||||
# 1205| getBlock(): [CatchBlock] { ... }
|
||||
# 1207| getStmt(1): [ReturnStmt] return ...
|
||||
# 1211| [TopLevelFunction] void VectorTypes(int)
|
||||
@@ -20586,6 +20594,8 @@ ir.cpp:
|
||||
# 2281| Type = [Struct] String
|
||||
# 2281| ValueCategory = lvalue
|
||||
# 2282| getChild(1): [Handler] <handler>
|
||||
# 2282| getParameter(): [Parameter] s
|
||||
# 2282| Type = [PointerType] const char *
|
||||
# 2282| getBlock(): [CatchBlock] { ... }
|
||||
# 2283| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2283| getExpr(): [ThrowExpr] throw ...
|
||||
@@ -20598,6 +20608,8 @@ ir.cpp:
|
||||
# 2283| Type = [PointerType] const char *
|
||||
# 2283| ValueCategory = prvalue(load)
|
||||
# 2285| getChild(2): [Handler] <handler>
|
||||
# 2285| getParameter(): [Parameter] e
|
||||
# 2285| Type = [LValueReferenceType] const String &
|
||||
# 2285| getBlock(): [CatchBlock] { ... }
|
||||
# 2287| getChild(3): [Handler] <handler>
|
||||
# 2287| getBlock(): [CatchAnyBlock] { ... }
|
||||
@@ -22845,6 +22857,8 @@ ir.cpp:
|
||||
# 2537| Value = [Literal] 42
|
||||
# 2537| ValueCategory = prvalue
|
||||
# 2539| getChild(1): [Handler] <handler>
|
||||
# 2539| getParameter(): [Parameter] (unnamed parameter 0)
|
||||
# 2539| Type = [PlainCharType] char
|
||||
# 2539| getBlock(): [CatchBlock] { ... }
|
||||
# 2541| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2541| Type = [VoidType] void
|
||||
@@ -23564,6 +23578,26 @@ ir.cpp:
|
||||
# 2686| Value = [CStyleCast] 0
|
||||
# 2686| ValueCategory = prvalue
|
||||
# 2687| getStmt(1): [ReturnStmt] return ...
|
||||
# 2691| [TopLevelFunction] int concepts::requires_use()
|
||||
# 2691| <params>:
|
||||
# 2691| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2692| getStmt(0): [DeclStmt] declaration
|
||||
# 2692| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
|
||||
# 2692| Type = [IntType] int
|
||||
# 2692| getVariable().getInitializer(): [Initializer] initializer for y
|
||||
#-----| getExpr(): [RequiresExpr] requires ...
|
||||
#-----| Type = [BoolType] bool
|
||||
#-----| Value = [RequiresExpr] 1
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getExpr().getFullyConverted(): [CStyleCast] (int)...
|
||||
#-----| Conversion = [IntegralConversion] integral conversion
|
||||
#-----| Type = [IntType] int
|
||||
#-----| Value = [CStyleCast] 1
|
||||
#-----| ValueCategory = prvalue
|
||||
# 2693| getStmt(1): [ReturnStmt] return ...
|
||||
# 2693| getExpr(): [VariableAccess] y
|
||||
# 2693| Type = [IntType] int
|
||||
# 2693| ValueCategory = prvalue(load)
|
||||
many-defs-per-use.cpp:
|
||||
# 34| [TopLevelFunction] void many_defs_per_use()
|
||||
# 34| <params>:
|
||||
|
||||
@@ -19099,6 +19099,24 @@ ir.cpp:
|
||||
# 2684| Block 8
|
||||
# 2684| v2684_14(void) = Unreached :
|
||||
|
||||
# 2691| int concepts::requires_use()
|
||||
# 2691| Block 0
|
||||
# 2691| v2691_1(void) = EnterFunction :
|
||||
# 2691| m2691_2(unknown) = AliasedDefinition :
|
||||
# 2691| m2691_3(unknown) = InitializeNonLocal :
|
||||
# 2691| m2691_4(unknown) = Chi : total:m2691_2, partial:m2691_3
|
||||
# 2692| r2692_1(glval<int>) = VariableAddress[y] :
|
||||
#-----| r0_1(int) = Constant[1] :
|
||||
#-----| m0_2(int) = Store[y] : &:r2692_1, r0_1
|
||||
# 2693| r2693_1(glval<int>) = VariableAddress[#return] :
|
||||
# 2693| r2693_2(glval<int>) = VariableAddress[y] :
|
||||
# 2693| r2693_3(int) = Load[y] : &:r2693_2, m0_2
|
||||
# 2693| m2693_4(int) = Store[#return] : &:r2693_1, r2693_3
|
||||
# 2691| r2691_5(glval<int>) = VariableAddress[#return] :
|
||||
# 2691| v2691_6(void) = ReturnValue : &:r2691_5, m2693_4
|
||||
# 2691| v2691_7(void) = AliasedUse : m2691_3
|
||||
# 2691| v2691_8(void) = ExitFunction :
|
||||
|
||||
many-defs-per-use.cpp:
|
||||
# 34| void many_defs_per_use()
|
||||
# 34| Block 0
|
||||
|
||||
@@ -2686,4 +2686,13 @@ void test(bool b)
|
||||
twice_call_use(b ? "" : "");
|
||||
}
|
||||
|
||||
namespace concepts {
|
||||
|
||||
int requires_use() {
|
||||
int y = requires { sizeof(int) > 0; };
|
||||
return y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++20 --clang
|
||||
|
||||
@@ -17422,6 +17422,23 @@ ir.cpp:
|
||||
# 2684| v2684_7(void) = AliasedUse : ~m?
|
||||
# 2684| v2684_8(void) = ExitFunction :
|
||||
|
||||
# 2691| int concepts::requires_use()
|
||||
# 2691| Block 0
|
||||
# 2691| v2691_1(void) = EnterFunction :
|
||||
# 2691| mu2691_2(unknown) = AliasedDefinition :
|
||||
# 2691| mu2691_3(unknown) = InitializeNonLocal :
|
||||
# 2692| r2692_1(glval<int>) = VariableAddress[y] :
|
||||
#-----| r0_1(int) = Constant[1] :
|
||||
#-----| mu0_2(int) = Store[y] : &:r2692_1, r0_1
|
||||
# 2693| r2693_1(glval<int>) = VariableAddress[#return] :
|
||||
# 2693| r2693_2(glval<int>) = VariableAddress[y] :
|
||||
# 2693| r2693_3(int) = Load[y] : &:r2693_2, ~m?
|
||||
# 2693| mu2693_4(int) = Store[#return] : &:r2693_1, r2693_3
|
||||
# 2691| r2691_4(glval<int>) = VariableAddress[#return] :
|
||||
# 2691| v2691_5(void) = ReturnValue : &:r2691_4, ~m?
|
||||
# 2691| v2691_6(void) = AliasedUse : ~m?
|
||||
# 2691| v2691_7(void) = ExitFunction :
|
||||
|
||||
many-defs-per-use.cpp:
|
||||
# 34| void many_defs_per_use()
|
||||
# 34| Block 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
| containserror.cpp:0:0:0:0 | containserror.cpp | query-tests/Diagnostics/containserror.cpp | fromSource, normalTermination |
|
||||
| containswarning.cpp:0:0:0:0 | containswarning.cpp | query-tests/Diagnostics/containswarning.cpp | fromSource, normalTermination |
|
||||
| doesnotcompile.cpp:0:0:0:0 | doesnotcompile.cpp | query-tests/Diagnostics/doesnotcompile.cpp | ExtractionProblem (severity 1), fromSource, normalTermination |
|
||||
| containserror.cpp:0:0:0:0 | containserror.cpp | containserror.cpp | fromSource, normalTermination |
|
||||
| containswarning.cpp:0:0:0:0 | containswarning.cpp | containswarning.cpp | fromSource, normalTermination |
|
||||
| doesnotcompile.cpp:0:0:0:0 | doesnotcompile.cpp | doesnotcompile.cpp | ExtractionProblem (severity 1), fromSource, normalTermination |
|
||||
| file://:0:0:0:0 | | | |
|
||||
| header.h:0:0:0:0 | header.h | query-tests/Diagnostics/header.h | fromSource |
|
||||
| successful.cpp:0:0:0:0 | successful.cpp | query-tests/Diagnostics/successful.cpp | fromSource, normalTermination |
|
||||
| header.h:0:0:0:0 | header.h | header.h | fromSource |
|
||||
| successful.cpp:0:0:0:0 | successful.cpp | successful.cpp | fromSource, normalTermination |
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:9:5:9:10 | call to proto6 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:9:5:9:10 | call to proto6 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:10:5:10:10 | call to proto7 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:10:5:10:10 | call to proto7 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:12:5:12:10 | call to proto9 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:12:5:12:10 | call to proto9 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:13:5:13:11 | call to proto10 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:13:5:13:11 | call to proto10 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:14:5:14:11 | call to proto11 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:14:5:14:11 | call to proto11 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:16:5:16:11 | call to proto13 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:16:5:16:11 | call to proto13 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user1.c:9:5:9:6 | call to f1 | query-tests/Documentation/DocumentApi/user1.c |
|
||||
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user2.c:7:5:7:6 | call to f1 | query-tests/Documentation/DocumentApi/user2.c |
|
||||
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user1.c:14:5:14:6 | call to f6 | query-tests/Documentation/DocumentApi/user1.c |
|
||||
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user2.c:10:5:10:6 | call to f6 | query-tests/Documentation/DocumentApi/user2.c |
|
||||
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:9:5:9:10 | call to proto6 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:9:5:9:10 | call to proto6 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:10:5:10:10 | call to proto7 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:10:5:10:10 | call to proto7 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:12:5:12:10 | call to proto9 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:12:5:12:10 | call to proto9 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:13:5:13:11 | call to proto10 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:13:5:13:11 | call to proto10 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:14:5:14:11 | call to proto11 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:14:5:14:11 | call to proto11 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:16:5:16:11 | call to proto13 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:16:5:16:11 | call to proto13 | comment_prototypes_caller2.c |
|
||||
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user1.c:9:5:9:6 | call to f1 | user1.c |
|
||||
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user2.c:7:5:7:6 | call to f1 | user2.c |
|
||||
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user1.c:14:5:14:6 | call to f6 | user1.c |
|
||||
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user2.c:10:5:10:6 | call to f6 | user2.c |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibC<\|>unknown | 5 |
|
||||
| /query-tests/Metrics/Dependencies/include.h<\|>LibD<\|>unknown | 1 |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibA<\|>unknown | 1 |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibB<\|>unknown | 1 |
|
||||
| /main.cpp<\|>LibC<\|>unknown | 5 |
|
||||
| /include.h<\|>LibD<\|>unknown | 1 |
|
||||
| /main.cpp<\|>LibA<\|>unknown | 1 |
|
||||
| /main.cpp<\|>LibB<\|>unknown | 1 |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| /query-tests/Metrics/Dependencies/include.h<\|>LibD<\|>unknown | include.h:0:0:0:0 | include.h |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibA<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibB<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibC<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /include.h<\|>LibD<\|>unknown | include.h:0:0:0:0 | include.h |
|
||||
| /main.cpp<\|>LibA<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /main.cpp<\|>LibB<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /main.cpp<\|>LibC<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
|
||||
@@ -2,29 +2,36 @@ edges
|
||||
| test1.c:7:26:7:29 | **argv | test1.c:8:11:8:14 | call to atoi | provenance | TaintFunction |
|
||||
| test1.c:8:11:8:14 | call to atoi | test1.c:9:9:9:9 | i | provenance | |
|
||||
| test1.c:8:11:8:14 | call to atoi | test1.c:11:9:11:9 | i | provenance | |
|
||||
| test1.c:8:11:8:14 | call to atoi | test1.c:12:9:12:9 | i | provenance | |
|
||||
| test1.c:8:11:8:14 | call to atoi | test1.c:13:9:13:9 | i | provenance | |
|
||||
| test1.c:9:9:9:9 | i | test1.c:16:16:16:16 | i | provenance | |
|
||||
| test1.c:11:9:11:9 | i | test1.c:32:16:32:16 | i | provenance | |
|
||||
| test1.c:13:9:13:9 | i | test1.c:48:16:48:16 | i | provenance | |
|
||||
| test1.c:16:16:16:16 | i | test1.c:18:16:18:16 | i | provenance | |
|
||||
| test1.c:32:16:32:16 | i | test1.c:33:11:33:11 | i | provenance | |
|
||||
| test1.c:48:16:48:16 | i | test1.c:51:3:51:7 | ... = ... | provenance | |
|
||||
| test1.c:51:3:51:7 | ... = ... | test1.c:53:15:53:15 | j | provenance | |
|
||||
| test1.c:9:9:9:9 | i | test1.c:18:16:18:16 | i | provenance | |
|
||||
| test1.c:11:9:11:9 | i | test1.c:34:16:34:16 | i | provenance | |
|
||||
| test1.c:12:9:12:9 | i | test1.c:42:16:42:16 | i | provenance | |
|
||||
| test1.c:13:9:13:9 | i | test1.c:50:16:50:16 | i | provenance | |
|
||||
| test1.c:18:16:18:16 | i | test1.c:20:16:20:16 | i | provenance | |
|
||||
| test1.c:34:16:34:16 | i | test1.c:35:11:35:11 | i | provenance | |
|
||||
| test1.c:42:16:42:16 | i | test1.c:43:11:43:11 | i | provenance | |
|
||||
| test1.c:50:16:50:16 | i | test1.c:53:3:53:7 | ... = ... | provenance | |
|
||||
| test1.c:53:3:53:7 | ... = ... | test1.c:55:15:55:15 | j | provenance | |
|
||||
nodes
|
||||
| test1.c:7:26:7:29 | **argv | semmle.label | **argv |
|
||||
| test1.c:8:11:8:14 | call to atoi | semmle.label | call to atoi |
|
||||
| test1.c:9:9:9:9 | i | semmle.label | i |
|
||||
| test1.c:11:9:11:9 | i | semmle.label | i |
|
||||
| test1.c:12:9:12:9 | i | semmle.label | i |
|
||||
| test1.c:13:9:13:9 | i | semmle.label | i |
|
||||
| test1.c:16:16:16:16 | i | semmle.label | i |
|
||||
| test1.c:18:16:18:16 | i | semmle.label | i |
|
||||
| test1.c:32:16:32:16 | i | semmle.label | i |
|
||||
| test1.c:33:11:33:11 | i | semmle.label | i |
|
||||
| test1.c:48:16:48:16 | i | semmle.label | i |
|
||||
| test1.c:51:3:51:7 | ... = ... | semmle.label | ... = ... |
|
||||
| test1.c:53:15:53:15 | j | semmle.label | j |
|
||||
| test1.c:20:16:20:16 | i | semmle.label | i |
|
||||
| test1.c:34:16:34:16 | i | semmle.label | i |
|
||||
| test1.c:35:11:35:11 | i | semmle.label | i |
|
||||
| test1.c:42:16:42:16 | i | semmle.label | i |
|
||||
| test1.c:43:11:43:11 | i | semmle.label | i |
|
||||
| test1.c:50:16:50:16 | i | semmle.label | i |
|
||||
| test1.c:53:3:53:7 | ... = ... | semmle.label | ... = ... |
|
||||
| test1.c:55:15:55:15 | j | semmle.label | j |
|
||||
subpaths
|
||||
#select
|
||||
| test1.c:18:16:18:16 | i | test1.c:7:26:7:29 | **argv | test1.c:18:16:18:16 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:33:11:33:11 | i | test1.c:7:26:7:29 | **argv | test1.c:33:11:33:11 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:53:15:53:15 | j | test1.c:7:26:7:29 | **argv | test1.c:53:15:53:15 | j | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:20:16:20:16 | i | test1.c:7:26:7:29 | **argv | test1.c:20:16:20:16 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:35:11:35:11 | i | test1.c:7:26:7:29 | **argv | test1.c:35:11:35:11 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:43:11:43:11 | i | test1.c:7:26:7:29 | **argv | test1.c:43:11:43:11 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:55:15:55:15 | j | test1.c:7:26:7:29 | **argv | test1.c:55:15:55:15 | j | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
|
||||
@@ -11,6 +11,8 @@ int main(int argc, char *argv[]) {
|
||||
test3(i);
|
||||
test4(i);
|
||||
test5(i);
|
||||
test6(i);
|
||||
test7(argv[1]);
|
||||
}
|
||||
|
||||
void test1(int i) {
|
||||
@@ -38,7 +40,7 @@ void test3(int i) {
|
||||
}
|
||||
|
||||
void test4(int i) {
|
||||
myArray[i] = 0; // BAD: i has not been validated [NOT REPORTED]
|
||||
myArray[i] = 0; // BAD: i has not been validated
|
||||
|
||||
if ((i < 0) || (i >= 10)) return;
|
||||
|
||||
@@ -52,3 +54,26 @@ void test5(int i) {
|
||||
|
||||
j = myArray[j]; // BAD: j has not been validated
|
||||
}
|
||||
|
||||
extern int myTable[256];
|
||||
|
||||
void test6(int i) {
|
||||
unsigned char s = i;
|
||||
|
||||
myTable[s] = 0; // GOOD: Input is small [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
typedef void FILE;
|
||||
#define EOF (-1)
|
||||
|
||||
int getc(FILE*);
|
||||
|
||||
extern int myMaxCharTable[256];
|
||||
|
||||
void test7(FILE* fp) {
|
||||
int ch;
|
||||
while ((ch = getc(fp)) != EOF) {
|
||||
myMaxCharTable[ch] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@ char *strcpy(char *s1, const char *s2);
|
||||
|
||||
//// Test code /////
|
||||
|
||||
void bad0(char *str) {
|
||||
static void bad0(char *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = malloc(strlen(str));
|
||||
strcpy(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good0(char *str) {
|
||||
static void good0(char *str) {
|
||||
// GOOD -- Allocating extra byte for terminator
|
||||
char *buffer = malloc(strlen(str)+1);
|
||||
strcpy(buffer, str);
|
||||
@@ -26,7 +26,7 @@ void good0(char *str) {
|
||||
}
|
||||
|
||||
|
||||
void bad1(char *str) {
|
||||
static void bad1(char *str) {
|
||||
int len = strlen(str);
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = malloc(len);
|
||||
@@ -34,7 +34,7 @@ void bad1(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good1(char *str) {
|
||||
static void good1(char *str) {
|
||||
int len = strlen(str);
|
||||
// GOOD -- Allocating extra byte for terminator
|
||||
char *buffer = malloc(len+1);
|
||||
@@ -43,7 +43,7 @@ void good1(char *str) {
|
||||
}
|
||||
|
||||
|
||||
void bad2(char *str) {
|
||||
static void bad2(char *str) {
|
||||
int len = strlen(str);
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = malloc(len);
|
||||
@@ -51,7 +51,7 @@ void bad2(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good2(char *str) {
|
||||
static void good2(char *str) {
|
||||
int len = strlen(str)+1;
|
||||
// GOOD -- Allocating extra byte for terminator
|
||||
char *buffer = malloc(len);
|
||||
@@ -59,14 +59,14 @@ void good2(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad3(char *str) {
|
||||
static void bad3(char *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = malloc(strlen(str) * sizeof(char));
|
||||
strcpy(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good3(char *str) {
|
||||
static void good3(char *str) {
|
||||
// GOOD -- Allocating extra byte for terminator
|
||||
char *buffer = malloc((strlen(str) + 1) * sizeof(char));
|
||||
strcpy(buffer, str);
|
||||
@@ -75,7 +75,7 @@ void good3(char *str) {
|
||||
|
||||
void *memcpy(void *s1, const void *s2, size_t n);
|
||||
|
||||
void good4(char *str) {
|
||||
static void good4(char *str) {
|
||||
// GOOD -- allocating a non zero-terminated string
|
||||
int len = strlen(str);
|
||||
char *buffer = malloc(len);
|
||||
|
||||
@@ -19,28 +19,28 @@ int strcmp(const char *s1, const char *s2);
|
||||
|
||||
//// Test code /////
|
||||
|
||||
void bad1(wchar_t *wstr) {
|
||||
static void bad1(wchar_t *wstr) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr));
|
||||
wcscpy(wbuffer, wstr);
|
||||
free(wbuffer);
|
||||
}
|
||||
|
||||
void bad2(wchar_t *wstr) {
|
||||
static void bad2(wchar_t *wstr) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr) * sizeof(wchar_t));
|
||||
wcscpy(wbuffer, wstr);
|
||||
free(wbuffer);
|
||||
}
|
||||
|
||||
void good1(wchar_t *wstr) {
|
||||
static void good1(wchar_t *wstr) {
|
||||
// GOOD -- Allocating extra character for terminator
|
||||
wchar_t *wbuffer = (wchar_t *)malloc((wcslen(wstr) + 1) * sizeof(wchar_t));
|
||||
wcscpy(wbuffer, wstr);
|
||||
free(wbuffer);
|
||||
}
|
||||
|
||||
void bad3(char *str) {
|
||||
static void bad3(char *str) {
|
||||
// BAD -- zero-termination proved by sprintf (as destination)
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
sprintf(buffer, "%s", str);
|
||||
@@ -50,7 +50,7 @@ void bad3(char *str) {
|
||||
void decode(char *dest, char *src);
|
||||
void wdecode(wchar_t *dest, wchar_t *src);
|
||||
|
||||
void bad4(char *str) {
|
||||
static void bad4(char *str) {
|
||||
// BAD -- zero-termination proved by wprintf (as parameter)
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
@@ -58,7 +58,7 @@ void bad4(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad5(char *str) {
|
||||
static void bad5(char *str) {
|
||||
// BAD -- zero-termination proved by strcat (as destination)
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
buffer[0] = 0;
|
||||
@@ -66,7 +66,7 @@ void bad5(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad6(char *str, char *dest) {
|
||||
static void bad6(char *str, char *dest) {
|
||||
// BAD -- zero-termination proved by strcat (as source)
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
@@ -74,7 +74,7 @@ void bad6(char *str, char *dest) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad7(char *str, char *str2) {
|
||||
static void bad7(char *str, char *str2) {
|
||||
// BAD -- zero-termination proved by strcmp
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
@@ -84,7 +84,7 @@ void bad7(char *str, char *str2) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad8(wchar_t *str) {
|
||||
static void bad8(wchar_t *str) {
|
||||
// BAD -- zero-termination proved by wcslen
|
||||
wchar_t *wbuffer = (wchar_t *)malloc(wcslen(str));
|
||||
wdecode(wbuffer, str);
|
||||
@@ -94,21 +94,21 @@ void bad8(wchar_t *str) {
|
||||
free(wbuffer);
|
||||
}
|
||||
|
||||
void good2(char *str, char *dest) {
|
||||
static void good2(char *str, char *dest) {
|
||||
// GOOD -- zero-termination not proven
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad9(wchar_t *wstr) {
|
||||
static void bad9(wchar_t *wstr) {
|
||||
// BAD -- using new
|
||||
wchar_t *wbuffer = new wchar_t[wcslen(wstr)];
|
||||
wcscpy(wbuffer, wstr);
|
||||
delete wbuffer;
|
||||
}
|
||||
|
||||
void good3(char *str) {
|
||||
static void good3(char *str) {
|
||||
// GOOD -- zero-termination not required for this printf
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
@@ -116,7 +116,7 @@ void good3(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good4(char *str) {
|
||||
static void good4(char *str) {
|
||||
// GOOD -- zero-termination not required for this printf
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
|
||||
@@ -38,35 +38,35 @@ namespace std
|
||||
|
||||
//// Test code /////
|
||||
|
||||
void bad1(char *str) {
|
||||
static void bad1(char *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator [NOT DETECTED]
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
std::string str2(buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good1(char *str) {
|
||||
static void good1(char *str) {
|
||||
// GOOD --- copy does not overrun due to size limit
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
std::string str2(buffer, strlen(str));
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad2(wchar_t *str) {
|
||||
static void bad2(wchar_t *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator [NOT DETECTED]
|
||||
wchar_t *buffer = (wchar_t *)calloc(wcslen(str), sizeof(wchar_t));
|
||||
wcscpy(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad3(wchar_t *str) {
|
||||
static void bad3(wchar_t *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
wchar_t *buffer = (wchar_t *)calloc(sizeof(wchar_t), wcslen(str));
|
||||
wcscpy(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad4(char *str) {
|
||||
static void bad4(char *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = (char *)realloc(0, strlen(str));
|
||||
strcpy(buffer, str);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
edges
|
||||
| main.cpp:7:27:7:30 | **argv | main.cpp:8:17:8:20 | **argv | provenance | |
|
||||
| main.cpp:8:17:8:20 | **argv | test.c:10:28:10:31 | **argv | provenance | |
|
||||
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v | provenance | |
|
||||
| test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:13:27:13 | v | provenance | |
|
||||
| test2.cpp:27:13:27:13 | v | test2.cpp:12:21:12:21 | v | provenance | |
|
||||
@@ -6,18 +8,15 @@ edges
|
||||
| test2.cpp:38:13:38:16 | call to atoi | test2.cpp:39:3:39:18 | ... = ... | provenance | |
|
||||
| test2.cpp:38:13:38:16 | call to atoi | test2.cpp:39:9:39:11 | num | provenance | |
|
||||
| test2.cpp:39:3:39:18 | ... = ... | test2.cpp:40:3:40:5 | num | provenance | |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:11:24:11:27 | call to atoi | provenance | TaintFunction |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:41:5:41:24 | ... = ... | provenance | TaintFunction |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:51:5:51:24 | ... = ... | provenance | TaintFunction |
|
||||
| test5.cpp:5:5:5:17 | *getTaintedInt | test5.cpp:17:6:17:18 | call to getTaintedInt | provenance | |
|
||||
| test5.cpp:5:5:5:17 | *getTaintedInt | test5.cpp:18:6:18:18 | call to getTaintedInt | provenance | |
|
||||
| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:10:9:10:27 | call to strtoul | provenance | TaintFunction |
|
||||
| test5.cpp:10:9:10:27 | call to strtoul | test5.cpp:5:5:5:17 | *getTaintedInt | provenance | |
|
||||
| test5.cpp:18:2:18:20 | ... = ... | test5.cpp:19:6:19:6 | y | provenance | |
|
||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:18:2:18:20 | ... = ... | provenance | |
|
||||
| test.c:10:27:10:30 | **argv | test.c:11:24:11:27 | call to atoi | provenance | TaintFunction |
|
||||
| test.c:10:27:10:30 | **argv | test.c:41:5:41:24 | ... = ... | provenance | TaintFunction |
|
||||
| test.c:10:27:10:30 | **argv | test.c:51:5:51:24 | ... = ... | provenance | TaintFunction |
|
||||
| test.c:10:28:10:31 | **argv | test.c:11:24:11:27 | call to atoi | provenance | TaintFunction |
|
||||
| test.c:10:28:10:31 | **argv | test.c:41:5:41:24 | ... = ... | provenance | TaintFunction |
|
||||
| test.c:10:28:10:31 | **argv | test.c:51:5:51:24 | ... = ... | provenance | TaintFunction |
|
||||
| test.c:11:24:11:27 | call to atoi | test.c:14:15:14:28 | maxConnections | provenance | |
|
||||
| test.c:41:5:41:24 | ... = ... | test.c:44:7:44:10 | len2 | provenance | |
|
||||
| test.c:41:5:41:24 | ... = ... | test.c:44:7:44:12 | ... -- | provenance | |
|
||||
@@ -26,6 +25,8 @@ edges
|
||||
| test.c:51:5:51:24 | ... = ... | test.c:54:7:54:12 | ... -- | provenance | |
|
||||
| test.c:54:7:54:12 | ... -- | test.c:54:7:54:10 | len3 | provenance | |
|
||||
nodes
|
||||
| main.cpp:7:27:7:30 | **argv | semmle.label | **argv |
|
||||
| main.cpp:8:17:8:20 | **argv | semmle.label | **argv |
|
||||
| test2.cpp:12:21:12:21 | v | semmle.label | v |
|
||||
| test2.cpp:14:11:14:11 | v | semmle.label | v |
|
||||
| test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument |
|
||||
@@ -35,7 +36,6 @@ nodes
|
||||
| test2.cpp:39:3:39:18 | ... = ... | semmle.label | ... = ... |
|
||||
| test2.cpp:39:9:39:11 | num | semmle.label | num |
|
||||
| test2.cpp:40:3:40:5 | num | semmle.label | num |
|
||||
| test3.c:10:27:10:30 | **argv | semmle.label | **argv |
|
||||
| test5.cpp:5:5:5:17 | *getTaintedInt | semmle.label | *getTaintedInt |
|
||||
| test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument |
|
||||
| test5.cpp:10:9:10:27 | call to strtoul | semmle.label | call to strtoul |
|
||||
@@ -43,7 +43,7 @@ nodes
|
||||
| test5.cpp:18:2:18:20 | ... = ... | semmle.label | ... = ... |
|
||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
||||
| test5.cpp:19:6:19:6 | y | semmle.label | y |
|
||||
| test.c:10:27:10:30 | **argv | semmle.label | **argv |
|
||||
| test.c:10:28:10:31 | **argv | semmle.label | **argv |
|
||||
| test.c:11:24:11:27 | call to atoi | semmle.label | call to atoi |
|
||||
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
|
||||
| test.c:41:5:41:24 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -61,19 +61,7 @@ subpaths
|
||||
| test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | main.cpp:7:27:7:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | main.cpp:7:27:7:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | main.cpp:7:27:7:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | main.cpp:7:27:7:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
|
||||
@@ -4,20 +4,15 @@
|
||||
| test2.cpp:17:11:17:22 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||
| test2.cpp:39:9:39:18 | ... + ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||
| test2.cpp:40:3:40:13 | ... += ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||
| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test4.cpp:13:7:13:20 | access to array | $@ flows an expression which might overflow negatively. | test4.cpp:8:27:8:30 | **argv | a command-line argument |
|
||||
| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test4.cpp:13:7:13:20 | access to array | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test5.cpp:10:9:10:27 | call to strtoul | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:17:6:17:27 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:19:6:19:13 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test6.cpp:11:10:11:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
|
||||
| test6.cpp:16:10:16:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
|
||||
| test6.cpp:30:11:30:16 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
|
||||
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
extern "C" {
|
||||
int main1(int argc, char** argv);
|
||||
int main3(int argc, char** argv);
|
||||
}
|
||||
int main4(int argc, char** argv);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
main1(argc, argv);
|
||||
main3(argc, argv);
|
||||
main4(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ void startServer(int heapSize);
|
||||
typedef unsigned long size_t;
|
||||
size_t strlen(const char *s);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main1(int argc, char** argv) {
|
||||
int maxConnections = atoi(argv[1]);
|
||||
|
||||
// BAD: arithmetic on a user input without any validation
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// Regression test for ODASA-6054: IntegerOverflowTainted should
|
||||
// not report a result if the overflow happens in a macro expansion
|
||||
// from a macro that is defined in a system header.
|
||||
int main(int argc, char **argv) {
|
||||
int main3(int argc, char **argv) {
|
||||
char *cmd = argv[0];
|
||||
int x = (int)(unsigned char)*cmd; // BAD: overflow
|
||||
int y = CAST(*cmd); // BAD: overflow in macro expansion (macro is not from a system header)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// by comparing the value to 0. This means that the cast cannot overflow,
|
||||
// regardless of what the input type is.
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int main4(int argc, char **argv) {
|
||||
char *p = argv[0];
|
||||
if (!p[0]) { // GOOD: cast to bool.
|
||||
return 1;
|
||||
|
||||
@@ -50,7 +50,7 @@ int val();
|
||||
const char *global1 = mysql_get_client_info();
|
||||
const char *global2 = "abc";
|
||||
|
||||
void test1()
|
||||
void test7()
|
||||
{
|
||||
int sock = socket(val(), val(), val());
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.27
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.27
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.26
|
||||
lastReleaseVersion: 1.7.27
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.27-dev
|
||||
version: 1.7.27
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.27
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.27
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.26
|
||||
lastReleaseVersion: 1.7.27
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.27-dev
|
||||
version: 1.7.27
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 3.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
3
csharp/ql/lib/change-notes/released/3.0.1.md
Normal file
3
csharp/ql/lib/change-notes/released/3.0.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 3.0.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 3.0.0
|
||||
lastReleaseVersion: 3.0.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 3.0.1-dev
|
||||
version: 3.0.1
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -53,7 +53,6 @@ private predicate idOf(AstNode x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
private module CfgInput implements CfgShared::InputSig<Location> {
|
||||
private import ControlFlowGraphImpl as Impl
|
||||
private import Completion as Comp
|
||||
private import Splitting as Splitting
|
||||
private import SuccessorType as ST
|
||||
private import semmle.code.csharp.Caching
|
||||
|
||||
@@ -80,10 +79,6 @@ private module CfgInput implements CfgShared::InputSig<Location> {
|
||||
Impl::scopeLast(scope, last, c)
|
||||
}
|
||||
|
||||
class SplitKindBase = Splitting::TSplitKind;
|
||||
|
||||
class Split = Splitting::Split;
|
||||
|
||||
class SuccessorType = ST::SuccessorType;
|
||||
|
||||
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
|
||||
@@ -102,7 +97,21 @@ private module CfgInput implements CfgShared::InputSig<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
import CfgShared::Make<Location, CfgInput>
|
||||
private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> {
|
||||
private import Splitting as S
|
||||
|
||||
class SplitKindBase = S::TSplitKind;
|
||||
|
||||
class Split = S::Split;
|
||||
}
|
||||
|
||||
private module ConditionalCompletionSplittingInput implements
|
||||
CfgShared::ConditionalCompletionSplittingInputSig<Location, CfgInput, CfgSplittingInput>
|
||||
{
|
||||
import Splitting::ConditionalCompletionSplitting::ConditionalCompletionSplittingInput
|
||||
}
|
||||
|
||||
import CfgShared::MakeWithSplitting<Location, CfgInput, CfgSplittingInput, ConditionalCompletionSplittingInput>
|
||||
|
||||
/**
|
||||
* A compilation.
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import Completion
|
||||
private import Completion as Comp
|
||||
private import Comp
|
||||
private import ControlFlowGraphImpl
|
||||
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg
|
||||
private import semmle.code.csharp.controlflow.internal.PreSsa
|
||||
@@ -260,10 +261,12 @@ module ConditionalCompletionSplitting {
|
||||
|
||||
ConditionalCompletionSplit() { this = TConditionalCompletionSplit(completion) }
|
||||
|
||||
ConditionalCompletion getCompletion() { result = completion }
|
||||
|
||||
override string toString() { result = completion.toString() }
|
||||
}
|
||||
|
||||
private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind {
|
||||
private class ConditionalCompletionSplitKind_ extends SplitKind, TConditionalCompletionSplitKind {
|
||||
override int getListOrder() { result = InitializerSplitting::getNextListOrder() }
|
||||
|
||||
override predicate isEnabled(AstNode cfe) { this.appliesTo(cfe) }
|
||||
@@ -271,89 +274,64 @@ module ConditionalCompletionSplitting {
|
||||
override string toString() { result = "ConditionalCompletion" }
|
||||
}
|
||||
|
||||
int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
|
||||
module ConditionalCompletionSplittingInput {
|
||||
private import Completion as Comp
|
||||
|
||||
private class ConditionalCompletionSplitImpl extends SplitImpl instanceof ConditionalCompletionSplit
|
||||
{
|
||||
ConditionalCompletion completion;
|
||||
class ConditionalCompletion = Comp::ConditionalCompletion;
|
||||
|
||||
ConditionalCompletionSplitImpl() { this = TConditionalCompletionSplit(completion) }
|
||||
class ConditionalCompletionSplitKind extends ConditionalCompletionSplitKind_, TSplitKind { }
|
||||
|
||||
override ConditionalCompletionSplitKind getKind() { any() }
|
||||
class ConditionalCompletionSplit = ConditionalCompletionSplitting::ConditionalCompletionSplit;
|
||||
|
||||
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||
succ(pred, succ, c) and
|
||||
last(succ, _, completion) and
|
||||
bindingset[parent, parentCompletion]
|
||||
predicate condPropagateExpr(
|
||||
AstNode parent, ConditionalCompletion parentCompletion, AstNode child,
|
||||
ConditionalCompletion childCompletion
|
||||
) {
|
||||
child = parent.(LogicalNotExpr).getOperand() and
|
||||
childCompletion.getDual() = parentCompletion
|
||||
or
|
||||
childCompletion = parentCompletion and
|
||||
(
|
||||
last(succ.(LogicalNotExpr).getOperand(), pred, c) and
|
||||
completion.(BooleanCompletion).getDual() = c
|
||||
child = parent.(LogicalAndExpr).getAnOperand()
|
||||
or
|
||||
last(succ.(LogicalAndExpr).getAnOperand(), pred, c) and
|
||||
completion = c
|
||||
child = parent.(LogicalOrExpr).getAnOperand()
|
||||
or
|
||||
last(succ.(LogicalOrExpr).getAnOperand(), pred, c) and
|
||||
completion = c
|
||||
parent = any(ConditionalExpr ce | child = [ce.getThen(), ce.getElse()])
|
||||
or
|
||||
succ =
|
||||
any(ConditionalExpr ce |
|
||||
last([ce.getThen(), ce.getElse()], pred, c) and
|
||||
completion = c
|
||||
)
|
||||
child = parent.(SwitchExpr).getACase()
|
||||
or
|
||||
succ =
|
||||
child = parent.(SwitchCaseExpr).getBody()
|
||||
or
|
||||
parent =
|
||||
any(NullCoalescingExpr nce |
|
||||
exists(Expr operand |
|
||||
last(operand, pred, c) and
|
||||
completion = c
|
||||
|
|
||||
if c instanceof NullnessCompletion
|
||||
then operand = nce.getRightOperand()
|
||||
else operand = nce.getAnOperand()
|
||||
)
|
||||
if childCompletion instanceof NullnessCompletion
|
||||
then child = nce.getRightOperand()
|
||||
else child = nce.getAnOperand()
|
||||
)
|
||||
)
|
||||
or
|
||||
child = parent.(NotPatternExpr).getPattern() and
|
||||
childCompletion.getDual() = parentCompletion
|
||||
or
|
||||
child = parent.(IsExpr).getPattern() and
|
||||
parentCompletion.(BooleanCompletion).getValue() =
|
||||
childCompletion.(MatchingCompletion).getValue()
|
||||
or
|
||||
childCompletion = parentCompletion and
|
||||
(
|
||||
child = parent.(AndPatternExpr).getAnOperand()
|
||||
or
|
||||
last(succ.(SwitchExpr).getACase(), pred, c) and
|
||||
completion = c
|
||||
child = parent.(OrPatternExpr).getAnOperand()
|
||||
or
|
||||
last(succ.(SwitchCaseExpr).getBody(), pred, c) and
|
||||
completion = c
|
||||
child = parent.(RecursivePatternExpr).getAChildExpr()
|
||||
or
|
||||
last(succ.(NotPatternExpr).getPattern(), pred, c) and
|
||||
completion.(MatchingCompletion).getDual() = c
|
||||
or
|
||||
last(succ.(IsExpr).getPattern(), pred, c) and
|
||||
completion.(BooleanCompletion).getValue() = c.(MatchingCompletion).getValue()
|
||||
or
|
||||
last(succ.(AndPatternExpr).getAnOperand(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
last(succ.(OrPatternExpr).getAnOperand(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
last(succ.(RecursivePatternExpr).getAChildExpr(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
last(succ.(PropertyPatternExpr).getPattern(_), pred, c) and
|
||||
completion = c
|
||||
child = parent.(PropertyPatternExpr).getPattern(_)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
|
||||
|
||||
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||
this.appliesTo(pred) and
|
||||
succ(pred, succ, c) and
|
||||
if c instanceof ConditionalCompletion then completion = c else any()
|
||||
}
|
||||
|
||||
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||
this.appliesTo(last) and
|
||||
scopeLast(scope, last, c) and
|
||||
if c instanceof ConditionalCompletion then completion = c else any()
|
||||
}
|
||||
|
||||
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() }
|
||||
}
|
||||
|
||||
int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
|
||||
}
|
||||
|
||||
module AssertionSplitting {
|
||||
|
||||
@@ -42,7 +42,7 @@ private module LogForgingConfig implements DataFlow::ConfigSig {
|
||||
*/
|
||||
module LogForging = TaintTracking::Global<LogForgingConfig>;
|
||||
|
||||
/** A source of remote user input. */
|
||||
/** A source supported by the current threat model. */
|
||||
private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { }
|
||||
|
||||
private class HtmlSanitizer extends Sanitizer {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.10
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
3
csharp/ql/src/change-notes/released/1.0.10.md
Normal file
3
csharp/ql/src/change-notes/released/1.0.10.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.10
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.9
|
||||
lastReleaseVersion: 1.0.10
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 1.0.10-dev
|
||||
version: 1.0.10
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -639,7 +639,7 @@ public class Inheritance
|
||||
public override string Prop { get { return tainted; } }
|
||||
}
|
||||
|
||||
public abstract class BaseContent
|
||||
public abstract class BaseContent
|
||||
{
|
||||
public abstract object GetValue();
|
||||
|
||||
@@ -961,3 +961,30 @@ public class Fanout
|
||||
return other + b2.GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
public class AvoidDuplicateLifted
|
||||
{
|
||||
public class A
|
||||
{
|
||||
public object Prop { get; set; }
|
||||
|
||||
// contentbased-summary=Models;AvoidDuplicateLifted+A;true;GetValue;();;Argument[this].Property[Models.AvoidDuplicateLifted+A.Prop];ReturnValue;value;dfc-generated
|
||||
// summary=Models;AvoidDuplicateLifted+A;true;GetValue;();;Argument[this];ReturnValue;taint;df-generated
|
||||
public virtual object GetValue()
|
||||
{
|
||||
return Prop;
|
||||
}
|
||||
}
|
||||
|
||||
public class B : A
|
||||
{
|
||||
private object field;
|
||||
|
||||
// No content based summary as field is a dead synthetic field.
|
||||
// summary=Models;AvoidDuplicateLifted+A;true;GetValue;();;Argument[this];ReturnValue;taint;df-generated
|
||||
public override object GetValue()
|
||||
{
|
||||
return field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ This example of an extensible predicate for a source is taken from the core Java
|
||||
.. code-block:: ql
|
||||
|
||||
extensible predicate sourceModel(
|
||||
string package, string type, boolean subtypes, string name,
|
||||
string signature, string ext, string output, string kind,
|
||||
string package, string type, boolean subtypes, string name,
|
||||
string signature, string ext, string output, string kind,
|
||||
string provenance
|
||||
);
|
||||
|
||||
@@ -36,7 +36,7 @@ An extensible predicate is a CodeQL predicate with the following restrictions:
|
||||
|
||||
- It uses the ``extensible`` keyword.
|
||||
- It has no body.
|
||||
- All predicate parameters have primitive types.
|
||||
- All predicate parameters have type ``string``, ``int``, ``float``, ``boolean``, or ``date``.
|
||||
- It is not in a module.
|
||||
|
||||
Columns shared by all extensible predicates
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
.. _codeql-cli-2.19.1:
|
||||
|
||||
==========================
|
||||
CodeQL 2.19.1 (2024-10-04)
|
||||
==========================
|
||||
|
||||
.. contents:: Contents
|
||||
:depth: 2
|
||||
:local:
|
||||
:backlinks: none
|
||||
|
||||
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/code-scanning/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
|
||||
|
||||
Security Coverage
|
||||
-----------------
|
||||
|
||||
CodeQL 2.19.1 runs a total of 426 security queries when configured with the Default suite (covering 164 CWE). The Extended suite enables an additional 128 queries (covering 34 more CWE).
|
||||
|
||||
CodeQL CLI
|
||||
----------
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* The command :code:`codeql generate query-help` now supports Markdown help files.
|
||||
The Markdown help format is commonly used in custom CodeQL query packs. This new feature allows us to generate SARIF reporting descriptors for CodeQL queries that include Markdown help directly from a query Markdown help file.
|
||||
|
||||
* Added a new command, :code:`codeql resolve packs`. This command shows each step in the pack search process, including what packs were found in each step. With the
|
||||
:code:`--show-hidden-packs` option, it can also show details on which packs were hidden by packs found earlier in the search sequence. :code:`codeql resolve packs` is intended as a replacement for most uses of :code:`codeql resolve qlpacks`, whose output is both less detailed and less accurate.
|
||||
|
||||
Query Packs
|
||||
-----------
|
||||
|
||||
Minor Analysis Improvements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
C/C++
|
||||
"""""
|
||||
|
||||
* Fixed false positives in the :code:`cpp/wrong-number-format-arguments` ("Too few arguments to formatting function") query when the formatting function has been declared implicitly.
|
||||
|
||||
C#
|
||||
""
|
||||
|
||||
* C#: The indexer and :code:`Add` method on :code:`System.Web.UI.AttributeCollection` is no longer considered an HTML sink.
|
||||
|
||||
Java/Kotlin
|
||||
"""""""""""
|
||||
|
||||
* Added taint summary model for :code:`org.springframework.core.io.InputStreamSource#getInputStream()`.
|
||||
|
||||
New Queries
|
||||
~~~~~~~~~~~
|
||||
|
||||
Python
|
||||
""""""
|
||||
|
||||
* The :code:`py/cors-misconfiguration-with-credentials` query, which finds insecure CORS middleware configurations.
|
||||
|
||||
Query Metadata Changes
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Golang
|
||||
""""""
|
||||
|
||||
* The precision of the :code:`go/incorrect-integer-conversion-query` query was decreased from :code:`very-high` to :code:`high`, since there is at least one known class of false positives involving dynamic bounds checking.
|
||||
|
||||
Language Libraries
|
||||
------------------
|
||||
|
||||
Breaking Changes
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
C#
|
||||
""
|
||||
|
||||
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using :code:`Attribute.Getter` or :code:`Attribute.Setter` in the model :code:`ext` field applies the model to the getter or setter for properties and indexers. Prior to this change :code:`Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the :code:`Attribute` feature directly on a property for a property setter needs to be changed to :code:`Attribute.Setter`.
|
||||
* C#: Remove all CIL tables and related QL library functionality.
|
||||
|
||||
Minor Analysis Improvements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
C#
|
||||
""
|
||||
|
||||
* :code:`DataFlow::Node` instances are no longer created for library methods and fields that are not callable (either statically or dynamically) or otherwise referred to from source code. This may affect third-party queries that use these nodes to identify library methods or fields that are present in DLL files where those methods or fields are unreferenced. If this presents a problem, consider using :code:`Callable` and other non-dataflow classes to identify such library entities.
|
||||
* C#: Add extractor support for attributes on indexers.
|
||||
|
||||
Golang
|
||||
""""""
|
||||
|
||||
* A method in the method set of an embedded field of a struct should not be promoted to the method set of the struct if the struct has a method with the same name. This was not being enforced, which meant that there were two methods with the same qualified name, and models were sometimes being applied when they shouldn't have been. This has now been fixed.
|
||||
|
||||
Python
|
||||
""""""
|
||||
|
||||
* The common sanitizer guard :code:`StringConstCompareBarrier` has been renamed to :code:`ConstCompareBarrier` and expanded to cover comparisons with other constant values such as :code:`None`. This may result in fewer false positive results for several queries.
|
||||
|
||||
Swift
|
||||
"""""
|
||||
|
||||
* All AST classes in :code:`codeql.swift.elements` are now :code:`final`, which means that it is no longer possible to :code:`override` predicates defined in those classes (it is, however, still possible to :code:`extend` the classes).
|
||||
|
||||
Deprecated APIs
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
C#
|
||||
""
|
||||
|
||||
* The class :code:`ThreatModelFlowSource` has been renamed to :code:`ActiveThreatModelSource` to more clearly reflect it only contains the currently active threat model sources. :code:`ThreatModelFlowSource` has been marked as deprecated.
|
||||
|
||||
Golang
|
||||
""""""
|
||||
|
||||
* The class :code:`ThreatModelFlowSource` has been renamed to :code:`ActiveThreatModelSource` to more clearly reflect it only contains the currently active threat model sources. :code:`ThreatModelFlowSource` has been marked as deprecated.
|
||||
|
||||
Java/Kotlin
|
||||
"""""""""""
|
||||
|
||||
* The :code:`Field.getSourceDeclaration()` predicate has been deprecated. The result was always the original field, so calls to it can simply be removed.
|
||||
* The :code:`Field.isSourceDeclaration()` predicate has been deprecated. It always holds.
|
||||
* The :code:`RefType.nestedName()` predicate has been deprecated, and :code:`RefType.getNestedName()` added to replace it.
|
||||
* The class :code:`ThreatModelFlowSource` has been renamed to :code:`ActiveThreatModelSource` to more clearly reflect it only contains the currently active threat model sources. :code:`ThreatModelFlowSource` has been marked as deprecated.
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Java/Kotlin
|
||||
"""""""""""
|
||||
|
||||
* The Java extractor and QL libraries now support Java 23.
|
||||
* Kotlin versions up to 2.1.0\ *x* are now supported.
|
||||
|
||||
Python
|
||||
""""""
|
||||
|
||||
* Added support for custom threat-models, which can be used in most of our taint-tracking queries, see our `documentation <https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-threat-models>`__ for more details.
|
||||
@@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here <https://docs.g
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
codeql-cli-2.19.1
|
||||
codeql-cli-2.19.0
|
||||
codeql-cli-2.18.4
|
||||
codeql-cli-2.18.3
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
latest version of CodeQL...</div>
|
||||
</div>
|
||||
<div class="Subhead border-0">
|
||||
<a href="codeql-overview/supported-languages-and-frameworks/">
|
||||
<a href="../codeql-query-help/codeql-cwe-coverage/">
|
||||
<div class="Subhead-heading f4 text-center">CodeQL coverage of CWEs</div>
|
||||
</a>
|
||||
<div class="Subhead-description">Detailed information on the coverage of Common Weakness Enumerations (CWEs) in the latest release...</div>
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
Modules
|
||||
#######
|
||||
|
||||
Modules provide a way of organizing QL code by grouping together related types, predicates, and other modules.
|
||||
|
||||
You can import modules into other files, which avoids duplication, and helps
|
||||
Modules provide a way of organizing QL code by grouping together related types, predicates, and other modules.
|
||||
|
||||
You can import modules into other files, which avoids duplication, and helps
|
||||
structure your code into more manageable pieces.
|
||||
|
||||
.. _defining-module:
|
||||
@@ -16,7 +16,7 @@ Defining a module
|
||||
*****************
|
||||
|
||||
There are various ways to define modules—here is an example of the simplest way, declaring an
|
||||
:ref:`explicit module <explicit-modules>` named ``Example`` containing
|
||||
:ref:`explicit module <explicit-modules>` named ``Example`` containing
|
||||
a class ``OneTwoThree``:
|
||||
|
||||
.. code-block:: ql
|
||||
@@ -27,17 +27,17 @@ a class ``OneTwoThree``:
|
||||
this = 1 or this = 2 or this = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
The name of a module can be any `identifier <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers>`_
|
||||
that starts with an uppercase or lowercase letter.
|
||||
that starts with an uppercase or lowercase letter.
|
||||
|
||||
``.ql`` or ``.qll`` files also implicitly define modules.
|
||||
For more information, see ":ref:`kinds-of-modules`."
|
||||
|
||||
You can also annotate a module. For more information, see of ":ref:`annotations-overview`."
|
||||
|
||||
Note that you can only annotate :ref:`explicit modules <explicit-modules>`.
|
||||
Note that you can only annotate :ref:`explicit modules <explicit-modules>`.
|
||||
File modules cannot be annotated.
|
||||
|
||||
.. _kinds-of-modules:
|
||||
@@ -48,7 +48,7 @@ Kinds of modules
|
||||
File modules
|
||||
============
|
||||
|
||||
Each query file (extension ``.ql``) and library file (extension ``.qll``) implicitly defines
|
||||
Each query file (extension ``.ql``) and library file (extension ``.qll``) implicitly defines
|
||||
a module. The module has the same name as the file, but any spaces in the file name are replaced
|
||||
by underscores (``_``). The contents of the file form the :ref:`body of the module <module-bodies>`.
|
||||
|
||||
@@ -57,7 +57,7 @@ by underscores (``_``). The contents of the file form the :ref:`body of the modu
|
||||
Library modules
|
||||
---------------
|
||||
|
||||
A library module is defined by a ``.qll`` file. It can contain any of the
|
||||
A library module is defined by a ``.qll`` file. It can contain any of the
|
||||
elements listed in :ref:`module-bodies` below, apart from select clauses.
|
||||
|
||||
For example, consider the following QL library:
|
||||
@@ -75,19 +75,19 @@ For example, consider the following QL library:
|
||||
This file defines a library module named ``OneTwoThreeLib``. The body of this module
|
||||
defines the class ``OneTwoThree``.
|
||||
|
||||
.. _query-modules:
|
||||
.. _query-modules:
|
||||
|
||||
Query modules
|
||||
-------------
|
||||
|
||||
A query module is defined by a ``.ql`` file. It can contain any of the elements listed
|
||||
in :ref:`module-bodies` below.
|
||||
A query module is defined by a ``.ql`` file. It can contain any of the elements listed
|
||||
in :ref:`module-bodies` below.
|
||||
|
||||
Query modules are slightly different from other modules:
|
||||
|
||||
- A query module can't be imported.
|
||||
- A query module must have at least one query in its
|
||||
:ref:`namespace <namespaces>`. This is usually a :ref:`select clause <select-clauses>`,
|
||||
- A query module must have at least one query in its
|
||||
:ref:`namespace <namespaces>`. This is usually a :ref:`select clause <select-clauses>`,
|
||||
but can also be a :ref:`query predicate <query-predicates>`.
|
||||
|
||||
For example:
|
||||
@@ -97,7 +97,7 @@ For example:
|
||||
.. code-block:: ql
|
||||
|
||||
import OneTwoThreeLib
|
||||
|
||||
|
||||
from OneTwoThree ott
|
||||
where ott = 1 or ott = 2
|
||||
select ott
|
||||
@@ -110,13 +110,13 @@ This file defines a query module named ``OneTwoQuery``. The body of this module
|
||||
Explicit modules
|
||||
================
|
||||
|
||||
You can also define a module within another module. This is an explicit module definition.
|
||||
You can also define a module within another module. This is an explicit module definition.
|
||||
|
||||
An explicit module is defined with the keyword ``module`` followed by
|
||||
the module name, and then the module body enclosed in braces. It can contain any
|
||||
of the elements listed in ":ref:`module-bodies`" below, apart from select clauses.
|
||||
An explicit module is defined with the keyword ``module`` followed by
|
||||
the module name, and then the module body enclosed in braces. It can contain any
|
||||
of the elements listed in ":ref:`module-bodies`" below, apart from select clauses.
|
||||
|
||||
For example, you could add the following QL snippet to the library file **OneTwoThreeLib.qll**
|
||||
For example, you could add the following QL snippet to the library file **OneTwoThreeLib.qll**
|
||||
defined :ref:`above <library-modules>`:
|
||||
|
||||
.. code-block:: ql
|
||||
@@ -129,7 +129,7 @@ defined :ref:`above <library-modules>`:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
This defines an explicit module named ``M``. The body of this module defines
|
||||
the class ``OneTwo``.
|
||||
|
||||
@@ -226,7 +226,7 @@ Module bodies
|
||||
*************
|
||||
|
||||
The body of a module is the code inside the module definition, for example
|
||||
the class ``OneTwo`` in the :ref:`explicit module <explicit-modules>` ``M``.
|
||||
the class ``OneTwo`` in the :ref:`explicit module <explicit-modules>` ``M``.
|
||||
|
||||
In general, the body of a module can contain the following constructs:
|
||||
|
||||
@@ -243,11 +243,11 @@ In general, the body of a module can contain the following constructs:
|
||||
Importing modules
|
||||
*****************
|
||||
|
||||
The main benefit of storing code in a module is that you can reuse it in other modules.
|
||||
To access the contents of an external module, you can import the module using an
|
||||
The main benefit of storing code in a module is that you can reuse it in other modules.
|
||||
To access the contents of an external module, you can import the module using an
|
||||
:ref:`import statement <import-statements>`.
|
||||
|
||||
When you import a module this brings all the names in its namespace, apart from :ref:`private` names,
|
||||
When you import a module this brings all the names in its namespace, apart from :ref:`private` names,
|
||||
into the :ref:`namespace <namespaces>` of the current module.
|
||||
|
||||
.. _import-statements:
|
||||
@@ -263,7 +263,7 @@ Import statements are used for importing modules. They are of the form:
|
||||
import <module_expression2>
|
||||
|
||||
Import statements are usually listed at the beginning of the module. Each
|
||||
import statement imports one module. You can import multiple modules by
|
||||
import statement imports one module. You can import multiple modules by
|
||||
including multiple import statements (one for each module you want to import).
|
||||
|
||||
An import statement can also be :ref:`annotated <annotations-overview>` with
|
||||
@@ -272,14 +272,14 @@ An import statement can also be :ref:`annotated <annotations-overview>` with
|
||||
only reachable through deprecated imports in a given context then usage of the
|
||||
name in that context will generate deprecation warnings.
|
||||
|
||||
You can import a module under a different name using the ``as`` keyword,
|
||||
You can import a module under a different name using the ``as`` keyword,
|
||||
for example ``import javascript as js``.
|
||||
|
||||
The ``<module_expression>`` itself can be a module name, a selection, or a qualified
|
||||
reference. For more information, see ":ref:`name-resolution`."
|
||||
|
||||
For information about how import statements are looked up, see "`Module resolution <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#module-resolution>`__"
|
||||
in the QL language specification.
|
||||
in the QL language specification.
|
||||
|
||||
Built-in modules
|
||||
****************
|
||||
@@ -353,7 +353,7 @@ Sets
|
||||
|
||||
The built-in ``InternSets`` module is parameterized by ``Key`` and ``Value`` types
|
||||
and a ``Value getAValue(Key key)`` relation. The module groups the ``Value``
|
||||
column by ``Key`` and creates a set for each group of values related by a key.
|
||||
column by ``Key`` and creates a set for each group of values related by a key.
|
||||
|
||||
The ``InternSets`` module exports a functional ``Set getSet(Key key)`` relation
|
||||
that relates keys with the set of value related to the given key by
|
||||
@@ -424,3 +424,30 @@ The above query therefore evalutes to:
|
||||
+----+----+
|
||||
| 4 | 4 |
|
||||
+----+----+
|
||||
|
||||
.. index:: BigInt
|
||||
.. _bigint:
|
||||
|
||||
BigInt
|
||||
======
|
||||
|
||||
The built-in ``QlBuiltins`` module provides an **experimental** type ``BigInt`` of arbitrary-precision integers.
|
||||
|
||||
This type is not available in the CodeQL CLI by default, but you can enable it by passing the ``--allow-experimental=bigint``
|
||||
option to the CodeQL CLI. Consequently, BigInts are currently disallowed in query results and dbscheme columns.
|
||||
|
||||
Unlike ``int`` and ``float``, there is no automatic conversion between ``BigInt`` and other numeric types.
|
||||
Instead, big integers can be constructed using the ``.toBigInt()`` methods of ``int`` and ``string``.
|
||||
|
||||
The other built-in operations are:
|
||||
|
||||
* comparisons between ``BigInt``\s: ``=``, ``!=``, ``<``, ``<=``, ``>``, ``>=``,
|
||||
* conversions from ``BigInt``\s to strings or integers (if within range): ``.toString()``, ``.toInt()``,
|
||||
* ``BigInt`` arithmetic: binary ``+``, ``-``, ``*``, ``/``, ``%``, unary ``-``,
|
||||
* bitwise operations: ``.bitAnd(BigInt)``, ``.bitOr(BigInt)``,
|
||||
``.bitXor(BigInt)``, ``.bitShiftLeft(int)``, ``.bitShiftRightSigned(int)``,
|
||||
``.bitNot()``,
|
||||
* aggregates: ``min``, ``max``, (``strict``)\ ``sum``, (``strict``)\ ``count``, ``avg``,
|
||||
``rank``, ``unique``, ``any``.
|
||||
* other: ``.pow(int)``, ``.abs()``, ``.gcd(BigInt)``, ``.minimum(BigInt)``,
|
||||
``.maximum(BigInt)``.
|
||||
|
||||
@@ -359,7 +359,7 @@ Kinds of types
|
||||
|
||||
Types in QL are either *primitive* types, *database* types, *class* types, *character* types, *class domain* types, type *parameters*, or *instantiation-nested* types.
|
||||
|
||||
The primitive types are ``boolean``, ``date``, ``float``, ``int``, and ``string``.
|
||||
The primitive types are ``boolean``, ``date``, ``float``, ``int``, ``string``, and ``QlBuiltins::BigInt``.
|
||||
|
||||
Database types are supplied as part of the database. Each database type has a *name*, which is an identifier starting with an at sign (``@``, U+0040) followed by lower-case letter. Database types have some number of *base types*, which are other database types. In a valid database, the base types relation is non-cyclic.
|
||||
|
||||
@@ -433,7 +433,7 @@ Values are the fundamental data that QL programs compute over. This section spec
|
||||
Kinds of values
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
There are six kinds of values in QL: one kind for each of the five primitive types, and *entities*. Each value has a type.
|
||||
There are seven kinds of values in QL: one kind for each of the six primitive types, and *entities*. Each value has a type.
|
||||
|
||||
A boolean value is of type ``boolean``, and may have one of two distinct values: ``true`` or ``false``.
|
||||
|
||||
@@ -445,6 +445,8 @@ An integer value is of type ``int``. Each value is a 32-bit two's complement int
|
||||
|
||||
A string is a finite sequence of 16-bit characters. The characters are interpreted as Unicode code points.
|
||||
|
||||
A :ref:`big integer <bigint>` value is of type ``QlBuiltins::BigInt``. Each value is a signed arbitrary-precision integer.
|
||||
|
||||
The database includes a number of opaque entity values. Each such value has a type that is one of the database types, and an identifying integer. An entity value is written as the name of its database type followed by its identifying integer in parentheses. For example, ``@tree(12)``, ``@person(16)``, and ``@location(38132)`` are entity values. The identifying integers are left opaque to programmers in this specification, so an implementation of QL is free to use some other set of countable labels to identify its entities.
|
||||
|
||||
Ordering
|
||||
@@ -458,7 +460,7 @@ For dates, the ordering is chronological.
|
||||
|
||||
For floats, the ordering is as specified in IEEE 754 when one exists, except that NaN is considered equal to itself and is ordered after all other floats, and negative zero is considered to be strictly less than positive zero.
|
||||
|
||||
For integers, the ordering is as for two's complement integers.
|
||||
For integers (and :ref:`big integers <bigint>`), the ordering is numerical.
|
||||
|
||||
For strings, the ordering is lexicographic.
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@ Types
|
||||
QL is a statically typed language, so each variable must have a declared type.
|
||||
|
||||
A type is a set of values.
|
||||
For example, the type ``int`` is the set of integers.
|
||||
Note that a value can belong to more than one of these sets, which means that it can have more
|
||||
For example, the type ``int`` is the set of integers.
|
||||
Note that a value can belong to more than one of these sets, which means that it can have more
|
||||
than one type.
|
||||
|
||||
The kinds of types in QL are :ref:`primitive types <primitive-types>`, :ref:`classes <classes>`,
|
||||
:ref:`character types <character-types>`, :ref:`class domain types <domain-types>`,
|
||||
:ref:`character types <character-types>`, :ref:`class domain types <domain-types>`,
|
||||
:ref:`algebraic datatypes <algebraic-datatypes>`, :ref:`type unions <type-unions>`,
|
||||
and :ref:`database types <database-types>`.
|
||||
|
||||
@@ -31,27 +31,29 @@ independent of the database that you are querying.
|
||||
.. _boolean:
|
||||
|
||||
#. **boolean**: This type contains the values ``true`` and ``false``.
|
||||
|
||||
|
||||
.. _float:
|
||||
|
||||
#. **float**: This type contains 64-bit floating point numbers, such as ``6.28`` and ``-0.618``.
|
||||
|
||||
|
||||
.. _int:
|
||||
|
||||
#. **int**: This type contains 32-bit `two's complement <https://en.wikipedia.org/wiki/Two%27s_complement>`_ integers, such as ``-1`` and ``42``.
|
||||
|
||||
|
||||
.. _string:
|
||||
|
||||
#. **string**: This type contains finite strings of 16-bit characters.
|
||||
|
||||
|
||||
.. _date:
|
||||
|
||||
#. **date**: This type contains dates (and optionally times).
|
||||
|
||||
#. **date**: This type contains dates (and optionally times).
|
||||
|
||||
|
||||
QL has a range of built-in operations defined on primitive types. These are available by using dispatch on expressions of the appropriate type. For example, ``1.toString()`` is the string representation of the integer constant ``1``. For a full list of built-in operations available in QL, see the
|
||||
section on `built-ins <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#built-ins>`__ in the QL language specification.
|
||||
|
||||
Additionally, there is an experimental arbitrary-precision integer primitive type at :ref:`QlBuiltins::BigInt <bigint>`. This type is not available in the CodeQL CLI by default, but you can enable it by passing the ``--allow-experimental=bigint`` option to the CodeQL CLI.
|
||||
|
||||
.. index:: class
|
||||
.. _classes:
|
||||
|
||||
@@ -65,7 +67,7 @@ Classes provide an easy way to reuse and structure code. For example, you can:
|
||||
- Define :ref:`member predicates <member-predicates>` on those values.
|
||||
- Define subclasses that :ref:`override member predicates <overriding-member-predicates>`.
|
||||
|
||||
A class in QL doesn't "create" a new object, it just represents a logical property. A value is
|
||||
A class in QL doesn't "create" a new object, it just represents a logical property. A value is
|
||||
in a particular class if it satisfies that logical property.
|
||||
|
||||
.. _defining-a-class:
|
||||
@@ -75,8 +77,8 @@ Defining a class
|
||||
|
||||
To define a class, you write:
|
||||
|
||||
#. The keyword ``class``.
|
||||
#. The name of the class. This is an `identifier <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers>`_
|
||||
#. The keyword ``class``.
|
||||
#. The name of the class. This is an `identifier <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers>`_
|
||||
starting with an uppercase letter.
|
||||
#. The supertypes that the class is derived from via `extends` and/or `instanceof`
|
||||
#. The :ref:`body of the class <class-bodies>`, enclosed in braces.
|
||||
@@ -89,11 +91,11 @@ For example:
|
||||
OneTwoThree() { // characteristic predicate
|
||||
this = 1 or this = 2 or this = 3
|
||||
}
|
||||
|
||||
|
||||
string getAString() { // member predicate
|
||||
result = "One, two or three: " + this.toString()
|
||||
}
|
||||
|
||||
|
||||
predicate isEven() { // member predicate
|
||||
this = 2
|
||||
}
|
||||
@@ -101,7 +103,7 @@ For example:
|
||||
|
||||
This defines a class ``OneTwoThree``, which contains the values ``1``, ``2``, and ``3``. The
|
||||
:ref:`characteristic predicate <characteristic-predicates>` captures the logical property of
|
||||
"being one of the integers 1, 2, or 3."
|
||||
"being one of the integers 1, 2, or 3."
|
||||
|
||||
.. index:: extends
|
||||
|
||||
@@ -132,12 +134,12 @@ Class bodies
|
||||
The body of a class can contain:
|
||||
- A :ref:`characteristic predicate <characteristic-predicates>` declaration.
|
||||
- Any number of :ref:`member predicate <member-predicates>` declarations.
|
||||
- Any number of :ref:`field <fields>` declarations.
|
||||
- Any number of :ref:`field <fields>` declarations.
|
||||
|
||||
When you define a class, that class also inherits all non-:ref:`private` member predicates and
|
||||
fields from its supertypes.
|
||||
|
||||
Depending on whether they are final, you can :ref:`override <overriding-member-predicates>` or
|
||||
Depending on whether they are final, you can :ref:`override <overriding-member-predicates>` or
|
||||
:ref:`shadow <final-extensions>` those predicates and fields to give them a more specific definition.
|
||||
|
||||
.. _characteristic-predicates:
|
||||
@@ -181,22 +183,22 @@ This call returns ``"ONE, TWO OR THREE: 1"``.
|
||||
|
||||
.. pull-quote:: Note
|
||||
|
||||
Characteristic predicates and member predicates often use the variable ``this``.
|
||||
This variable always refers to a member of the class—in this case a value belonging to the
|
||||
Characteristic predicates and member predicates often use the variable ``this``.
|
||||
This variable always refers to a member of the class—in this case a value belonging to the
|
||||
class ``OneTwoThree``.
|
||||
In the :ref:`characteristic predicate <characteristic-predicates>`, the variable ``this``
|
||||
In the :ref:`characteristic predicate <characteristic-predicates>`, the variable ``this``
|
||||
constrains the values that are in the class.
|
||||
In a :ref:`member predicate <member-predicates>`, ``this`` acts in the same way as any
|
||||
In a :ref:`member predicate <member-predicates>`, ``this`` acts in the same way as any
|
||||
other argument to the predicate.
|
||||
|
||||
.. index:: field
|
||||
.. _fields:
|
||||
.. _fields:
|
||||
|
||||
Fields
|
||||
------
|
||||
|
||||
These are variables declared in the body of a class. A class can have any number of field
|
||||
declarations (that is, variable declarations) within its body. You can use these variables in
|
||||
declarations (that is, variable declarations) within its body. You can use these variables in
|
||||
predicate declarations inside the class. Much like the :ref:`variable <this>` ``this``, fields
|
||||
must be constrained in the :ref:`characteristic predicate <characteristic-predicates>`.
|
||||
|
||||
@@ -207,21 +209,21 @@ For example:
|
||||
class SmallInt extends int {
|
||||
SmallInt() { this = [1 .. 10] }
|
||||
}
|
||||
|
||||
|
||||
class DivisibleInt extends SmallInt {
|
||||
SmallInt divisor; // declaration of the field `divisor`
|
||||
DivisibleInt() { this % divisor = 0 }
|
||||
|
||||
|
||||
SmallInt getADivisor() { result = divisor }
|
||||
}
|
||||
|
||||
|
||||
from DivisibleInt i
|
||||
select i, i.getADivisor()
|
||||
|
||||
In this example, the declaration ``SmallInt divisor`` introduces a field ``divisor``, constrains
|
||||
it in the characteristic predicate, and then uses it in the declaration of the member predicate
|
||||
``getADivisor``. This is similar to introducing variables in a :ref:`select clause <select-clauses>`
|
||||
by declaring them in the ``from`` part.
|
||||
by declaring them in the ``from`` part.
|
||||
|
||||
You can also annotate predicates and fields. See the list of :ref:`annotations <annotations-overview>`
|
||||
that are available.
|
||||
@@ -231,7 +233,7 @@ that are available.
|
||||
Concrete classes
|
||||
================
|
||||
|
||||
The classes in the above examples are all **concrete** classes. They are defined by
|
||||
The classes in the above examples are all **concrete** classes. They are defined by
|
||||
restricting the values in a larger type. The values in a concrete class are precisely those
|
||||
values in the intersection of the supertypes that also satisfy the
|
||||
:ref:`characteristic predicate <characteristic-predicates>` of the class.
|
||||
@@ -241,32 +243,32 @@ values in the intersection of the supertypes that also satisfy the
|
||||
Abstract classes
|
||||
================
|
||||
|
||||
A class :ref:`annotated <abstract>` with ``abstract``, known as an **abstract** class, is also a restriction of
|
||||
the values in a larger type. However, an abstract class is defined as the union of its
|
||||
subclasses. In particular, for a value to be in an abstract class, it must satisfy the
|
||||
A class :ref:`annotated <abstract>` with ``abstract``, known as an **abstract** class, is also a restriction of
|
||||
the values in a larger type. However, an abstract class is defined as the union of its
|
||||
subclasses. In particular, for a value to be in an abstract class, it must satisfy the
|
||||
characteristic predicate of the class itself **and** the characteristic predicate of a subclass.
|
||||
Note that final extensions are not considered subclasses in this context.
|
||||
|
||||
An abstract class is useful if you want to group multiple existing classes together
|
||||
under a common name. You can then define member predicates on all those classes. You can also
|
||||
extend predefined abstract classes: for example, if you import a library that contains an
|
||||
An abstract class is useful if you want to group multiple existing classes together
|
||||
under a common name. You can then define member predicates on all those classes. You can also
|
||||
extend predefined abstract classes: for example, if you import a library that contains an
|
||||
abstract class, you can add more subclasses to it.
|
||||
|
||||
**Example**
|
||||
|
||||
If you are writing a security query, you may be interested in identifying
|
||||
all expressions that can be interpreted as SQL queries.
|
||||
If you are writing a security query, you may be interested in identifying
|
||||
all expressions that can be interpreted as SQL queries.
|
||||
You can use the following abstract class to describe these expressions:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
abstract class SqlExpr extends Expr {
|
||||
...
|
||||
...
|
||||
}
|
||||
|
||||
Now define various subclasses—one for each kind of database management system. For example, you
|
||||
can define a subclass ``class PostgresSqlExpr extends SqlExpr``, which contains expressions
|
||||
passed to some Postgres API that performs a database query.
|
||||
can define a subclass ``class PostgresSqlExpr extends SqlExpr``, which contains expressions
|
||||
passed to some Postgres API that performs a database query.
|
||||
You can define similar subclasses for MySQL and other database management systems.
|
||||
|
||||
The abstract class ``SqlExpr`` refers to all of those different expressions. If you want to add
|
||||
@@ -278,7 +280,7 @@ there is no need to update the queries that rely on it.
|
||||
|
||||
You must take care when you add a new subclass to an existing abstract class. Adding a subclass
|
||||
is not an isolated change, it also extends the abstract class since that is a union of its
|
||||
subclasses.
|
||||
subclasses.
|
||||
|
||||
.. _overriding-member-predicates:
|
||||
|
||||
@@ -288,7 +290,7 @@ Overriding member predicates
|
||||
If a class inherits a member predicate from a non-final supertype, you can **override** the
|
||||
inherited definition. You do this by defining a member predicate with the same name and arity
|
||||
as the inherited predicate, and by adding the ``override`` :ref:`annotation <override>`.
|
||||
This is useful if you want to refine the predicate to give a more specific result for the
|
||||
This is useful if you want to refine the predicate to give a more specific result for the
|
||||
values in the subclass.
|
||||
|
||||
For example, extending the class from the :ref:`first example <defining-a-class>`:
|
||||
@@ -299,7 +301,7 @@ For example, extending the class from the :ref:`first example <defining-a-class>
|
||||
OneTwo() {
|
||||
this = 1 or this = 2
|
||||
}
|
||||
|
||||
|
||||
override string getAString() {
|
||||
result = "One or two: " + this.toString()
|
||||
}
|
||||
@@ -328,7 +330,7 @@ look like this:
|
||||
| 3 | One, two or three: 3 |
|
||||
+---+-------------------------+
|
||||
|
||||
In QL, unlike other object-oriented languages, different subtypes of the same types don't need to be
|
||||
In QL, unlike other object-oriented languages, different subtypes of the same types don't need to be
|
||||
disjoint. For example, you could define another subclass of ``OneTwoThree``, which overlaps
|
||||
with ``OneTwo``:
|
||||
|
||||
@@ -338,14 +340,14 @@ with ``OneTwo``:
|
||||
TwoThree() {
|
||||
this = 2 or this = 3
|
||||
}
|
||||
|
||||
|
||||
override string getAString() {
|
||||
result = "Two or three: " + this.toString()
|
||||
}
|
||||
}
|
||||
|
||||
Now the value 2 is included in both class types ``OneTwo`` and ``TwoThree``. Both of these classes
|
||||
override the original definition of ``getAString()``. There are two new "most specific" definitions,
|
||||
Now the value 2 is included in both class types ``OneTwo`` and ``TwoThree``. Both of these classes
|
||||
override the original definition of ``getAString()``. There are two new "most specific" definitions,
|
||||
so running the above query gives the following results:
|
||||
|
||||
+---+-------------------------+
|
||||
@@ -373,7 +375,7 @@ For example, using the definitions from the above section:
|
||||
|
||||
class Two extends OneTwo, TwoThree {}
|
||||
|
||||
Any value in the class ``Two`` must satisfy the logical property represented by ``OneTwo``,
|
||||
Any value in the class ``Two`` must satisfy the logical property represented by ``OneTwo``,
|
||||
**and** the logical property represented by ``TwoThree``. Here the class ``Two`` contains one
|
||||
value, namely 2.
|
||||
|
||||
@@ -401,12 +403,12 @@ For example, extending the class from the :ref:`first example <defining-a-class>
|
||||
.. code-block:: ql
|
||||
|
||||
final class FinalOneTwoThree = OneTwoThree;
|
||||
|
||||
|
||||
class OneTwoFinalExtension extends FinalOneTwoThree {
|
||||
OneTwoFinalExtension() {
|
||||
this = 1 or this = 2
|
||||
}
|
||||
|
||||
|
||||
string getAString() {
|
||||
result = "One or two: " + this.toString()
|
||||
}
|
||||
@@ -507,19 +509,19 @@ Had ``Bar`` been defined as ``extends Foo``, then ``select any(Foo f).foo()`` wo
|
||||
Character types and class domain types
|
||||
**************************************
|
||||
|
||||
You can't refer to these types directly, but each class in QL implicitly defines a character
|
||||
type and a class domain type. (These are rather more subtle concepts and don't appear very
|
||||
You can't refer to these types directly, but each class in QL implicitly defines a character
|
||||
type and a class domain type. (These are rather more subtle concepts and don't appear very
|
||||
often in practical query writing.)
|
||||
|
||||
The **character type** of a QL class is the set of values satisfying the :ref:`characteristic
|
||||
predicate <characteristic-predicates>` of the class.
|
||||
It is a subset of the domain type. For concrete classes, a value belongs to
|
||||
the class if, and only if, it is in the character type. For :ref:`abstract classes
|
||||
The **character type** of a QL class is the set of values satisfying the :ref:`characteristic
|
||||
predicate <characteristic-predicates>` of the class.
|
||||
It is a subset of the domain type. For concrete classes, a value belongs to
|
||||
the class if, and only if, it is in the character type. For :ref:`abstract classes
|
||||
<abstract-classes>`, a value must also belong to at least one of the subclasses, in addition to
|
||||
being in the character type.
|
||||
being in the character type.
|
||||
|
||||
The **domain type** of a QL class is the intersection of the character types of all its supertypes, that is, a value
|
||||
belongs to the domain type if it belongs to every supertype. It occurs as the type of ``this``
|
||||
belongs to the domain type if it belongs to every supertype. It occurs as the type of ``this``
|
||||
in the characteristic predicate of a class.
|
||||
|
||||
.. index:: newtype
|
||||
@@ -570,13 +572,13 @@ The branch definitions have the following form:
|
||||
|
||||
<BranchName>(<arguments>) { <body> }
|
||||
|
||||
- The type name and the branch names must be `identifiers <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers>`_
|
||||
- The type name and the branch names must be `identifiers <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers>`_
|
||||
starting with an uppercase letter. Conventionally, they start with ``T``.
|
||||
- The different branches of an algebraic datatype are separated by ``or``.
|
||||
- The arguments to a branch, if any, are :ref:`variable declarations <variable-declarations>`
|
||||
separated by commas.
|
||||
- The body of a branch is a :ref:`predicate <predicates>` body. You can omit the branch body, in which case
|
||||
it defaults to ``any()``.
|
||||
it defaults to ``any()``.
|
||||
Note that branch bodies are evaluated fully, so they must be finite. They should be kept small
|
||||
for good performance.
|
||||
|
||||
@@ -586,28 +588,28 @@ For example, the following algebraic datatype has three branches:
|
||||
|
||||
newtype T =
|
||||
Type1(A a, B b) { body(a, b) }
|
||||
or
|
||||
or
|
||||
Type2(C c)
|
||||
or
|
||||
or
|
||||
Type3()
|
||||
|
||||
Standard pattern for using algebraic datatypes
|
||||
==============================================
|
||||
|
||||
Algebraic datatypes are different from :ref:`classes <classes>`. In particular, algebraic datatypes don't have a
|
||||
Algebraic datatypes are different from :ref:`classes <classes>`. In particular, algebraic datatypes don't have a
|
||||
``toString()`` member predicate, so you can't use them in a :ref:`select clause <select-clauses>`.
|
||||
|
||||
Classes are often used to extend algebraic datatypes (and to provide a ``toString()`` predicate).
|
||||
Classes are often used to extend algebraic datatypes (and to provide a ``toString()`` predicate).
|
||||
In the standard QL language libraries, this is usually done as follows:
|
||||
|
||||
- Define a class ``A`` that extends the algebraic datatype and optionally declares :ref:`abstract`
|
||||
predicates.
|
||||
- For each branch type, define a class ``B`` that extends both ``A`` and the branch type,
|
||||
- For each branch type, define a class ``B`` that extends both ``A`` and the branch type,
|
||||
and provide a definition for any abstract predicates from ``A``.
|
||||
- Annotate the algebraic datatype with :ref:`private`, and leave the classes public.
|
||||
|
||||
For example, the following code snippet from the CodeQL data-flow library for C# defines classes
|
||||
for dealing with tainted or untainted values. In this case, it doesn't make sense for
|
||||
for dealing with tainted or untainted values. In this case, it doesn't make sense for
|
||||
``TaintType`` to extend a database type. It is part of the taint analysis, not the underlying
|
||||
program, so it's helpful to extend a new type (namely ``TTaintType``):
|
||||
|
||||
@@ -617,24 +619,24 @@ program, so it's helpful to extend a new type (namely ``TTaintType``):
|
||||
TExactValue()
|
||||
or
|
||||
TTaintedValue()
|
||||
|
||||
|
||||
/** Describes how data is tainted. */
|
||||
class TaintType extends TTaintType {
|
||||
string toString() {
|
||||
this = TExactValue() and result = "exact"
|
||||
or
|
||||
or
|
||||
this = TTaintedValue() and result = "tainted"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** A taint type where the data is untainted. */
|
||||
class Untainted extends TaintType, TExactValue {
|
||||
}
|
||||
|
||||
|
||||
/** A taint type where the data is tainted. */
|
||||
class Tainted extends TaintType, TTaintedValue {
|
||||
}
|
||||
|
||||
|
||||
.. _type-unions:
|
||||
|
||||
Type unions
|
||||
@@ -672,7 +674,7 @@ If we had implemented ``DefiniteInitialization`` as a class extension instead, i
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
// THIS WON'T WORK: The implicit type check for InitialValueSource involves an illegal recursion
|
||||
// THIS WON'T WORK: The implicit type check for InitialValueSource involves an illegal recursion
|
||||
// DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization!
|
||||
class DefiniteInitialization extends InitialValueSource {
|
||||
DefiniteInitialization() {
|
||||
@@ -692,7 +694,7 @@ Database types are defined in the database schema. This means that they depend o
|
||||
that you are querying, and vary according to the data you are analyzing.
|
||||
|
||||
For example, if you are querying a CodeQL database for a Java project, the database types may
|
||||
include ``@ifstmt``, representing an if statement in the Java code, and ``@variable``,
|
||||
include ``@ifstmt``, representing an if statement in the Java code, and ``@variable``,
|
||||
representing a variable.
|
||||
|
||||
.. _type-compatibility:
|
||||
|
||||
@@ -0,0 +1,546 @@
|
||||
/** Auto-generated dbscheme; do not edit. */
|
||||
|
||||
|
||||
/** Duplicate code **/
|
||||
|
||||
duplicateCode(
|
||||
unique int id : @duplication,
|
||||
varchar(900) relativePath : string ref,
|
||||
int equivClass : int ref);
|
||||
|
||||
similarCode(
|
||||
unique int id : @similarity,
|
||||
varchar(900) relativePath : string ref,
|
||||
int equivClass : int ref);
|
||||
|
||||
@duplication_or_similarity = @duplication | @similarity;
|
||||
|
||||
tokens(
|
||||
int id : @duplication_or_similarity ref,
|
||||
int offset : int ref,
|
||||
int beginLine : int ref,
|
||||
int beginColumn : int ref,
|
||||
int endLine : int ref,
|
||||
int endColumn : int ref);
|
||||
|
||||
/** External data **/
|
||||
|
||||
externalData(
|
||||
int id : @externalDataElement,
|
||||
varchar(900) path : string ref,
|
||||
int column: int ref,
|
||||
varchar(900) value : string ref
|
||||
);
|
||||
|
||||
snapshotDate(unique date snapshotDate : date ref);
|
||||
|
||||
sourceLocationPrefix(varchar(900) prefix : string ref);
|
||||
|
||||
|
||||
/*
|
||||
* XML Files
|
||||
*/
|
||||
|
||||
xmlEncoding(
|
||||
unique int id: @file ref,
|
||||
string encoding: string ref
|
||||
);
|
||||
|
||||
xmlDTDs(
|
||||
unique int id: @xmldtd,
|
||||
string root: string ref,
|
||||
string publicId: string ref,
|
||||
string systemId: string ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlElements(
|
||||
unique int id: @xmlelement,
|
||||
string name: string ref,
|
||||
int parentid: @xmlparent ref,
|
||||
int idx: int ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlAttrs(
|
||||
unique int id: @xmlattribute,
|
||||
int elementid: @xmlelement ref,
|
||||
string name: string ref,
|
||||
string value: string ref,
|
||||
int idx: int ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlNs(
|
||||
int id: @xmlnamespace,
|
||||
string prefixName: string ref,
|
||||
string URI: string ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlHasNs(
|
||||
int elementId: @xmlnamespaceable ref,
|
||||
int nsId: @xmlnamespace ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlComments(
|
||||
unique int id: @xmlcomment,
|
||||
string text: string ref,
|
||||
int parentid: @xmlparent ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlChars(
|
||||
unique int id: @xmlcharacters,
|
||||
string text: string ref,
|
||||
int parentid: @xmlparent ref,
|
||||
int idx: int ref,
|
||||
int isCDATA: int ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
@xmlparent = @file | @xmlelement;
|
||||
@xmlnamespaceable = @xmlelement | @xmlattribute;
|
||||
|
||||
xmllocations(
|
||||
int xmlElement: @xmllocatable ref,
|
||||
int location: @location_default ref
|
||||
);
|
||||
|
||||
@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
|
||||
|
||||
compilations(unique int id: @compilation, string cwd: string ref);
|
||||
|
||||
#keyset[id, num]
|
||||
compilation_args(int id: @compilation ref, int num: int ref, string arg: string ref);
|
||||
|
||||
#keyset[id, num, kind]
|
||||
compilation_time(int id: @compilation ref, int num: int ref, int kind: int ref, float secs: float ref);
|
||||
|
||||
diagnostic_for(unique int diagnostic: @diagnostic ref, int compilation: @compilation ref, int file_number: int ref, int file_number_diagnostic_number: int ref);
|
||||
|
||||
compilation_finished(unique int id: @compilation ref, float cpu_seconds: float ref, float elapsed_seconds: float ref);
|
||||
|
||||
#keyset[id, num]
|
||||
compilation_compiling_files(int id: @compilation ref, int num: int ref, int file: @file ref);
|
||||
|
||||
diagnostics(unique int id: @diagnostic, int severity: int ref, string error_tag: string ref, string error_message: string ref,
|
||||
string full_error_message: string ref, int location: @location ref);
|
||||
|
||||
locations_default(unique int id: @location_default, int file: @file ref, int beginLine: int ref, int beginColumn: int ref,
|
||||
int endLine: int ref, int endColumn: int ref);
|
||||
|
||||
numlines(int element_id: @sourceline ref, int num_lines: int ref, int num_code: int ref, int num_comment: int ref);
|
||||
|
||||
files(unique int id: @file, string name: string ref);
|
||||
|
||||
folders(unique int id: @folder, string name: string ref);
|
||||
|
||||
containerparent(int parent: @container ref, unique int child: @container ref);
|
||||
|
||||
has_location(unique int locatable: @locatable ref, int location: @location ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
comment_groups(unique int id: @comment_group, int parent: @file ref, int idx: int ref);
|
||||
|
||||
comments(unique int id: @comment, int kind: int ref, int parent: @comment_group ref, int idx: int ref, string text: string ref);
|
||||
|
||||
doc_comments(unique int node: @documentable ref, int comment: @comment_group ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
exprs(unique int id: @expr, int kind: int ref, int parent: @exprparent ref, int idx: int ref);
|
||||
|
||||
literals(unique int expr: @expr ref, string value: string ref, string raw: string ref);
|
||||
|
||||
constvalues(unique int expr: @expr ref, string value: string ref, string exact: string ref);
|
||||
|
||||
fields(unique int id: @field, int parent: @fieldparent ref, int idx: int ref);
|
||||
|
||||
typeparamdecls(unique int id: @typeparamdecl, int parent: @typeparamdeclparent ref, int idx: int ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
stmts(unique int id: @stmt, int kind: int ref, int parent: @stmtparent ref, int idx: int ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
decls(unique int id: @decl, int kind: int ref, int parent: @declparent ref, int idx: int ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
specs(unique int id: @spec, int kind: int ref, int parent: @gendecl ref, int idx: int ref);
|
||||
|
||||
scopes(unique int id: @scope, int kind: int ref);
|
||||
|
||||
scopenesting(unique int inner: @scope ref, int outer: @scope ref);
|
||||
|
||||
scopenodes(unique int node: @scopenode ref, int scope: @localscope ref);
|
||||
|
||||
objects(unique int id: @object, int kind: int ref, string name: string ref);
|
||||
|
||||
objectscopes(unique int object: @object ref, int scope: @scope ref);
|
||||
|
||||
objecttypes(unique int object: @object ref, int tp: @type ref);
|
||||
|
||||
methodreceivers(unique int method: @object ref, int receiver: @object ref);
|
||||
|
||||
fieldstructs(unique int field: @object ref, int struct: @structtype ref);
|
||||
|
||||
methodhosts(int method: @object ref, int host: @namedtype ref);
|
||||
|
||||
defs(int ident: @ident ref, int object: @object ref);
|
||||
|
||||
uses(int ident: @ident ref, int object: @object ref);
|
||||
|
||||
types(unique int id: @type, int kind: int ref);
|
||||
|
||||
type_of(unique int expr: @expr ref, int tp: @type ref);
|
||||
|
||||
typename(unique int tp: @type ref, string name: string ref);
|
||||
|
||||
key_type(unique int map: @maptype ref, int tp: @type ref);
|
||||
|
||||
element_type(unique int container: @containertype ref, int tp: @type ref);
|
||||
|
||||
base_type(unique int ptr: @pointertype ref, int tp: @type ref);
|
||||
|
||||
underlying_type(unique int named: @namedtype ref, int tp: @type ref);
|
||||
|
||||
#keyset[parent, index]
|
||||
component_types(int parent: @compositetype ref, int index: int ref, string name: string ref, int tp: @type ref);
|
||||
|
||||
array_length(unique int tp: @arraytype ref, string len: string ref);
|
||||
|
||||
type_objects(unique int tp: @type ref, int object: @object ref);
|
||||
|
||||
packages(unique int id: @package, string name: string ref, string path: string ref, int scope: @packagescope ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
modexprs(unique int id: @modexpr, int kind: int ref, int parent: @modexprparent ref, int idx: int ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
modtokens(string token: string ref, int parent: @modexpr ref, int idx: int ref);
|
||||
|
||||
#keyset[package, idx]
|
||||
errors(unique int id: @error, int kind: int ref, string msg: string ref, string rawpos: string ref,
|
||||
string file: string ref, int line: int ref, int col: int ref, int package: @package ref, int idx: int ref);
|
||||
|
||||
has_ellipsis(int id: @callorconversionexpr ref);
|
||||
|
||||
variadic(int id: @signaturetype ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
typeparam(unique int tp: @typeparamtype ref, string name: string ref, int bound: @compositetype ref,
|
||||
int parent: @typeparamparentobject ref, int idx: int ref);
|
||||
|
||||
@container = @file | @folder;
|
||||
|
||||
@locatable = @xmllocatable | @node | @localscope;
|
||||
|
||||
@node = @documentable | @exprparent | @modexprparent | @fieldparent | @stmtparent | @declparent | @typeparamdeclparent
|
||||
| @scopenode | @comment_group | @comment;
|
||||
|
||||
@documentable = @file | @field | @typeparamdecl | @spec | @gendecl | @funcdecl | @modexpr;
|
||||
|
||||
@exprparent = @funcdef | @file | @expr | @field | @stmt | @decl | @typeparamdecl | @spec;
|
||||
|
||||
@modexprparent = @file | @modexpr;
|
||||
|
||||
@fieldparent = @decl | @structtypeexpr | @functypeexpr | @interfacetypeexpr;
|
||||
|
||||
@stmtparent = @funcdef | @stmt | @decl;
|
||||
|
||||
@declparent = @file | @declstmt;
|
||||
|
||||
@typeparamdeclparent = @funcdecl | @typespec;
|
||||
|
||||
@funcdef = @funclit | @funcdecl;
|
||||
|
||||
@scopenode = @file | @functypeexpr | @blockstmt | @ifstmt | @caseclause | @switchstmt | @commclause | @loopstmt;
|
||||
|
||||
@location = @location_default;
|
||||
|
||||
@sourceline = @locatable;
|
||||
|
||||
case @comment.kind of
|
||||
0 = @slashslashcomment
|
||||
| 1 = @slashstarcomment;
|
||||
|
||||
case @expr.kind of
|
||||
0 = @badexpr
|
||||
| 1 = @ident
|
||||
| 2 = @ellipsis
|
||||
| 3 = @intlit
|
||||
| 4 = @floatlit
|
||||
| 5 = @imaglit
|
||||
| 6 = @charlit
|
||||
| 7 = @stringlit
|
||||
| 8 = @funclit
|
||||
| 9 = @compositelit
|
||||
| 10 = @parenexpr
|
||||
| 11 = @selectorexpr
|
||||
| 12 = @indexexpr
|
||||
| 13 = @genericfunctioninstantiationexpr
|
||||
| 14 = @generictypeinstantiationexpr
|
||||
| 15 = @sliceexpr
|
||||
| 16 = @typeassertexpr
|
||||
| 17 = @callorconversionexpr
|
||||
| 18 = @starexpr
|
||||
| 19 = @keyvalueexpr
|
||||
| 20 = @arraytypeexpr
|
||||
| 21 = @structtypeexpr
|
||||
| 22 = @functypeexpr
|
||||
| 23 = @interfacetypeexpr
|
||||
| 24 = @maptypeexpr
|
||||
| 25 = @typesetliteralexpr
|
||||
| 26 = @plusexpr
|
||||
| 27 = @minusexpr
|
||||
| 28 = @notexpr
|
||||
| 29 = @complementexpr
|
||||
| 30 = @derefexpr
|
||||
| 31 = @addressexpr
|
||||
| 32 = @arrowexpr
|
||||
| 33 = @lorexpr
|
||||
| 34 = @landexpr
|
||||
| 35 = @eqlexpr
|
||||
| 36 = @neqexpr
|
||||
| 37 = @lssexpr
|
||||
| 38 = @leqexpr
|
||||
| 39 = @gtrexpr
|
||||
| 40 = @geqexpr
|
||||
| 41 = @addexpr
|
||||
| 42 = @subexpr
|
||||
| 43 = @orexpr
|
||||
| 44 = @xorexpr
|
||||
| 45 = @mulexpr
|
||||
| 46 = @quoexpr
|
||||
| 47 = @remexpr
|
||||
| 48 = @shlexpr
|
||||
| 49 = @shrexpr
|
||||
| 50 = @andexpr
|
||||
| 51 = @andnotexpr
|
||||
| 52 = @sendchantypeexpr
|
||||
| 53 = @recvchantypeexpr
|
||||
| 54 = @sendrcvchantypeexpr;
|
||||
|
||||
@basiclit = @intlit | @floatlit | @imaglit | @charlit | @stringlit;
|
||||
|
||||
@operatorexpr = @logicalexpr | @arithmeticexpr | @bitwiseexpr | @unaryexpr | @binaryexpr;
|
||||
|
||||
@logicalexpr = @logicalunaryexpr | @logicalbinaryexpr;
|
||||
|
||||
@arithmeticexpr = @arithmeticunaryexpr | @arithmeticbinaryexpr;
|
||||
|
||||
@bitwiseexpr = @bitwiseunaryexpr | @bitwisebinaryexpr;
|
||||
|
||||
@unaryexpr = @logicalunaryexpr | @bitwiseunaryexpr | @arithmeticunaryexpr | @derefexpr | @addressexpr | @arrowexpr;
|
||||
|
||||
@logicalunaryexpr = @notexpr;
|
||||
|
||||
@bitwiseunaryexpr = @complementexpr;
|
||||
|
||||
@arithmeticunaryexpr = @plusexpr | @minusexpr;
|
||||
|
||||
@binaryexpr = @logicalbinaryexpr | @bitwisebinaryexpr | @arithmeticbinaryexpr | @comparison;
|
||||
|
||||
@logicalbinaryexpr = @lorexpr | @landexpr;
|
||||
|
||||
@bitwisebinaryexpr = @shiftexpr | @orexpr | @xorexpr | @andexpr | @andnotexpr;
|
||||
|
||||
@arithmeticbinaryexpr = @addexpr | @subexpr | @mulexpr | @quoexpr | @remexpr;
|
||||
|
||||
@shiftexpr = @shlexpr | @shrexpr;
|
||||
|
||||
@comparison = @equalitytest | @relationalcomparison;
|
||||
|
||||
@equalitytest = @eqlexpr | @neqexpr;
|
||||
|
||||
@relationalcomparison = @lssexpr | @leqexpr | @gtrexpr | @geqexpr;
|
||||
|
||||
@chantypeexpr = @sendchantypeexpr | @recvchantypeexpr | @sendrcvchantypeexpr;
|
||||
|
||||
case @stmt.kind of
|
||||
0 = @badstmt
|
||||
| 1 = @declstmt
|
||||
| 2 = @emptystmt
|
||||
| 3 = @labeledstmt
|
||||
| 4 = @exprstmt
|
||||
| 5 = @sendstmt
|
||||
| 6 = @incstmt
|
||||
| 7 = @decstmt
|
||||
| 8 = @gostmt
|
||||
| 9 = @deferstmt
|
||||
| 10 = @returnstmt
|
||||
| 11 = @breakstmt
|
||||
| 12 = @continuestmt
|
||||
| 13 = @gotostmt
|
||||
| 14 = @fallthroughstmt
|
||||
| 15 = @blockstmt
|
||||
| 16 = @ifstmt
|
||||
| 17 = @caseclause
|
||||
| 18 = @exprswitchstmt
|
||||
| 19 = @typeswitchstmt
|
||||
| 20 = @commclause
|
||||
| 21 = @selectstmt
|
||||
| 22 = @forstmt
|
||||
| 23 = @rangestmt
|
||||
| 24 = @assignstmt
|
||||
| 25 = @definestmt
|
||||
| 26 = @addassignstmt
|
||||
| 27 = @subassignstmt
|
||||
| 28 = @mulassignstmt
|
||||
| 29 = @quoassignstmt
|
||||
| 30 = @remassignstmt
|
||||
| 31 = @andassignstmt
|
||||
| 32 = @orassignstmt
|
||||
| 33 = @xorassignstmt
|
||||
| 34 = @shlassignstmt
|
||||
| 35 = @shrassignstmt
|
||||
| 36 = @andnotassignstmt;
|
||||
|
||||
@incdecstmt = @incstmt | @decstmt;
|
||||
|
||||
@assignment = @simpleassignstmt | @compoundassignstmt;
|
||||
|
||||
@simpleassignstmt = @assignstmt | @definestmt;
|
||||
|
||||
@compoundassignstmt = @addassignstmt | @subassignstmt | @mulassignstmt | @quoassignstmt | @remassignstmt
|
||||
| @andassignstmt | @orassignstmt | @xorassignstmt | @shlassignstmt | @shrassignstmt | @andnotassignstmt;
|
||||
|
||||
@branchstmt = @breakstmt | @continuestmt | @gotostmt | @fallthroughstmt;
|
||||
|
||||
@switchstmt = @exprswitchstmt | @typeswitchstmt;
|
||||
|
||||
@loopstmt = @forstmt | @rangestmt;
|
||||
|
||||
case @decl.kind of
|
||||
0 = @baddecl
|
||||
| 1 = @importdecl
|
||||
| 2 = @constdecl
|
||||
| 3 = @typedecl
|
||||
| 4 = @vardecl
|
||||
| 5 = @funcdecl;
|
||||
|
||||
@gendecl = @importdecl | @constdecl | @typedecl | @vardecl;
|
||||
|
||||
case @spec.kind of
|
||||
0 = @importspec
|
||||
| 1 = @valuespec
|
||||
| 2 = @typedefspec
|
||||
| 3 = @aliasspec;
|
||||
|
||||
@typespec = @typedefspec | @aliasspec;
|
||||
|
||||
case @object.kind of
|
||||
0 = @pkgobject
|
||||
| 1 = @decltypeobject
|
||||
| 2 = @builtintypeobject
|
||||
| 3 = @declconstobject
|
||||
| 4 = @builtinconstobject
|
||||
| 5 = @declvarobject
|
||||
| 6 = @declfunctionobject
|
||||
| 7 = @builtinfunctionobject
|
||||
| 8 = @labelobject;
|
||||
|
||||
@typeparamparentobject = @decltypeobject | @declfunctionobject;
|
||||
|
||||
@declobject = @decltypeobject | @declconstobject | @declvarobject | @declfunctionobject;
|
||||
|
||||
@builtinobject = @builtintypeobject | @builtinconstobject | @builtinfunctionobject;
|
||||
|
||||
@typeobject = @decltypeobject | @builtintypeobject;
|
||||
|
||||
@valueobject = @constobject | @varobject | @functionobject;
|
||||
|
||||
@constobject = @declconstobject | @builtinconstobject;
|
||||
|
||||
@varobject = @declvarobject;
|
||||
|
||||
@functionobject = @declfunctionobject | @builtinfunctionobject;
|
||||
|
||||
case @scope.kind of
|
||||
0 = @universescope
|
||||
| 1 = @packagescope
|
||||
| 2 = @localscope;
|
||||
|
||||
case @type.kind of
|
||||
0 = @invalidtype
|
||||
| 1 = @boolexprtype
|
||||
| 2 = @inttype
|
||||
| 3 = @int8type
|
||||
| 4 = @int16type
|
||||
| 5 = @int32type
|
||||
| 6 = @int64type
|
||||
| 7 = @uinttype
|
||||
| 8 = @uint8type
|
||||
| 9 = @uint16type
|
||||
| 10 = @uint32type
|
||||
| 11 = @uint64type
|
||||
| 12 = @uintptrtype
|
||||
| 13 = @float32type
|
||||
| 14 = @float64type
|
||||
| 15 = @complex64type
|
||||
| 16 = @complex128type
|
||||
| 17 = @stringexprtype
|
||||
| 18 = @unsafepointertype
|
||||
| 19 = @boolliteraltype
|
||||
| 20 = @intliteraltype
|
||||
| 21 = @runeliteraltype
|
||||
| 22 = @floatliteraltype
|
||||
| 23 = @complexliteraltype
|
||||
| 24 = @stringliteraltype
|
||||
| 25 = @nilliteraltype
|
||||
| 26 = @typeparamtype
|
||||
| 27 = @arraytype
|
||||
| 28 = @slicetype
|
||||
| 29 = @structtype
|
||||
| 30 = @pointertype
|
||||
| 31 = @interfacetype
|
||||
| 32 = @tupletype
|
||||
| 33 = @signaturetype
|
||||
| 34 = @maptype
|
||||
| 35 = @sendchantype
|
||||
| 36 = @recvchantype
|
||||
| 37 = @sendrcvchantype
|
||||
| 38 = @namedtype
|
||||
| 39 = @typesetliteraltype;
|
||||
|
||||
@basictype = @booltype | @numerictype | @stringtype | @literaltype | @invalidtype | @unsafepointertype;
|
||||
|
||||
@booltype = @boolexprtype | @boolliteraltype;
|
||||
|
||||
@numerictype = @integertype | @floattype | @complextype;
|
||||
|
||||
@integertype = @signedintegertype | @unsignedintegertype;
|
||||
|
||||
@signedintegertype = @inttype | @int8type | @int16type | @int32type | @int64type | @intliteraltype | @runeliteraltype;
|
||||
|
||||
@unsignedintegertype = @uinttype | @uint8type | @uint16type | @uint32type | @uint64type | @uintptrtype;
|
||||
|
||||
@floattype = @float32type | @float64type | @floatliteraltype;
|
||||
|
||||
@complextype = @complex64type | @complex128type | @complexliteraltype;
|
||||
|
||||
@stringtype = @stringexprtype | @stringliteraltype;
|
||||
|
||||
@literaltype = @boolliteraltype | @intliteraltype | @runeliteraltype | @floatliteraltype | @complexliteraltype
|
||||
| @stringliteraltype | @nilliteraltype;
|
||||
|
||||
@compositetype = @typeparamtype | @containertype | @structtype | @pointertype | @interfacetype | @tupletype
|
||||
| @signaturetype | @namedtype | @typesetliteraltype;
|
||||
|
||||
@containertype = @arraytype | @slicetype | @maptype | @chantype;
|
||||
|
||||
@chantype = @sendchantype | @recvchantype | @sendrcvchantype;
|
||||
|
||||
case @modexpr.kind of
|
||||
0 = @modcommentblock
|
||||
| 1 = @modline
|
||||
| 2 = @modlineblock
|
||||
| 3 = @modlparen
|
||||
| 4 = @modrparen;
|
||||
|
||||
case @error.kind of
|
||||
0 = @unknownerror
|
||||
| 1 = @listerror
|
||||
| 2 = @parseerror
|
||||
| 3 = @typeerror;
|
||||
|
||||
@@ -0,0 +1,552 @@
|
||||
/** Auto-generated dbscheme; do not edit. Run `make gen` in directory `go/` to regenerate. */
|
||||
|
||||
|
||||
/** Duplicate code **/
|
||||
|
||||
duplicateCode(
|
||||
unique int id : @duplication,
|
||||
varchar(900) relativePath : string ref,
|
||||
int equivClass : int ref);
|
||||
|
||||
similarCode(
|
||||
unique int id : @similarity,
|
||||
varchar(900) relativePath : string ref,
|
||||
int equivClass : int ref);
|
||||
|
||||
@duplication_or_similarity = @duplication | @similarity;
|
||||
|
||||
tokens(
|
||||
int id : @duplication_or_similarity ref,
|
||||
int offset : int ref,
|
||||
int beginLine : int ref,
|
||||
int beginColumn : int ref,
|
||||
int endLine : int ref,
|
||||
int endColumn : int ref);
|
||||
|
||||
/** External data **/
|
||||
|
||||
externalData(
|
||||
int id : @externalDataElement,
|
||||
varchar(900) path : string ref,
|
||||
int column: int ref,
|
||||
varchar(900) value : string ref
|
||||
);
|
||||
|
||||
snapshotDate(unique date snapshotDate : date ref);
|
||||
|
||||
sourceLocationPrefix(varchar(900) prefix : string ref);
|
||||
|
||||
|
||||
/*
|
||||
* XML Files
|
||||
*/
|
||||
|
||||
xmlEncoding(
|
||||
unique int id: @file ref,
|
||||
string encoding: string ref
|
||||
);
|
||||
|
||||
xmlDTDs(
|
||||
unique int id: @xmldtd,
|
||||
string root: string ref,
|
||||
string publicId: string ref,
|
||||
string systemId: string ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlElements(
|
||||
unique int id: @xmlelement,
|
||||
string name: string ref,
|
||||
int parentid: @xmlparent ref,
|
||||
int idx: int ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlAttrs(
|
||||
unique int id: @xmlattribute,
|
||||
int elementid: @xmlelement ref,
|
||||
string name: string ref,
|
||||
string value: string ref,
|
||||
int idx: int ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlNs(
|
||||
int id: @xmlnamespace,
|
||||
string prefixName: string ref,
|
||||
string URI: string ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlHasNs(
|
||||
int elementId: @xmlnamespaceable ref,
|
||||
int nsId: @xmlnamespace ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlComments(
|
||||
unique int id: @xmlcomment,
|
||||
string text: string ref,
|
||||
int parentid: @xmlparent ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
xmlChars(
|
||||
unique int id: @xmlcharacters,
|
||||
string text: string ref,
|
||||
int parentid: @xmlparent ref,
|
||||
int idx: int ref,
|
||||
int isCDATA: int ref,
|
||||
int fileid: @file ref
|
||||
);
|
||||
|
||||
@xmlparent = @file | @xmlelement;
|
||||
@xmlnamespaceable = @xmlelement | @xmlattribute;
|
||||
|
||||
xmllocations(
|
||||
int xmlElement: @xmllocatable ref,
|
||||
int location: @location_default ref
|
||||
);
|
||||
|
||||
@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
|
||||
|
||||
compilations(unique int id: @compilation, string cwd: string ref);
|
||||
|
||||
#keyset[id, num]
|
||||
compilation_args(int id: @compilation ref, int num: int ref, string arg: string ref);
|
||||
|
||||
#keyset[id, num, kind]
|
||||
compilation_time(int id: @compilation ref, int num: int ref, int kind: int ref, float secs: float ref);
|
||||
|
||||
diagnostic_for(unique int diagnostic: @diagnostic ref, int compilation: @compilation ref, int file_number: int ref, int file_number_diagnostic_number: int ref);
|
||||
|
||||
compilation_finished(unique int id: @compilation ref, float cpu_seconds: float ref, float elapsed_seconds: float ref);
|
||||
|
||||
#keyset[id, num]
|
||||
compilation_compiling_files(int id: @compilation ref, int num: int ref, int file: @file ref);
|
||||
|
||||
diagnostics(unique int id: @diagnostic, int severity: int ref, string error_tag: string ref, string error_message: string ref,
|
||||
string full_error_message: string ref, int location: @location ref);
|
||||
|
||||
locations_default(unique int id: @location_default, int file: @file ref, int beginLine: int ref, int beginColumn: int ref,
|
||||
int endLine: int ref, int endColumn: int ref);
|
||||
|
||||
numlines(int element_id: @sourceline ref, int num_lines: int ref, int num_code: int ref, int num_comment: int ref);
|
||||
|
||||
files(unique int id: @file, string name: string ref);
|
||||
|
||||
folders(unique int id: @folder, string name: string ref);
|
||||
|
||||
containerparent(int parent: @container ref, unique int child: @container ref);
|
||||
|
||||
has_location(unique int locatable: @locatable ref, int location: @location ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
comment_groups(unique int id: @comment_group, int parent: @file ref, int idx: int ref);
|
||||
|
||||
comments(unique int id: @comment, int kind: int ref, int parent: @comment_group ref, int idx: int ref, string text: string ref);
|
||||
|
||||
doc_comments(unique int node: @documentable ref, int comment: @comment_group ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
exprs(unique int id: @expr, int kind: int ref, int parent: @exprparent ref, int idx: int ref);
|
||||
|
||||
literals(unique int expr: @expr ref, string value: string ref, string raw: string ref);
|
||||
|
||||
constvalues(unique int expr: @expr ref, string value: string ref, string exact: string ref);
|
||||
|
||||
fields(unique int id: @field, int parent: @fieldparent ref, int idx: int ref);
|
||||
|
||||
typeparamdecls(unique int id: @typeparamdecl, int parent: @typeparamdeclparent ref, int idx: int ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
stmts(unique int id: @stmt, int kind: int ref, int parent: @stmtparent ref, int idx: int ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
decls(unique int id: @decl, int kind: int ref, int parent: @declparent ref, int idx: int ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
specs(unique int id: @spec, int kind: int ref, int parent: @gendecl ref, int idx: int ref);
|
||||
|
||||
scopes(unique int id: @scope, int kind: int ref);
|
||||
|
||||
scopenesting(unique int inner: @scope ref, int outer: @scope ref);
|
||||
|
||||
scopenodes(unique int node: @scopenode ref, int scope: @localscope ref);
|
||||
|
||||
objects(unique int id: @object, int kind: int ref, string name: string ref);
|
||||
|
||||
objectscopes(unique int object: @object ref, int scope: @scope ref);
|
||||
|
||||
objecttypes(unique int object: @object ref, int tp: @type ref);
|
||||
|
||||
methodreceivers(unique int method: @object ref, int receiver: @object ref);
|
||||
|
||||
fieldstructs(unique int field: @object ref, int struct: @structtype ref);
|
||||
|
||||
methodhosts(int method: @object ref, int host: @namedtype ref);
|
||||
|
||||
defs(int ident: @ident ref, int object: @object ref);
|
||||
|
||||
uses(int ident: @ident ref, int object: @object ref);
|
||||
|
||||
types(unique int id: @type, int kind: int ref);
|
||||
|
||||
type_of(unique int expr: @expr ref, int tp: @type ref);
|
||||
|
||||
typename(unique int tp: @type ref, string name: string ref);
|
||||
|
||||
key_type(unique int map: @maptype ref, int tp: @type ref);
|
||||
|
||||
element_type(unique int container: @containertype ref, int tp: @type ref);
|
||||
|
||||
base_type(unique int ptr: @pointertype ref, int tp: @type ref);
|
||||
|
||||
underlying_type(unique int named: @namedtype ref, int tp: @type ref);
|
||||
|
||||
#keyset[parent, index]
|
||||
component_types(int parent: @compositetype ref, int index: int ref, string name: string ref, int tp: @type ref);
|
||||
|
||||
#keyset[parent, index]
|
||||
struct_tags(int parent: @structtype ref, int index: int ref, string tag: string ref);
|
||||
|
||||
#keyset[interface, index]
|
||||
interface_private_method_ids(int interface: @interfacetype ref, int index: int ref, string id: string ref);
|
||||
|
||||
array_length(unique int tp: @arraytype ref, string len: string ref);
|
||||
|
||||
type_objects(unique int tp: @type ref, int object: @object ref);
|
||||
|
||||
packages(unique int id: @package, string name: string ref, string path: string ref, int scope: @packagescope ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
modexprs(unique int id: @modexpr, int kind: int ref, int parent: @modexprparent ref, int idx: int ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
modtokens(string token: string ref, int parent: @modexpr ref, int idx: int ref);
|
||||
|
||||
#keyset[package, idx]
|
||||
errors(unique int id: @error, int kind: int ref, string msg: string ref, string rawpos: string ref,
|
||||
string file: string ref, int line: int ref, int col: int ref, int package: @package ref, int idx: int ref);
|
||||
|
||||
has_ellipsis(int id: @callorconversionexpr ref);
|
||||
|
||||
variadic(int id: @signaturetype ref);
|
||||
|
||||
#keyset[parent, idx]
|
||||
typeparam(unique int tp: @typeparamtype ref, string name: string ref, int bound: @compositetype ref,
|
||||
int parent: @typeparamparentobject ref, int idx: int ref);
|
||||
|
||||
@container = @file | @folder;
|
||||
|
||||
@locatable = @xmllocatable | @node | @localscope;
|
||||
|
||||
@node = @documentable | @exprparent | @modexprparent | @fieldparent | @stmtparent | @declparent | @typeparamdeclparent
|
||||
| @scopenode | @comment_group | @comment;
|
||||
|
||||
@documentable = @file | @field | @typeparamdecl | @spec | @gendecl | @funcdecl | @modexpr;
|
||||
|
||||
@exprparent = @funcdef | @file | @expr | @field | @stmt | @decl | @typeparamdecl | @spec;
|
||||
|
||||
@modexprparent = @file | @modexpr;
|
||||
|
||||
@fieldparent = @decl | @structtypeexpr | @functypeexpr | @interfacetypeexpr;
|
||||
|
||||
@stmtparent = @funcdef | @stmt | @decl;
|
||||
|
||||
@declparent = @file | @declstmt;
|
||||
|
||||
@typeparamdeclparent = @funcdecl | @typespec;
|
||||
|
||||
@funcdef = @funclit | @funcdecl;
|
||||
|
||||
@scopenode = @file | @functypeexpr | @blockstmt | @ifstmt | @caseclause | @switchstmt | @commclause | @loopstmt;
|
||||
|
||||
@location = @location_default;
|
||||
|
||||
@sourceline = @locatable;
|
||||
|
||||
case @comment.kind of
|
||||
0 = @slashslashcomment
|
||||
| 1 = @slashstarcomment;
|
||||
|
||||
case @expr.kind of
|
||||
0 = @badexpr
|
||||
| 1 = @ident
|
||||
| 2 = @ellipsis
|
||||
| 3 = @intlit
|
||||
| 4 = @floatlit
|
||||
| 5 = @imaglit
|
||||
| 6 = @charlit
|
||||
| 7 = @stringlit
|
||||
| 8 = @funclit
|
||||
| 9 = @compositelit
|
||||
| 10 = @parenexpr
|
||||
| 11 = @selectorexpr
|
||||
| 12 = @indexexpr
|
||||
| 13 = @genericfunctioninstantiationexpr
|
||||
| 14 = @generictypeinstantiationexpr
|
||||
| 15 = @sliceexpr
|
||||
| 16 = @typeassertexpr
|
||||
| 17 = @callorconversionexpr
|
||||
| 18 = @starexpr
|
||||
| 19 = @keyvalueexpr
|
||||
| 20 = @arraytypeexpr
|
||||
| 21 = @structtypeexpr
|
||||
| 22 = @functypeexpr
|
||||
| 23 = @interfacetypeexpr
|
||||
| 24 = @maptypeexpr
|
||||
| 25 = @typesetliteralexpr
|
||||
| 26 = @plusexpr
|
||||
| 27 = @minusexpr
|
||||
| 28 = @notexpr
|
||||
| 29 = @complementexpr
|
||||
| 30 = @derefexpr
|
||||
| 31 = @addressexpr
|
||||
| 32 = @arrowexpr
|
||||
| 33 = @lorexpr
|
||||
| 34 = @landexpr
|
||||
| 35 = @eqlexpr
|
||||
| 36 = @neqexpr
|
||||
| 37 = @lssexpr
|
||||
| 38 = @leqexpr
|
||||
| 39 = @gtrexpr
|
||||
| 40 = @geqexpr
|
||||
| 41 = @addexpr
|
||||
| 42 = @subexpr
|
||||
| 43 = @orexpr
|
||||
| 44 = @xorexpr
|
||||
| 45 = @mulexpr
|
||||
| 46 = @quoexpr
|
||||
| 47 = @remexpr
|
||||
| 48 = @shlexpr
|
||||
| 49 = @shrexpr
|
||||
| 50 = @andexpr
|
||||
| 51 = @andnotexpr
|
||||
| 52 = @sendchantypeexpr
|
||||
| 53 = @recvchantypeexpr
|
||||
| 54 = @sendrcvchantypeexpr;
|
||||
|
||||
@basiclit = @intlit | @floatlit | @imaglit | @charlit | @stringlit;
|
||||
|
||||
@operatorexpr = @logicalexpr | @arithmeticexpr | @bitwiseexpr | @unaryexpr | @binaryexpr;
|
||||
|
||||
@logicalexpr = @logicalunaryexpr | @logicalbinaryexpr;
|
||||
|
||||
@arithmeticexpr = @arithmeticunaryexpr | @arithmeticbinaryexpr;
|
||||
|
||||
@bitwiseexpr = @bitwiseunaryexpr | @bitwisebinaryexpr;
|
||||
|
||||
@unaryexpr = @logicalunaryexpr | @bitwiseunaryexpr | @arithmeticunaryexpr | @derefexpr | @addressexpr | @arrowexpr;
|
||||
|
||||
@logicalunaryexpr = @notexpr;
|
||||
|
||||
@bitwiseunaryexpr = @complementexpr;
|
||||
|
||||
@arithmeticunaryexpr = @plusexpr | @minusexpr;
|
||||
|
||||
@binaryexpr = @logicalbinaryexpr | @bitwisebinaryexpr | @arithmeticbinaryexpr | @comparison;
|
||||
|
||||
@logicalbinaryexpr = @lorexpr | @landexpr;
|
||||
|
||||
@bitwisebinaryexpr = @shiftexpr | @orexpr | @xorexpr | @andexpr | @andnotexpr;
|
||||
|
||||
@arithmeticbinaryexpr = @addexpr | @subexpr | @mulexpr | @quoexpr | @remexpr;
|
||||
|
||||
@shiftexpr = @shlexpr | @shrexpr;
|
||||
|
||||
@comparison = @equalitytest | @relationalcomparison;
|
||||
|
||||
@equalitytest = @eqlexpr | @neqexpr;
|
||||
|
||||
@relationalcomparison = @lssexpr | @leqexpr | @gtrexpr | @geqexpr;
|
||||
|
||||
@chantypeexpr = @sendchantypeexpr | @recvchantypeexpr | @sendrcvchantypeexpr;
|
||||
|
||||
case @stmt.kind of
|
||||
0 = @badstmt
|
||||
| 1 = @declstmt
|
||||
| 2 = @emptystmt
|
||||
| 3 = @labeledstmt
|
||||
| 4 = @exprstmt
|
||||
| 5 = @sendstmt
|
||||
| 6 = @incstmt
|
||||
| 7 = @decstmt
|
||||
| 8 = @gostmt
|
||||
| 9 = @deferstmt
|
||||
| 10 = @returnstmt
|
||||
| 11 = @breakstmt
|
||||
| 12 = @continuestmt
|
||||
| 13 = @gotostmt
|
||||
| 14 = @fallthroughstmt
|
||||
| 15 = @blockstmt
|
||||
| 16 = @ifstmt
|
||||
| 17 = @caseclause
|
||||
| 18 = @exprswitchstmt
|
||||
| 19 = @typeswitchstmt
|
||||
| 20 = @commclause
|
||||
| 21 = @selectstmt
|
||||
| 22 = @forstmt
|
||||
| 23 = @rangestmt
|
||||
| 24 = @assignstmt
|
||||
| 25 = @definestmt
|
||||
| 26 = @addassignstmt
|
||||
| 27 = @subassignstmt
|
||||
| 28 = @mulassignstmt
|
||||
| 29 = @quoassignstmt
|
||||
| 30 = @remassignstmt
|
||||
| 31 = @andassignstmt
|
||||
| 32 = @orassignstmt
|
||||
| 33 = @xorassignstmt
|
||||
| 34 = @shlassignstmt
|
||||
| 35 = @shrassignstmt
|
||||
| 36 = @andnotassignstmt;
|
||||
|
||||
@incdecstmt = @incstmt | @decstmt;
|
||||
|
||||
@assignment = @simpleassignstmt | @compoundassignstmt;
|
||||
|
||||
@simpleassignstmt = @assignstmt | @definestmt;
|
||||
|
||||
@compoundassignstmt = @addassignstmt | @subassignstmt | @mulassignstmt | @quoassignstmt | @remassignstmt
|
||||
| @andassignstmt | @orassignstmt | @xorassignstmt | @shlassignstmt | @shrassignstmt | @andnotassignstmt;
|
||||
|
||||
@branchstmt = @breakstmt | @continuestmt | @gotostmt | @fallthroughstmt;
|
||||
|
||||
@switchstmt = @exprswitchstmt | @typeswitchstmt;
|
||||
|
||||
@loopstmt = @forstmt | @rangestmt;
|
||||
|
||||
case @decl.kind of
|
||||
0 = @baddecl
|
||||
| 1 = @importdecl
|
||||
| 2 = @constdecl
|
||||
| 3 = @typedecl
|
||||
| 4 = @vardecl
|
||||
| 5 = @funcdecl;
|
||||
|
||||
@gendecl = @importdecl | @constdecl | @typedecl | @vardecl;
|
||||
|
||||
case @spec.kind of
|
||||
0 = @importspec
|
||||
| 1 = @valuespec
|
||||
| 2 = @typedefspec
|
||||
| 3 = @aliasspec;
|
||||
|
||||
@typespec = @typedefspec | @aliasspec;
|
||||
|
||||
case @object.kind of
|
||||
0 = @pkgobject
|
||||
| 1 = @decltypeobject
|
||||
| 2 = @builtintypeobject
|
||||
| 3 = @declconstobject
|
||||
| 4 = @builtinconstobject
|
||||
| 5 = @declvarobject
|
||||
| 6 = @declfunctionobject
|
||||
| 7 = @builtinfunctionobject
|
||||
| 8 = @labelobject;
|
||||
|
||||
@typeparamparentobject = @decltypeobject | @declfunctionobject;
|
||||
|
||||
@declobject = @decltypeobject | @declconstobject | @declvarobject | @declfunctionobject;
|
||||
|
||||
@builtinobject = @builtintypeobject | @builtinconstobject | @builtinfunctionobject;
|
||||
|
||||
@typeobject = @decltypeobject | @builtintypeobject;
|
||||
|
||||
@valueobject = @constobject | @varobject | @functionobject;
|
||||
|
||||
@constobject = @declconstobject | @builtinconstobject;
|
||||
|
||||
@varobject = @declvarobject;
|
||||
|
||||
@functionobject = @declfunctionobject | @builtinfunctionobject;
|
||||
|
||||
case @scope.kind of
|
||||
0 = @universescope
|
||||
| 1 = @packagescope
|
||||
| 2 = @localscope;
|
||||
|
||||
case @type.kind of
|
||||
0 = @invalidtype
|
||||
| 1 = @boolexprtype
|
||||
| 2 = @inttype
|
||||
| 3 = @int8type
|
||||
| 4 = @int16type
|
||||
| 5 = @int32type
|
||||
| 6 = @int64type
|
||||
| 7 = @uinttype
|
||||
| 8 = @uint8type
|
||||
| 9 = @uint16type
|
||||
| 10 = @uint32type
|
||||
| 11 = @uint64type
|
||||
| 12 = @uintptrtype
|
||||
| 13 = @float32type
|
||||
| 14 = @float64type
|
||||
| 15 = @complex64type
|
||||
| 16 = @complex128type
|
||||
| 17 = @stringexprtype
|
||||
| 18 = @unsafepointertype
|
||||
| 19 = @boolliteraltype
|
||||
| 20 = @intliteraltype
|
||||
| 21 = @runeliteraltype
|
||||
| 22 = @floatliteraltype
|
||||
| 23 = @complexliteraltype
|
||||
| 24 = @stringliteraltype
|
||||
| 25 = @nilliteraltype
|
||||
| 26 = @typeparamtype
|
||||
| 27 = @arraytype
|
||||
| 28 = @slicetype
|
||||
| 29 = @structtype
|
||||
| 30 = @pointertype
|
||||
| 31 = @interfacetype
|
||||
| 32 = @tupletype
|
||||
| 33 = @signaturetype
|
||||
| 34 = @maptype
|
||||
| 35 = @sendchantype
|
||||
| 36 = @recvchantype
|
||||
| 37 = @sendrcvchantype
|
||||
| 38 = @namedtype
|
||||
| 39 = @typesetliteraltype;
|
||||
|
||||
@basictype = @booltype | @numerictype | @stringtype | @literaltype | @invalidtype | @unsafepointertype;
|
||||
|
||||
@booltype = @boolexprtype | @boolliteraltype;
|
||||
|
||||
@numerictype = @integertype | @floattype | @complextype;
|
||||
|
||||
@integertype = @signedintegertype | @unsignedintegertype;
|
||||
|
||||
@signedintegertype = @inttype | @int8type | @int16type | @int32type | @int64type | @intliteraltype | @runeliteraltype;
|
||||
|
||||
@unsignedintegertype = @uinttype | @uint8type | @uint16type | @uint32type | @uint64type | @uintptrtype;
|
||||
|
||||
@floattype = @float32type | @float64type | @floatliteraltype;
|
||||
|
||||
@complextype = @complex64type | @complex128type | @complexliteraltype;
|
||||
|
||||
@stringtype = @stringexprtype | @stringliteraltype;
|
||||
|
||||
@literaltype = @boolliteraltype | @intliteraltype | @runeliteraltype | @floatliteraltype | @complexliteraltype
|
||||
| @stringliteraltype | @nilliteraltype;
|
||||
|
||||
@compositetype = @typeparamtype | @containertype | @structtype | @pointertype | @interfacetype | @tupletype
|
||||
| @signaturetype | @namedtype | @typesetliteraltype;
|
||||
|
||||
@containertype = @arraytype | @slicetype | @maptype | @chantype;
|
||||
|
||||
@chantype = @sendchantype | @recvchantype | @sendrcvchantype;
|
||||
|
||||
case @modexpr.kind of
|
||||
0 = @modcommentblock
|
||||
| 1 = @modline
|
||||
| 2 = @modlineblock
|
||||
| 3 = @modlparen
|
||||
| 4 = @modrparen;
|
||||
|
||||
case @error.kind of
|
||||
0 = @unknownerror
|
||||
| 1 = @listerror
|
||||
| 2 = @parseerror
|
||||
| 3 = @typeerror;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
description: Remove component-tags and interface-method-id tables
|
||||
compatibility: full
|
||||
|
||||
struct_tags.rel: delete
|
||||
interface_private_method_ids.rel: delete
|
||||
@@ -410,7 +410,7 @@ func AddDefaultSnippet(snippet string) bool {
|
||||
|
||||
// PrintDbScheme prints the schema of this database to the writer `w`
|
||||
func PrintDbScheme(w io.Writer) {
|
||||
fmt.Fprintf(w, "/** Auto-generated dbscheme; do not edit. */\n\n")
|
||||
fmt.Fprintf(w, "/** Auto-generated dbscheme; do not edit. Run `make gen` in directory `go/` to regenerate. */\n\n")
|
||||
for _, snippet := range defaultSnippets {
|
||||
fmt.Fprintf(w, "%s\n", snippet)
|
||||
}
|
||||
|
||||
@@ -1150,6 +1150,20 @@ var ComponentTypesTable = NewTable("component_types",
|
||||
EntityColumn(TypeType, "tp"),
|
||||
).KeySet("parent", "index")
|
||||
|
||||
// StructTagsTable is the table associating struct types with their component types' tags
|
||||
var StructTagsTable = NewTable("struct_tags",
|
||||
EntityColumn(StructType, "parent"),
|
||||
IntColumn("index"),
|
||||
StringColumn("tag"),
|
||||
).KeySet("parent", "index")
|
||||
|
||||
// InterfacePrivateMethodIdsTable is the table associating interface types with the indices and ids of their private methods.
|
||||
var InterfacePrivateMethodIdsTable = NewTable("interface_private_method_ids",
|
||||
EntityColumn(InterfaceType, "interface"),
|
||||
IntColumn("index"),
|
||||
StringColumn("id"),
|
||||
).KeySet("interface", "index")
|
||||
|
||||
// ArrayLengthTable is the table associating array types with their length (represented as a string
|
||||
// since Go array lengths are 64-bit and hence do not always fit into a QL integer)
|
||||
var ArrayLengthTable = NewTable("array_length",
|
||||
|
||||
@@ -1624,6 +1624,9 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label {
|
||||
name = ""
|
||||
}
|
||||
extractComponentType(tw, lbl, i, name, field.Type())
|
||||
if tp.Tag(i) != "" {
|
||||
dbscheme.StructTagsTable.Emit(tw, lbl, i, tp.Tag(i))
|
||||
}
|
||||
}
|
||||
case *types.Pointer:
|
||||
kind = dbscheme.PointerType.Index()
|
||||
@@ -1641,6 +1644,10 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label {
|
||||
extractMethod(tw, meth)
|
||||
|
||||
extractComponentType(tw, lbl, i, meth.Name(), meth.Type())
|
||||
|
||||
if !meth.Exported() {
|
||||
dbscheme.InterfacePrivateMethodIdsTable.Emit(tw, lbl, i, meth.Id())
|
||||
}
|
||||
}
|
||||
for i := 0; i < tp.NumEmbeddeds(); i++ {
|
||||
component := tp.EmbeddedType(i)
|
||||
|
||||
@@ -10,7 +10,7 @@ toolchain go1.23.1
|
||||
// bazel mod tidy
|
||||
require (
|
||||
golang.org/x/mod v0.21.0
|
||||
golang.org/x/tools v0.25.0
|
||||
golang.org/x/tools v0.26.0
|
||||
)
|
||||
|
||||
require golang.org/x/sync v0.8.0 // indirect
|
||||
|
||||
@@ -2,5 +2,5 @@ golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
|
||||
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.10
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.9
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.0.10
|
||||
|
||||
No user-facing changes.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user