зеркало из https://github.com/github/codeql.git
Merge branch 'main' into unsafeHtmlConstruction
This commit is contained in:
Коммит
7c6ee5f293
|
@ -19,4 +19,6 @@ runs:
|
|||
gh extension install github/gh-codeql
|
||||
gh codeql set-channel "$CHANNEL"
|
||||
gh codeql version
|
||||
printf "CODEQL_FETCHED_CODEQL_PATH=" >> "${GITHUB_ENV}"
|
||||
gh codeql version --format=json | jq -r .unpackedLocation >> "${GITHUB_ENV}"
|
||||
gh codeql version --format=json | jq -r .unpackedLocation >> "${GITHUB_PATH}"
|
||||
|
|
|
@ -10,6 +10,8 @@ There is [extensive documentation](https://codeql.github.com/docs/) on getting s
|
|||
|
||||
We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/main/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query.
|
||||
|
||||
For information on contributing to CodeQL documentation, see the "[contributing guide](docs/codeql/CONTRIBUTING.md)" for docs.
|
||||
|
||||
## License
|
||||
|
||||
The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com).
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImplForStringsNewReplacer.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
## 0.5.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Breaking Changes
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
## 0.5.1
|
||||
|
||||
No user-facing changes.
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
lastReleaseVersion: 0.5.0
|
||||
lastReleaseVersion: 0.5.1
|
||||
|
|
|
@ -45,6 +45,16 @@ module Consistency {
|
|||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */
|
||||
predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */
|
||||
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
|
@ -246,6 +256,7 @@ module Consistency {
|
|||
query predicate uniqueParameterNodeAtPosition(
|
||||
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||
) {
|
||||
not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and
|
||||
isParameterNode(p, c, pos) and
|
||||
not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and
|
||||
msg = "Parameters with overlapping positions."
|
||||
|
@ -254,6 +265,7 @@ module Consistency {
|
|||
query predicate uniqueParameterNodePosition(
|
||||
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||
) {
|
||||
not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and
|
||||
isParameterNode(p, c, pos) and
|
||||
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
||||
msg = "Parameter node with multiple positions."
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
private import RangeAnalysisStage
|
||||
|
||||
module FloatDelta implements DeltaSig {
|
||||
class Delta = float;
|
||||
|
||||
bindingset[d]
|
||||
bindingset[result]
|
||||
float toFloat(Delta d) { result = d }
|
||||
|
||||
bindingset[d]
|
||||
bindingset[result]
|
||||
int toInt(Delta d) { result = d }
|
||||
|
||||
bindingset[n]
|
||||
bindingset[result]
|
||||
Delta fromInt(int n) { result = n }
|
||||
|
||||
bindingset[f]
|
||||
Delta fromFloat(float f) {
|
||||
result =
|
||||
min(float diff, float res |
|
||||
diff = (res - f) and res = f.ceil()
|
||||
or
|
||||
diff = (f - res) and res = f.floor()
|
||||
|
|
||||
res order by diff
|
||||
)
|
||||
}
|
||||
}
|
|
@ -14,321 +14,328 @@ private import ModulusAnalysisSpecific::Private
|
|||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
private import RangeUtils
|
||||
private import RangeAnalysisStage
|
||||
|
||||
/**
|
||||
* Holds if `e + delta` equals `v` at `pos`.
|
||||
*/
|
||||
private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
|
||||
semSsaUpdateStep(v, e, delta) and pos.hasReadOfVar(v)
|
||||
or
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = semEqFlowCond(v, e, delta, true, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `add` is the addition of `larg` and `rarg`, neither of which are
|
||||
* `ConstantIntegerExpr`s.
|
||||
*/
|
||||
private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
|
||||
exists(SemAddExpr a | a = add |
|
||||
larg = a.getLeftOperand() and
|
||||
rarg = a.getRightOperand()
|
||||
) and
|
||||
not larg instanceof SemConstantIntegerExpr and
|
||||
not rarg instanceof SemConstantIntegerExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not
|
||||
* a `ConstantIntegerExpr`.
|
||||
*/
|
||||
private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
|
||||
exists(SemSubExpr s | s = sub |
|
||||
larg = s.getLeftOperand() and
|
||||
rarg = s.getRightOperand()
|
||||
) and
|
||||
not rarg instanceof SemConstantIntegerExpr
|
||||
}
|
||||
|
||||
/** Gets an expression that is the remainder modulo `mod` of `arg`. */
|
||||
private SemExpr modExpr(SemExpr arg, int mod) {
|
||||
exists(SemRemExpr rem |
|
||||
result = rem and
|
||||
arg = rem.getLeftOperand() and
|
||||
rem.getRightOperand().(SemConstantIntegerExpr).getIntValue() = mod and
|
||||
mod >= 2
|
||||
)
|
||||
or
|
||||
exists(SemConstantIntegerExpr c |
|
||||
mod = 2.pow([1 .. 30]) and
|
||||
c.getIntValue() = mod - 1 and
|
||||
result.(SemBitAndExpr).hasOperands(arg, c)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on
|
||||
* its `testIsTrue` branch.
|
||||
*/
|
||||
private SemGuard moduloCheck(SemSsaVariable v, int val, int mod, boolean testIsTrue) {
|
||||
exists(SemExpr rem, SemConstantIntegerExpr c, int r, boolean polarity |
|
||||
result.isEquality(rem, c, polarity) and
|
||||
c.getIntValue() = r and
|
||||
rem = modExpr(v.getAUse(), mod) and
|
||||
(
|
||||
testIsTrue = polarity and val = r
|
||||
or
|
||||
testIsTrue = polarity.booleanNot() and
|
||||
mod = 2 and
|
||||
val = 1 - r and
|
||||
(r = 0 or r = 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`.
|
||||
*/
|
||||
private predicate moduloGuardedRead(SemSsaVariable v, SemSsaReadPosition pos, int val, int mod) {
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = moduloCheck(v, val, mod, testIsTrue) and
|
||||
semGuardControlsSsaRead(guard, pos, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `factor` is a power of 2 that divides `mask`. */
|
||||
bindingset[mask]
|
||||
private predicate andmaskFactor(int mask, int factor) {
|
||||
mask % factor = 0 and
|
||||
factor = 2.pow([1 .. 30])
|
||||
}
|
||||
|
||||
/** Holds if `e` is evenly divisible by `factor`. */
|
||||
private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
|
||||
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
|
||||
e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
|
||||
or
|
||||
e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
|
||||
or
|
||||
e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `rix` is the number of input edges to `phi`.
|
||||
*/
|
||||
private predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
|
||||
rix = max(int r | rankedPhiInput(phi, _, _, r))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the remainder of `val` modulo `mod`.
|
||||
*
|
||||
* For `mod = 0` the result equals `val` and for `mod > 1` the result is within
|
||||
* the range `[0 .. mod-1]`.
|
||||
*/
|
||||
bindingset[val, mod]
|
||||
private int remainder(int val, int mod) {
|
||||
mod = 0 and result = val
|
||||
or
|
||||
mod > 1 and result = ((val % mod) + mod) % mod
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`.
|
||||
*/
|
||||
private predicate phiSelfModulus(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
|
||||
) {
|
||||
exists(SemSsaBound phibound, int v, int m |
|
||||
edge.phiInput(phi, inp) and
|
||||
phibound.getAVariable() = phi and
|
||||
ssaModulus(inp, edge, phibound, v, m) and
|
||||
mod = m.gcd(v) and
|
||||
mod != 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
|
||||
*/
|
||||
private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod) {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
edge.phiInput(phi, inp) and
|
||||
ssaModulus(inp, edge, b, val, mod)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
|
||||
/*
|
||||
* base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
|
||||
* class for the phi node.
|
||||
module ModulusAnalysis<DeltaSig D, BoundSig<D> Bounds, UtilSig<D> U> {
|
||||
/**
|
||||
* Holds if `e + delta` equals `v` at `pos`.
|
||||
*/
|
||||
private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
|
||||
U::semSsaUpdateStep(v, e, D::fromInt(delta)) and pos.hasReadOfVar(v)
|
||||
or
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = U::semEqFlowCond(v, e, D::fromInt(delta), true, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
rix = 0 and
|
||||
phiModulusInit(phi, b, val, mod)
|
||||
or
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
|
||||
mod != 1 and
|
||||
val = remainder(v1, mod)
|
||||
|
|
||||
/**
|
||||
* Holds if `add` is the addition of `larg` and `rarg`, neither of which are
|
||||
* `ConstantIntegerExpr`s.
|
||||
*/
|
||||
private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
|
||||
exists(SemAddExpr a | a = add |
|
||||
larg = a.getLeftOperand() and
|
||||
rarg = a.getRightOperand()
|
||||
) and
|
||||
not larg instanceof SemConstantIntegerExpr and
|
||||
not rarg instanceof SemConstantIntegerExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not
|
||||
* a `ConstantIntegerExpr`.
|
||||
*/
|
||||
private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
|
||||
exists(SemSubExpr s | s = sub |
|
||||
larg = s.getLeftOperand() and
|
||||
rarg = s.getRightOperand()
|
||||
) and
|
||||
not rarg instanceof SemConstantIntegerExpr
|
||||
}
|
||||
|
||||
/** Gets an expression that is the remainder modulo `mod` of `arg`. */
|
||||
private SemExpr modExpr(SemExpr arg, int mod) {
|
||||
exists(SemRemExpr rem |
|
||||
result = rem and
|
||||
arg = rem.getLeftOperand() and
|
||||
rem.getRightOperand().(SemConstantIntegerExpr).getIntValue() = mod and
|
||||
mod >= 2
|
||||
)
|
||||
or
|
||||
exists(SemConstantIntegerExpr c |
|
||||
mod = 2.pow([1 .. 30]) and
|
||||
c.getIntValue() = mod - 1 and
|
||||
result.(SemBitAndExpr).hasOperands(arg, c)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on
|
||||
* its `testIsTrue` branch.
|
||||
*/
|
||||
private SemGuard moduloCheck(SemSsaVariable v, int val, int mod, boolean testIsTrue) {
|
||||
exists(SemExpr rem, SemConstantIntegerExpr c, int r, boolean polarity |
|
||||
result.isEquality(rem, c, polarity) and
|
||||
c.getIntValue() = r and
|
||||
rem = modExpr(v.getAUse(), mod) and
|
||||
(
|
||||
testIsTrue = polarity and val = r
|
||||
or
|
||||
testIsTrue = polarity.booleanNot() and
|
||||
mod = 2 and
|
||||
val = 1 - r and
|
||||
(r = 0 or r = 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`.
|
||||
*/
|
||||
private predicate moduloGuardedRead(SemSsaVariable v, SemSsaReadPosition pos, int val, int mod) {
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = moduloCheck(v, val, mod, testIsTrue) and
|
||||
semGuardControlsSsaRead(guard, pos, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `factor` is a power of 2 that divides `mask`. */
|
||||
bindingset[mask]
|
||||
private predicate andmaskFactor(int mask, int factor) {
|
||||
mask % factor = 0 and
|
||||
factor = 2.pow([1 .. 30])
|
||||
}
|
||||
|
||||
/** Holds if `e` is evenly divisible by `factor`. */
|
||||
private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
|
||||
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
|
||||
e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
|
||||
or
|
||||
e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
|
||||
or
|
||||
e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `rix` is the number of input edges to `phi`.
|
||||
*/
|
||||
private predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
|
||||
rix = max(int r | rankedPhiInput(phi, _, _, r))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the remainder of `val` modulo `mod`.
|
||||
*
|
||||
* For `mod = 0` the result equals `val` and for `mod > 1` the result is within
|
||||
* the range `[0 .. mod-1]`.
|
||||
*/
|
||||
bindingset[val, mod]
|
||||
private int remainder(int val, int mod) {
|
||||
mod = 0 and result = val
|
||||
or
|
||||
mod > 1 and result = ((val % mod) + mod) % mod
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`.
|
||||
*/
|
||||
private predicate phiSelfModulus(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
|
||||
) {
|
||||
exists(Bounds::SemSsaBound phibound, int v, int m |
|
||||
edge.phiInput(phi, inp) and
|
||||
phibound.getAVariable() = phi and
|
||||
ssaModulus(inp, edge, phibound, v, m) and
|
||||
mod = m.gcd(v) and
|
||||
mod != 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
|
||||
*/
|
||||
private predicate phiModulusInit(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
edge.phiInput(phi, inp) and
|
||||
ssaModulus(inp, edge, b, val, mod)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate phiModulusRankStep(
|
||||
SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod, int rix
|
||||
) {
|
||||
/*
|
||||
* Recursive case. If `inp` = `b + v2` mod `m2`, we combine that with the preceding potential
|
||||
* congruence class `b + v1` mod `m1`. The result will be the congruence class of `v1` modulo
|
||||
* the greatest common denominator of `m1`, `m2`, and `v1 - v2`.
|
||||
* base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
|
||||
* class for the phi node.
|
||||
*/
|
||||
|
||||
exists(int v2, int m2 |
|
||||
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
|
||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||
ssaModulus(inp, edge, b, v2, m2) and
|
||||
mod = m1.gcd(m2).gcd(v1 - v2)
|
||||
rix = 0 and
|
||||
phiModulusInit(phi, b, val, mod)
|
||||
or
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
|
||||
mod != 1 and
|
||||
val = remainder(v1, mod)
|
||||
|
|
||||
/*
|
||||
* Recursive case. If `inp` = `b + v2` mod `m2`, we combine that with the preceding potential
|
||||
* congruence class `b + v1` mod `m1`. The result will be the congruence class of `v1` modulo
|
||||
* the greatest common denominator of `m1`, `m2`, and `v1 - v2`.
|
||||
*/
|
||||
|
||||
exists(int v2, int m2 |
|
||||
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
|
||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||
ssaModulus(inp, edge, b, v2, m2) and
|
||||
mod = m1.gcd(m2).gcd(v1 - v2)
|
||||
)
|
||||
or
|
||||
/*
|
||||
* Recursive case. If `inp` = `phi` mod `m2`, we combine that with the preceding potential
|
||||
* congruence class `b + v1` mod `m1`. The result will be a congruence class modulo the greatest
|
||||
* common denominator of `m1` and `m2`.
|
||||
*/
|
||||
|
||||
exists(int m2 |
|
||||
rankedPhiInput(phi, inp, edge, rix) and
|
||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||
phiSelfModulus(phi, inp, edge, m2) and
|
||||
mod = m1.gcd(m2)
|
||||
)
|
||||
)
|
||||
or
|
||||
/*
|
||||
* Recursive case. If `inp` = `phi` mod `m2`, we combine that with the preceding potential
|
||||
* congruence class `b + v1` mod `m1`. The result will be a congruence class modulo the greatest
|
||||
* common denominator of `m1` and `m2`.
|
||||
*/
|
||||
}
|
||||
|
||||
exists(int m2 |
|
||||
rankedPhiInput(phi, inp, edge, rix) and
|
||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||
phiSelfModulus(phi, inp, edge, m2) and
|
||||
mod = m1.gcd(m2)
|
||||
/**
|
||||
* Holds if `phi` is equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
private predicate phiModulus(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
|
||||
exists(int r |
|
||||
maxPhiInputRank(phi, r) and
|
||||
phiModulusRankStep(phi, b, val, mod, r)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `phi` is equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
private predicate phiModulus(SemSsaPhiNode phi, SemBound b, int val, int mod) {
|
||||
exists(int r |
|
||||
maxPhiInputRank(phi, r) and
|
||||
phiModulusRankStep(phi, b, val, mod, r)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
private predicate ssaModulus(SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int val, int mod) {
|
||||
phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
|
||||
or
|
||||
b.(SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
|
||||
or
|
||||
exists(SemExpr e, int val0, int delta |
|
||||
semExprModulus(e, b, val0, mod) and
|
||||
valueFlowStepSsa(v, pos, e, delta) and
|
||||
val = remainder(val0 + delta, mod)
|
||||
)
|
||||
or
|
||||
moduloGuardedRead(v, pos, val, mod) and b instanceof SemZeroBound
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is equal to `b + val` modulo `mod`.
|
||||
*
|
||||
* There are two cases for the modulus:
|
||||
* - `mod = 0`: The equality `e = b + val` is an ordinary equality.
|
||||
* - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
|
||||
*/
|
||||
cached
|
||||
predicate semExprModulus(SemExpr e, SemBound b, int val, int mod) {
|
||||
not ignoreExprModulus(e) and
|
||||
(
|
||||
e = b.getExpr(val) and mod = 0
|
||||
/**
|
||||
* Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
private predicate ssaModulus(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, Bounds::SemBound b, int val, int mod
|
||||
) {
|
||||
phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
|
||||
or
|
||||
evenlyDivisibleExpr(e, mod) and
|
||||
val = 0 and
|
||||
b instanceof SemZeroBound
|
||||
b.(Bounds::SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
|
||||
or
|
||||
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
||||
ssaModulus(v, bb, b, val, mod) and
|
||||
e = v.getAUse() and
|
||||
bb.getAnExpr() = e
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int val0, int delta |
|
||||
semExprModulus(mid, b, val0, mod) and
|
||||
semValueFlowStep(e, mid, delta) and
|
||||
exists(SemExpr e, int val0, int delta |
|
||||
semExprModulus(e, b, val0, mod) and
|
||||
valueFlowStepSsa(v, pos, e, delta) and
|
||||
val = remainder(val0 + delta, mod)
|
||||
)
|
||||
or
|
||||
exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
|
||||
cond = e and
|
||||
condExprBranchModulus(cond, true, b, v1, m1) and
|
||||
condExprBranchModulus(cond, false, b, v2, m2) and
|
||||
mod = m1.gcd(m2).gcd(v1 - v2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1, mod)
|
||||
)
|
||||
or
|
||||
exists(SemBound b1, SemBound b2, int v1, int v2, int m1, int m2 |
|
||||
addModulus(e, true, b1, v1, m1) and
|
||||
addModulus(e, false, b2, v2, m2) and
|
||||
mod = m1.gcd(m2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1 + v2, mod)
|
||||
|
|
||||
b = b1 and b2 instanceof SemZeroBound
|
||||
moduloGuardedRead(v, pos, val, mod) and b instanceof Bounds::SemZeroBound
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is equal to `b + val` modulo `mod`.
|
||||
*
|
||||
* There are two cases for the modulus:
|
||||
* - `mod = 0`: The equality `e = b + val` is an ordinary equality.
|
||||
* - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
|
||||
*/
|
||||
cached
|
||||
predicate semExprModulus(SemExpr e, Bounds::SemBound b, int val, int mod) {
|
||||
not ignoreExprModulus(e) and
|
||||
(
|
||||
e = b.getExpr(D::fromInt(val)) and mod = 0
|
||||
or
|
||||
b = b2 and b1 instanceof SemZeroBound
|
||||
evenlyDivisibleExpr(e, mod) and
|
||||
val = 0 and
|
||||
b instanceof Bounds::SemZeroBound
|
||||
or
|
||||
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
||||
ssaModulus(v, bb, b, val, mod) and
|
||||
e = v.getAUse() and
|
||||
bb.getAnExpr() = e
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int val0, int delta |
|
||||
semExprModulus(mid, b, val0, mod) and
|
||||
U::semValueFlowStep(e, mid, D::fromInt(delta)) and
|
||||
val = remainder(val0 + delta, mod)
|
||||
)
|
||||
or
|
||||
exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
|
||||
cond = e and
|
||||
condExprBranchModulus(cond, true, b, v1, m1) and
|
||||
condExprBranchModulus(cond, false, b, v2, m2) and
|
||||
mod = m1.gcd(m2).gcd(v1 - v2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1, mod)
|
||||
)
|
||||
or
|
||||
exists(Bounds::SemBound b1, Bounds::SemBound b2, int v1, int v2, int m1, int m2 |
|
||||
addModulus(e, true, b1, v1, m1) and
|
||||
addModulus(e, false, b2, v2, m2) and
|
||||
mod = m1.gcd(m2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1 + v2, mod)
|
||||
|
|
||||
b = b1 and b2 instanceof Bounds::SemZeroBound
|
||||
or
|
||||
b = b2 and b1 instanceof Bounds::SemZeroBound
|
||||
)
|
||||
or
|
||||
exists(int v1, int v2, int m1, int m2 |
|
||||
subModulus(e, true, b, v1, m1) and
|
||||
subModulus(e, false, any(Bounds::SemZeroBound zb), v2, m2) and
|
||||
mod = m1.gcd(m2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1 - v2, mod)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(int v1, int v2, int m1, int m2 |
|
||||
subModulus(e, true, b, v1, m1) and
|
||||
subModulus(e, false, any(SemZeroBound zb), v2, m2) and
|
||||
mod = m1.gcd(m2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1 - v2, mod)
|
||||
}
|
||||
|
||||
private predicate condExprBranchModulus(
|
||||
SemConditionalExpr cond, boolean branch, Bounds::SemBound b, int val, int mod
|
||||
) {
|
||||
semExprModulus(cond.getBranchExpr(branch), b, val, mod)
|
||||
}
|
||||
|
||||
private predicate addModulus(SemExpr add, boolean isLeft, Bounds::SemBound b, int val, int mod) {
|
||||
exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
|
||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
||||
or
|
||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate condExprBranchModulus(
|
||||
SemConditionalExpr cond, boolean branch, SemBound b, int val, int mod
|
||||
) {
|
||||
semExprModulus(cond.getBranchExpr(branch), b, val, mod)
|
||||
}
|
||||
|
||||
private predicate addModulus(SemExpr add, boolean isLeft, SemBound b, int val, int mod) {
|
||||
exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
|
||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
||||
or
|
||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
||||
)
|
||||
}
|
||||
|
||||
private predicate subModulus(SemExpr sub, boolean isLeft, SemBound b, int val, int mod) {
|
||||
exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
|
||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
||||
or
|
||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
|
||||
* in an arbitrary 1-based numbering of the input edges to `phi`.
|
||||
*/
|
||||
private predicate rankedPhiInput(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
|
||||
) {
|
||||
edge.phiInput(phi, inp) and
|
||||
edge =
|
||||
rank[r](SemSsaReadPositionPhiInputEdge e |
|
||||
e.phiInput(phi, _)
|
||||
|
|
||||
e order by e.getOrigBlock().getUniqueId()
|
||||
private predicate subModulus(SemExpr sub, boolean isLeft, Bounds::SemBound b, int val, int mod) {
|
||||
exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
|
||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
||||
or
|
||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
|
||||
* in an arbitrary 1-based numbering of the input edges to `phi`.
|
||||
*/
|
||||
private predicate rankedPhiInput(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
|
||||
) {
|
||||
edge.phiInput(phi, inp) and
|
||||
edge =
|
||||
rank[r](SemSsaReadPositionPhiInputEdge e |
|
||||
e.phiInput(phi, _)
|
||||
|
|
||||
e order by e.getOrigBlock().getUniqueId()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,830 +1,24 @@
|
|||
/**
|
||||
* Provides classes and predicates for range analysis.
|
||||
*
|
||||
* An inferred bound can either be a specific integer, the abstract value of an
|
||||
* SSA variable, or the abstract value of an interesting expression. The latter
|
||||
* category includes array lengths that are not SSA variables.
|
||||
*
|
||||
* If an inferred bound relies directly on a condition, then this condition is
|
||||
* reported as the reason for the bound.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This library tackles range analysis as a flow problem. Consider e.g.:
|
||||
* ```
|
||||
* len = arr.length;
|
||||
* if (x < len) { ... y = x-1; ... y ... }
|
||||
* ```
|
||||
* In this case we would like to infer `y <= arr.length - 2`, and this is
|
||||
* accomplished by tracking the bound through a sequence of steps:
|
||||
* ```
|
||||
* arr.length --> len = .. --> x < len --> x-1 --> y = .. --> y
|
||||
* ```
|
||||
*
|
||||
* In its simplest form the step relation `E1 --> E2` relates two expressions
|
||||
* such that `E1 <= B` implies `E2 <= B` for any `B` (with a second separate
|
||||
* step relation handling lower bounds). Examples of such steps include
|
||||
* assignments `E2 = E1` and conditions `x <= E1` where `E2` is a use of `x`
|
||||
* guarded by the condition.
|
||||
*
|
||||
* In order to handle subtractions and additions with constants, and strict
|
||||
* comparisons, the step relation is augmented with an integer delta. With this
|
||||
* generalization `E1 --(delta)--> E2` relates two expressions and an integer
|
||||
* such that `E1 <= B` implies `E2 <= B + delta` for any `B`. This corresponds
|
||||
* to the predicate `boundFlowStep`.
|
||||
*
|
||||
* The complete range analysis is then implemented as the transitive closure of
|
||||
* the step relation summing the deltas along the way. If `E1` transitively
|
||||
* steps to `E2`, `delta` is the sum of deltas along the path, and `B` is an
|
||||
* interesting bound equal to the value of `E1` then `E2 <= B + delta`. This
|
||||
* corresponds to the predicate `bounded`.
|
||||
*
|
||||
* Phi nodes need a little bit of extra handling. Consider `x0 = phi(x1, x2)`.
|
||||
* There are essentially two cases:
|
||||
* - If `x1 <= B + d1` and `x2 <= B + d2` then `x0 <= B + max(d1,d2)`.
|
||||
* - If `x1 <= B + d1` and `x2 <= x0 + d2` with `d2 <= 0` then `x0 <= B + d1`.
|
||||
* The first case is for whenever a bound can be proven without taking looping
|
||||
* into account. The second case is relevant when `x2` comes from a back-edge
|
||||
* where we can prove that the variable has been non-increasing through the
|
||||
* loop-iteration as this means that any upper bound that holds prior to the
|
||||
* loop also holds for the variable during the loop.
|
||||
* This generalizes to a phi node with `n` inputs, so if
|
||||
* `x0 = phi(x1, ..., xn)` and `xi <= B + delta` for one of the inputs, then we
|
||||
* also have `x0 <= B + delta` if we can prove either:
|
||||
* - `xj <= B + d` with `d <= delta` or
|
||||
* - `xj <= x0 + d` with `d <= 0`
|
||||
* for each input `xj`.
|
||||
*
|
||||
* As all inferred bounds can be related directly to a path in the source code
|
||||
* the only source of non-termination is if successive redundant (and thereby
|
||||
* increasingly worse) bounds are calculated along a loop in the source code.
|
||||
* We prevent this by weakening the bound to a small finite set of bounds when
|
||||
* a path follows a second back-edge (we postpone weakening till the second
|
||||
* back-edge as a precise bound might require traversing a loop once).
|
||||
*/
|
||||
|
||||
private import RangeAnalysisSpecific as Specific
|
||||
private import RangeAnalysisStage
|
||||
private import RangeAnalysisSpecific
|
||||
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
private import RangeUtils
|
||||
private import SignAnalysisCommon
|
||||
private import ModulusAnalysis
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
private import experimental.semmle.code.cpp.semantic.SemanticBound as SemanticBound
|
||||
|
||||
cached
|
||||
private module RangeAnalysisCache {
|
||||
cached
|
||||
module RangeAnalysisPublic {
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `e`.
|
||||
* - `upper = true` : `e <= b + delta`
|
||||
* - `upper = false` : `e >= b + delta`
|
||||
*
|
||||
* The reason for the bound is given by `reason` and may be either a condition
|
||||
* or `NoReason` if the bound was proven directly without the use of a bounding
|
||||
* condition.
|
||||
*/
|
||||
cached
|
||||
predicate semBounded(SemExpr e, SemBound b, int delta, boolean upper, SemReason reason) {
|
||||
bounded(e, b, delta, upper, _, _, reason) and
|
||||
bestBound(e, b, delta, upper)
|
||||
}
|
||||
module Bounds implements BoundSig<FloatDelta> {
|
||||
class SemBound instanceof SemanticBound::SemBound {
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
SemExpr getExpr(float delta) { result = super.getExpr(delta) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard = boundFlowCond(_, _, _, _, _) or guard = eqFlowCond(_, _, _, _, _)`.
|
||||
*/
|
||||
cached
|
||||
predicate possibleReason(SemGuard guard) {
|
||||
guard = boundFlowCond(_, _, _, _, _) or guard = semEqFlowCond(_, _, _, _, _)
|
||||
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
||||
|
||||
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
||||
SemSsaVariable getAVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||
}
|
||||
}
|
||||
|
||||
private import RangeAnalysisCache
|
||||
import RangeAnalysisPublic
|
||||
private module CppRangeAnalysis =
|
||||
RangeStage<FloatDelta, Bounds, CppLangImpl, RangeUtil<FloatDelta, CppLangImpl>>;
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `e` and this is the best such delta.
|
||||
* - `upper = true` : `e <= b + delta`
|
||||
* - `upper = false` : `e >= b + delta`
|
||||
*/
|
||||
private predicate bestBound(SemExpr e, SemBound b, int delta, boolean upper) {
|
||||
delta = min(int d | bounded(e, b, d, upper, _, _, _)) and upper = true
|
||||
or
|
||||
delta = max(int d | bounded(e, b, d, upper, _, _, _)) and upper = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `comp` corresponds to:
|
||||
* - `upper = true` : `v <= e + delta` or `v < e + delta`
|
||||
* - `upper = false` : `v >= e + delta` or `v > e + delta`
|
||||
*/
|
||||
private predicate boundCondition(
|
||||
SemRelationalExpr comp, SemSsaVariable v, SemExpr e, int delta, boolean upper
|
||||
) {
|
||||
comp.getLesserOperand() = semSsaRead(v, delta) and e = comp.getGreaterOperand() and upper = true
|
||||
or
|
||||
comp.getGreaterOperand() = semSsaRead(v, delta) and e = comp.getLesserOperand() and upper = false
|
||||
or
|
||||
exists(SemSubExpr sub, SemConstantIntegerExpr c, int d |
|
||||
// (v - d) - e < c
|
||||
comp.getLesserOperand() = sub and
|
||||
comp.getGreaterOperand() = c and
|
||||
sub.getLeftOperand() = semSsaRead(v, d) and
|
||||
sub.getRightOperand() = e and
|
||||
upper = true and
|
||||
delta = d + c.getIntValue()
|
||||
or
|
||||
// (v - d) - e > c
|
||||
comp.getGreaterOperand() = sub and
|
||||
comp.getLesserOperand() = c and
|
||||
sub.getLeftOperand() = semSsaRead(v, d) and
|
||||
sub.getRightOperand() = e and
|
||||
upper = false and
|
||||
delta = d + c.getIntValue()
|
||||
or
|
||||
// e - (v - d) < c
|
||||
comp.getLesserOperand() = sub and
|
||||
comp.getGreaterOperand() = c and
|
||||
sub.getLeftOperand() = e and
|
||||
sub.getRightOperand() = semSsaRead(v, d) and
|
||||
upper = false and
|
||||
delta = d - c.getIntValue()
|
||||
or
|
||||
// e - (v - d) > c
|
||||
comp.getGreaterOperand() = sub and
|
||||
comp.getLesserOperand() = c and
|
||||
sub.getLeftOperand() = e and
|
||||
sub.getRightOperand() = semSsaRead(v, d) and
|
||||
upper = true and
|
||||
delta = d - c.getIntValue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `comp` is a comparison between `x` and `y` for which `y - x` has a
|
||||
* fixed value modulo some `mod > 1`, such that the comparison can be
|
||||
* strengthened by `strengthen` when evaluating to `testIsTrue`.
|
||||
*/
|
||||
private predicate modulusComparison(SemRelationalExpr comp, boolean testIsTrue, int strengthen) {
|
||||
exists(
|
||||
SemBound b, int v1, int v2, int mod1, int mod2, int mod, boolean resultIsStrict, int d, int k
|
||||
|
|
||||
// If `x <= y` and `x =(mod) b + v1` and `y =(mod) b + v2` then
|
||||
// `0 <= y - x =(mod) v2 - v1`. By choosing `k =(mod) v2 - v1` with
|
||||
// `0 <= k < mod` we get `k <= y - x`. If the resulting comparison is
|
||||
// strict then the strengthening amount is instead `k - 1` modulo `mod`:
|
||||
// `x < y` means `0 <= y - x - 1 =(mod) k - 1` so `k - 1 <= y - x - 1` and
|
||||
// thus `k - 1 < y - x` with `0 <= k - 1 < mod`.
|
||||
semExprModulus(comp.getLesserOperand(), b, v1, mod1) and
|
||||
semExprModulus(comp.getGreaterOperand(), b, v2, mod2) and
|
||||
mod = mod1.gcd(mod2) and
|
||||
mod != 1 and
|
||||
(testIsTrue = true or testIsTrue = false) and
|
||||
(
|
||||
if comp.isStrict()
|
||||
then resultIsStrict = testIsTrue
|
||||
else resultIsStrict = testIsTrue.booleanNot()
|
||||
) and
|
||||
(
|
||||
resultIsStrict = true and d = 1
|
||||
or
|
||||
resultIsStrict = false and d = 0
|
||||
) and
|
||||
(
|
||||
testIsTrue = true and k = v2 - v1
|
||||
or
|
||||
testIsTrue = false and k = v1 - v2
|
||||
) and
|
||||
strengthen = (((k - d) % mod) + mod) % mod
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a condition that tests whether `v` is bounded by `e + delta`.
|
||||
*
|
||||
* If the condition evaluates to `testIsTrue`:
|
||||
* - `upper = true` : `v <= e + delta`
|
||||
* - `upper = false` : `v >= e + delta`
|
||||
*/
|
||||
private SemGuard boundFlowCond(
|
||||
SemSsaVariable v, SemExpr e, int delta, boolean upper, boolean testIsTrue
|
||||
) {
|
||||
exists(
|
||||
SemRelationalExpr comp, int d1, int d2, int d3, int strengthen, boolean compIsUpper,
|
||||
boolean resultIsStrict
|
||||
|
|
||||
comp = result.asExpr() and
|
||||
boundCondition(comp, v, e, d1, compIsUpper) and
|
||||
(testIsTrue = true or testIsTrue = false) and
|
||||
upper = compIsUpper.booleanXor(testIsTrue.booleanNot()) and
|
||||
(
|
||||
if comp.isStrict()
|
||||
then resultIsStrict = testIsTrue
|
||||
else resultIsStrict = testIsTrue.booleanNot()
|
||||
) and
|
||||
(
|
||||
if
|
||||
getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
|
||||
getTrackedTypeForSsaVariable(v) instanceof SemAddressType
|
||||
then
|
||||
upper = true and strengthen = -1
|
||||
or
|
||||
upper = false and strengthen = 1
|
||||
else strengthen = 0
|
||||
) and
|
||||
(
|
||||
exists(int k | modulusComparison(comp, testIsTrue, k) and d2 = strengthen * k)
|
||||
or
|
||||
not modulusComparison(comp, testIsTrue, _) and d2 = 0
|
||||
) and
|
||||
// A strict inequality `x < y` can be strengthened to `x <= y - 1`.
|
||||
(
|
||||
resultIsStrict = true and d3 = strengthen
|
||||
or
|
||||
resultIsStrict = false and d3 = 0
|
||||
) and
|
||||
delta = d1 + d2 + d3
|
||||
)
|
||||
or
|
||||
exists(boolean testIsTrue0 |
|
||||
semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
|
||||
)
|
||||
or
|
||||
result = semEqFlowCond(v, e, delta, true, testIsTrue) and
|
||||
(upper = true or upper = false)
|
||||
or
|
||||
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
|
||||
// exists a guard `guardEq` such that `v = v2 - d1 + d2`.
|
||||
exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, int d1, int d2 |
|
||||
guardEq = semEqFlowCond(v, semSsaRead(v2, d1), d2, true, eqIsTrue) and
|
||||
result = boundFlowCond(v2, e, delta + d1 - d2, upper, testIsTrue) and
|
||||
// guardEq needs to control guard
|
||||
guardEq.directlyControls(result.getBasicBlock(), eqIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TSemReason =
|
||||
TSemNoReason() or
|
||||
TSemCondReason(SemGuard guard) { possibleReason(guard) }
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound. This can either be `CondReason` if the bound
|
||||
* is due to a specific condition, or `NoReason` if the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
abstract class SemReason extends TSemReason {
|
||||
/** Gets a textual representation of this reason. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
class SemNoReason extends SemReason, TSemNoReason {
|
||||
override string toString() { result = "NoReason" }
|
||||
}
|
||||
|
||||
/** A reason for an inferred bound pointing to a condition. */
|
||||
class SemCondReason extends SemReason, TSemCondReason {
|
||||
/** Gets the condition that is the reason for the bound. */
|
||||
SemGuard getCond() { this = TSemCondReason(result) }
|
||||
|
||||
override string toString() { result = getCond().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e + delta` is a valid bound for `v` at `pos`.
|
||||
* - `upper = true` : `v <= e + delta`
|
||||
* - `upper = false` : `v >= e + delta`
|
||||
*/
|
||||
private predicate boundFlowStepSsa(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, boolean upper, SemReason reason
|
||||
) {
|
||||
semSsaUpdateStep(v, e, delta) and
|
||||
pos.hasReadOfVar(v) and
|
||||
(upper = true or upper = false) and
|
||||
reason = TSemNoReason()
|
||||
or
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = boundFlowCond(v, e, delta, upper, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
|
||||
reason = TSemCondReason(guard)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `v != e + delta` at `pos` and `v` is of integral type. */
|
||||
private predicate unequalFlowStepIntegralSsa(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, SemReason reason
|
||||
) {
|
||||
getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = semEqFlowCond(v, e, delta, false, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
|
||||
reason = TSemCondReason(guard)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that does conversion, boxing, or unboxing
|
||||
*/
|
||||
private class ConvertOrBoxExpr extends SemUnaryExpr {
|
||||
ConvertOrBoxExpr() {
|
||||
this instanceof SemConvertExpr
|
||||
or
|
||||
this instanceof SemBoxExpr
|
||||
or
|
||||
this instanceof SemUnboxExpr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A cast that can be ignored for the purpose of range analysis.
|
||||
*/
|
||||
private class SafeCastExpr extends ConvertOrBoxExpr {
|
||||
SafeCastExpr() {
|
||||
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
|
||||
getTrackedType(this))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `typ` is a small integral type with the given lower and upper bounds.
|
||||
*/
|
||||
private predicate typeBound(SemIntegerType typ, int lowerbound, int upperbound) {
|
||||
exists(int bitSize | bitSize = typ.getByteSize() * 8 |
|
||||
bitSize < 32 and
|
||||
(
|
||||
if typ.isSigned()
|
||||
then (
|
||||
upperbound = 1.bitShiftLeft(bitSize - 1) - 1 and
|
||||
lowerbound = -upperbound - 1
|
||||
) else (
|
||||
lowerbound = 0 and
|
||||
upperbound = 1.bitShiftLeft(bitSize) - 1
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A cast to a small integral type that may overflow or underflow.
|
||||
*/
|
||||
private class NarrowingCastExpr extends ConvertOrBoxExpr {
|
||||
NarrowingCastExpr() {
|
||||
not this instanceof SafeCastExpr and
|
||||
typeBound(getTrackedType(this), _, _)
|
||||
}
|
||||
|
||||
/** Gets the lower bound of the resulting type. */
|
||||
int getLowerBound() { typeBound(getTrackedType(this), result, _) }
|
||||
|
||||
/** Gets the upper bound of the resulting type. */
|
||||
int getUpperBound() { typeBound(getTrackedType(this), _, result) }
|
||||
}
|
||||
|
||||
/** Holds if `e >= 1` as determined by sign analysis. */
|
||||
private predicate strictlyPositiveIntegralExpr(SemExpr e) {
|
||||
semStrictlyPositive(e) and getTrackedType(e) instanceof SemIntegerType
|
||||
}
|
||||
|
||||
/** Holds if `e <= -1` as determined by sign analysis. */
|
||||
private predicate strictlyNegativeIntegralExpr(SemExpr e) {
|
||||
semStrictlyNegative(e) and getTrackedType(e) instanceof SemIntegerType
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e1 + delta` is a valid bound for `e2`.
|
||||
* - `upper = true` : `e2 <= e1 + delta`
|
||||
* - `upper = false` : `e2 >= e1 + delta`
|
||||
*/
|
||||
private predicate boundFlowStep(SemExpr e2, SemExpr e1, int delta, boolean upper) {
|
||||
semValueFlowStep(e2, e1, delta) and
|
||||
(upper = true or upper = false)
|
||||
or
|
||||
e2.(SafeCastExpr).getOperand() = e1 and
|
||||
delta = 0 and
|
||||
(upper = true or upper = false)
|
||||
or
|
||||
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
|
||||
// `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
|
||||
not x instanceof SemConstantIntegerExpr and
|
||||
not e1 instanceof SemConstantIntegerExpr and
|
||||
if strictlyPositiveIntegralExpr(x)
|
||||
then upper = false and delta = 1
|
||||
else
|
||||
if semPositive(x)
|
||||
then upper = false and delta = 0
|
||||
else
|
||||
if strictlyNegativeIntegralExpr(x)
|
||||
then upper = true and delta = -1
|
||||
else
|
||||
if semNegative(x)
|
||||
then upper = true and delta = 0
|
||||
else none()
|
||||
)
|
||||
or
|
||||
exists(SemExpr x, SemSubExpr sub |
|
||||
e2 = sub and
|
||||
sub.getLeftOperand() = e1 and
|
||||
sub.getRightOperand() = x
|
||||
|
|
||||
// `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
|
||||
not x instanceof SemConstantIntegerExpr and
|
||||
if strictlyPositiveIntegralExpr(x)
|
||||
then upper = true and delta = -1
|
||||
else
|
||||
if semPositive(x)
|
||||
then upper = true and delta = 0
|
||||
else
|
||||
if strictlyNegativeIntegralExpr(x)
|
||||
then upper = false and delta = 1
|
||||
else
|
||||
if semNegative(x)
|
||||
then upper = false and delta = 0
|
||||
else none()
|
||||
)
|
||||
or
|
||||
e2.(SemRemExpr).getRightOperand() = e1 and
|
||||
semPositive(e1) and
|
||||
delta = -1 and
|
||||
upper = true
|
||||
or
|
||||
e2.(SemRemExpr).getLeftOperand() = e1 and semPositive(e1) and delta = 0 and upper = true
|
||||
or
|
||||
e2.(SemBitAndExpr).getAnOperand() = e1 and
|
||||
semPositive(e1) and
|
||||
delta = 0 and
|
||||
upper = true
|
||||
or
|
||||
e2.(SemBitOrExpr).getAnOperand() = e1 and
|
||||
semPositive(e2) and
|
||||
delta = 0 and
|
||||
upper = false
|
||||
or
|
||||
Specific::hasBound(e2, e1, delta, upper)
|
||||
}
|
||||
|
||||
/** Holds if `e2 = e1 * factor` and `factor > 0`. */
|
||||
private predicate boundFlowStepMul(SemExpr e2, SemExpr e1, int factor) {
|
||||
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
|
||||
e2.(SemMulExpr).hasOperands(e1, c) and factor = k
|
||||
or
|
||||
exists(SemShiftLeftExpr e |
|
||||
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e2 = e1 / factor` and `factor > 0`.
|
||||
*
|
||||
* This conflates division, right shift, and unsigned right shift and is
|
||||
* therefore only valid for non-negative numbers.
|
||||
*/
|
||||
private predicate boundFlowStepDiv(SemExpr e2, SemExpr e1, int factor) {
|
||||
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
|
||||
exists(SemDivExpr e |
|
||||
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = k
|
||||
)
|
||||
or
|
||||
exists(SemShiftRightExpr e |
|
||||
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
|
||||
)
|
||||
or
|
||||
exists(SemShiftRightUnsignedExpr e |
|
||||
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `v` at `pos`.
|
||||
* - `upper = true` : `v <= b + delta`
|
||||
* - `upper = false` : `v >= b + delta`
|
||||
*/
|
||||
private predicate boundedSsa(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, boolean upper,
|
||||
boolean fromBackEdge, int origdelta, SemReason reason
|
||||
) {
|
||||
exists(SemExpr mid, int d1, int d2, SemReason r1, SemReason r2 |
|
||||
boundFlowStepSsa(v, pos, mid, d1, upper, r1) and
|
||||
bounded(mid, b, d2, upper, fromBackEdge, origdelta, r2) and
|
||||
// upper = true: v <= mid + d1 <= b + d1 + d2 = b + delta
|
||||
// upper = false: v >= mid + d1 >= b + d1 + d2 = b + delta
|
||||
delta = d1 + d2 and
|
||||
(if r1 instanceof SemNoReason then reason = r2 else reason = r1)
|
||||
)
|
||||
or
|
||||
exists(int d, SemReason r1, SemReason r2 |
|
||||
boundedSsa(v, pos, b, d, upper, fromBackEdge, origdelta, r2) or
|
||||
boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2)
|
||||
|
|
||||
unequalIntegralSsa(v, pos, b, d, r1) and
|
||||
(
|
||||
upper = true and delta = d - 1
|
||||
or
|
||||
upper = false and delta = d + 1
|
||||
) and
|
||||
(
|
||||
reason = r1
|
||||
or
|
||||
reason = r2 and not r2 instanceof SemNoReason
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v != b + delta` at `pos` and `v` is of integral type.
|
||||
*/
|
||||
private predicate unequalIntegralSsa(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, SemReason reason
|
||||
) {
|
||||
exists(SemExpr e, int d1, int d2 |
|
||||
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
|
||||
boundedUpper(e, b, d1) and
|
||||
boundedLower(e, b, d2) and
|
||||
delta = d2 + d1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is an upper bound for `e`.
|
||||
*
|
||||
* This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate boundedUpper(SemExpr e, SemBound b, int delta) {
|
||||
bounded(e, b, delta, true, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a lower bound for `e`.
|
||||
*
|
||||
* This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate boundedLower(SemExpr e, SemBound b, int delta) {
|
||||
bounded(e, b, delta, false, _, _, _)
|
||||
}
|
||||
|
||||
/** Weakens a delta to lie in the range `[-1..1]`. */
|
||||
bindingset[delta, upper]
|
||||
private int weakenDelta(boolean upper, int delta) {
|
||||
delta in [-1 .. 1] and result = delta
|
||||
or
|
||||
upper = true and result = -1 and delta < -1
|
||||
or
|
||||
upper = false and result = 1 and delta > 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `inp` when used as an input to
|
||||
* `phi` along `edge`.
|
||||
* - `upper = true` : `inp <= b + delta`
|
||||
* - `upper = false` : `inp >= b + delta`
|
||||
*/
|
||||
private predicate boundedPhiInp(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, SemBound b, int delta,
|
||||
boolean upper, boolean fromBackEdge, int origdelta, SemReason reason
|
||||
) {
|
||||
edge.phiInput(phi, inp) and
|
||||
exists(int d, boolean fromBackEdge0 |
|
||||
boundedSsa(inp, edge, b, d, upper, fromBackEdge0, origdelta, reason)
|
||||
or
|
||||
boundedPhi(inp, b, d, upper, fromBackEdge0, origdelta, reason)
|
||||
or
|
||||
b.(SemSsaBound).getAVariable() = inp and
|
||||
d = 0 and
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge0 = false and
|
||||
origdelta = 0 and
|
||||
reason = TSemNoReason()
|
||||
|
|
||||
if semBackEdge(phi, inp, edge)
|
||||
then
|
||||
fromBackEdge = true and
|
||||
(
|
||||
fromBackEdge0 = true and delta = weakenDelta(upper, d - origdelta) + origdelta
|
||||
or
|
||||
fromBackEdge0 = false and delta = d
|
||||
)
|
||||
else (
|
||||
delta = d and fromBackEdge = fromBackEdge0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `inp` when used as an input to
|
||||
* `phi` along `edge`.
|
||||
* - `upper = true` : `inp <= b + delta`
|
||||
* - `upper = false` : `inp >= b + delta`
|
||||
*
|
||||
* Equivalent to `boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate boundedPhiInp1(
|
||||
SemSsaPhiNode phi, SemBound b, boolean upper, SemSsaVariable inp,
|
||||
SemSsaReadPositionPhiInputEdge edge, int delta
|
||||
) {
|
||||
boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `phi` is a valid bound for `inp` when used as an input to `phi`
|
||||
* along `edge`.
|
||||
* - `upper = true` : `inp <= phi`
|
||||
* - `upper = false` : `inp >= phi`
|
||||
*/
|
||||
private predicate selfBoundedPhiInp(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, boolean upper
|
||||
) {
|
||||
exists(int d, SemSsaBound phibound |
|
||||
phibound.getAVariable() = phi and
|
||||
boundedPhiInp(phi, inp, edge, phibound, d, upper, _, _, _) and
|
||||
(
|
||||
upper = true and d <= 0
|
||||
or
|
||||
upper = false and d >= 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for some input, `inp`, to `phi`, and
|
||||
* thus a candidate bound for `phi`.
|
||||
* - `upper = true` : `inp <= b + delta`
|
||||
* - `upper = false` : `inp >= b + delta`
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate boundedPhiCand(
|
||||
SemSsaPhiNode phi, boolean upper, SemBound b, int delta, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
boundedPhiInp(phi, _, _, b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the candidate bound `b + delta` for `phi` is valid for the phi input
|
||||
* `inp` along `edge`.
|
||||
*/
|
||||
private predicate boundedPhiCandValidForEdge(
|
||||
SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge
|
||||
) {
|
||||
boundedPhiCand(phi, upper, b, delta, fromBackEdge, origdelta, reason) and
|
||||
(
|
||||
exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = true and d <= delta)
|
||||
or
|
||||
exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = false and d >= delta)
|
||||
or
|
||||
selfBoundedPhiInp(phi, inp, edge, upper)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `phi`.
|
||||
* - `upper = true` : `phi <= b + delta`
|
||||
* - `upper = false` : `phi >= b + delta`
|
||||
*/
|
||||
private predicate boundedPhi(
|
||||
SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
forex(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge | edge.phiInput(phi, inp) |
|
||||
boundedPhiCandValidForEdge(phi, b, delta, upper, fromBackEdge, origdelta, reason, inp, edge)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` has an upper (for `upper = true`) or lower
|
||||
* (for `upper = false`) bound of `b`.
|
||||
*/
|
||||
private predicate baseBound(SemExpr e, int b, boolean upper) {
|
||||
Specific::hasConstantBound(e, b, upper)
|
||||
or
|
||||
upper = false and
|
||||
b = 0 and
|
||||
semPositive(e.(SemBitAndExpr).getAnOperand()) and
|
||||
// REVIEW: We let the language opt out here to preserve original results.
|
||||
not Specific::ignoreZeroLowerBound(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value being cast has an upper (for `upper = true`) or lower
|
||||
* (for `upper = false`) bound within the bounds of the resulting type.
|
||||
* For `upper = true` this means that the cast will not overflow and for
|
||||
* `upper = false` this means that the cast will not underflow.
|
||||
*/
|
||||
private predicate safeNarrowingCast(NarrowingCastExpr cast, boolean upper) {
|
||||
exists(int bound | bounded(cast.getOperand(), any(SemZeroBound zb), bound, upper, _, _, _) |
|
||||
upper = true and bound <= cast.getUpperBound()
|
||||
or
|
||||
upper = false and bound >= cast.getLowerBound()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate boundedCastExpr(
|
||||
NarrowingCastExpr cast, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `e`.
|
||||
* - `upper = true` : `e <= b + delta`
|
||||
* - `upper = false` : `e >= b + delta`
|
||||
*/
|
||||
private predicate bounded(
|
||||
SemExpr e, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
not Specific::ignoreExprBound(e) and
|
||||
(
|
||||
e = b.getExpr(delta) and
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TSemNoReason()
|
||||
or
|
||||
baseBound(e, delta, upper) and
|
||||
b instanceof SemZeroBound and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TSemNoReason()
|
||||
or
|
||||
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
||||
boundedSsa(v, bb, b, delta, upper, fromBackEdge, origdelta, reason) and
|
||||
e = v.getAUse() and
|
||||
bb.getBlock() = e.getBasicBlock()
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int d1, int d2 |
|
||||
boundFlowStep(e, mid, d1, upper) and
|
||||
// Constants have easy, base-case bounds, so let's not infer any recursive bounds.
|
||||
not e instanceof SemConstantIntegerExpr and
|
||||
bounded(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
|
||||
// upper = true: e <= mid + d1 <= b + d1 + d2 = b + delta
|
||||
// upper = false: e >= mid + d1 >= b + d1 + d2 = b + delta
|
||||
delta = d1 + d2
|
||||
)
|
||||
or
|
||||
exists(SemSsaPhiNode phi |
|
||||
boundedPhi(phi, b, delta, upper, fromBackEdge, origdelta, reason) and
|
||||
e = phi.getAUse()
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int factor, int d |
|
||||
boundFlowStepMul(e, mid, factor) and
|
||||
not e instanceof SemConstantIntegerExpr and
|
||||
bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
b instanceof SemZeroBound and
|
||||
delta = d * factor
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int factor, int d |
|
||||
boundFlowStepDiv(e, mid, factor) and
|
||||
not e instanceof SemConstantIntegerExpr and
|
||||
bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
b instanceof SemZeroBound and
|
||||
d >= 0 and
|
||||
delta = d / factor
|
||||
)
|
||||
or
|
||||
exists(NarrowingCastExpr cast |
|
||||
cast = e and
|
||||
safeNarrowingCast(cast, upper.booleanNot()) and
|
||||
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
SemConditionalExpr cond, int d1, int d2, boolean fbe1, boolean fbe2, int od1, int od2,
|
||||
SemReason r1, SemReason r2
|
||||
|
|
||||
cond = e and
|
||||
boundedConditionalExpr(cond, b, upper, true, d1, fbe1, od1, r1) and
|
||||
boundedConditionalExpr(cond, b, upper, false, d2, fbe2, od2, r2) and
|
||||
(
|
||||
delta = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
|
||||
or
|
||||
delta = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
|
||||
)
|
||||
|
|
||||
upper = true and delta = d1.maximum(d2)
|
||||
or
|
||||
upper = false and delta = d1.minimum(d2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate boundedConditionalExpr(
|
||||
SemConditionalExpr cond, SemBound b, boolean upper, boolean branch, int delta,
|
||||
boolean fromBackEdge, int origdelta, SemReason reason
|
||||
) {
|
||||
bounded(cond.getBranchExpr(branch), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
import CppRangeAnalysis
|
||||
|
|
|
@ -3,86 +3,90 @@
|
|||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import RangeAnalysisStage
|
||||
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadCopy(SemExpr e) { none() }
|
||||
module CppLangImpl implements LangSig<FloatDelta> {
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadCopy(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Ignore the bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreExprBound(SemExpr e) { none() }
|
||||
/**
|
||||
* Ignore the bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreExprBound(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Ignore any inferred zero lower bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreZeroLowerBound(SemExpr e) { none() }
|
||||
/**
|
||||
* Ignore any inferred zero lower bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreZeroLowerBound(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
|
||||
/**
|
||||
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
|
||||
|
||||
/**
|
||||
* Adds additional results to `ssaRead()` that are specific to Java.
|
||||
*
|
||||
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
|
||||
* in exactly the same way as the old Java implementation. Once the new implementation matches the
|
||||
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
|
||||
* or not they come from a post-increment/decrement expression.
|
||||
*/
|
||||
SemExpr specificSsaRead(SemSsaVariable v, int delta) { none() }
|
||||
/**
|
||||
* Adds additional results to `ssaRead()` that are specific to Java.
|
||||
*
|
||||
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
|
||||
* in exactly the same way as the old Java implementation. Once the new implementation matches the
|
||||
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
|
||||
* or not they come from a post-increment/decrement expression.
|
||||
*/
|
||||
SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||
*/
|
||||
predicate hasConstantBound(SemExpr e, int bound, boolean upper) { none() }
|
||||
/**
|
||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||
*/
|
||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||
*/
|
||||
predicate hasBound(SemExpr e, SemExpr bound, int delta, boolean upper) { none() }
|
||||
/**
|
||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||
*/
|
||||
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the value of `dest` is known to be `src + delta`.
|
||||
*/
|
||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() }
|
||||
/**
|
||||
* Holds if the value of `dest` is known to be `src + delta`.
|
||||
*/
|
||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
||||
* if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateType(SemExpr e) { none() }
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
||||
* if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateType(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified source
|
||||
* variable, if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified source
|
||||
* variable, if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -3,133 +3,138 @@
|
|||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import RangeAnalysisSpecific as Specific
|
||||
private import RangeAnalysisSpecific
|
||||
private import RangeAnalysisStage as Range
|
||||
private import ConstantAnalysis
|
||||
|
||||
/**
|
||||
* Gets an expression that equals `v - d`.
|
||||
*/
|
||||
SemExpr semSsaRead(SemSsaVariable v, int delta) {
|
||||
// There are various language-specific extension points that can be removed once we no longer
|
||||
// expect to match the original Java implementation's results exactly.
|
||||
result = v.getAUse() and delta = 0
|
||||
or
|
||||
exists(int d1, SemConstantIntegerExpr c |
|
||||
result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
|
||||
delta = d1 - c.getIntValue() and
|
||||
not Specific::ignoreSsaReadArithmeticExpr(result)
|
||||
)
|
||||
or
|
||||
exists(SemSubExpr sub, int d1, SemConstantIntegerExpr c |
|
||||
result = sub and
|
||||
sub.getLeftOperand() = semSsaRead(v, d1) and
|
||||
sub.getRightOperand() = c and
|
||||
delta = d1 + c.getIntValue() and
|
||||
not Specific::ignoreSsaReadArithmeticExpr(result)
|
||||
)
|
||||
or
|
||||
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
|
||||
delta = 0 and
|
||||
not Specific::ignoreSsaReadAssignment(v)
|
||||
or
|
||||
result = Specific::specificSsaRead(v, delta)
|
||||
or
|
||||
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta) and
|
||||
not Specific::ignoreSsaReadCopy(result)
|
||||
or
|
||||
result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a condition that tests whether `v` equals `e + delta`.
|
||||
*
|
||||
* If the condition evaluates to `testIsTrue`:
|
||||
* - `isEq = true` : `v == e + delta`
|
||||
* - `isEq = false` : `v != e + delta`
|
||||
*/
|
||||
SemGuard semEqFlowCond(SemSsaVariable v, SemExpr e, int delta, boolean isEq, boolean testIsTrue) {
|
||||
exists(boolean eqpolarity |
|
||||
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
|
||||
(testIsTrue = true or testIsTrue = false) and
|
||||
eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
|
||||
)
|
||||
or
|
||||
exists(boolean testIsTrue0 |
|
||||
semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
|
||||
*/
|
||||
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, int delta) {
|
||||
exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
|
||||
defExpr.(SemCopyValueExpr).getOperand() = e and delta = 0
|
||||
module RangeUtil<Range::DeltaSig D, Range::LangSig<D> Lang> implements Range::UtilSig<D> {
|
||||
/**
|
||||
* Gets an expression that equals `v - d`.
|
||||
*/
|
||||
SemExpr semSsaRead(SemSsaVariable v, D::Delta delta) {
|
||||
// There are various language-specific extension points that can be removed once we no longer
|
||||
// expect to match the original Java implementation's results exactly.
|
||||
result = v.getAUse() and delta = D::fromInt(0)
|
||||
or
|
||||
defExpr.(SemStoreExpr).getOperand() = e and delta = 0
|
||||
exists(D::Delta d1, SemConstantIntegerExpr c |
|
||||
result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
|
||||
delta = D::fromFloat(D::toFloat(d1) - c.getIntValue()) and
|
||||
not Lang::ignoreSsaReadArithmeticExpr(result)
|
||||
)
|
||||
or
|
||||
defExpr.(SemAddOneExpr).getOperand() = e and delta = 1
|
||||
exists(SemSubExpr sub, D::Delta d1, SemConstantIntegerExpr c |
|
||||
result = sub and
|
||||
sub.getLeftOperand() = semSsaRead(v, d1) and
|
||||
sub.getRightOperand() = c and
|
||||
delta = D::fromFloat(D::toFloat(d1) + c.getIntValue()) and
|
||||
not Lang::ignoreSsaReadArithmeticExpr(result)
|
||||
)
|
||||
or
|
||||
defExpr.(SemSubOneExpr).getOperand() = e and delta = -1
|
||||
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
|
||||
delta = D::fromFloat(0) and
|
||||
not Lang::ignoreSsaReadAssignment(v)
|
||||
or
|
||||
e = defExpr and
|
||||
not (
|
||||
defExpr instanceof SemCopyValueExpr or
|
||||
defExpr instanceof SemStoreExpr or
|
||||
defExpr instanceof SemAddOneExpr or
|
||||
defExpr instanceof SemSubOneExpr
|
||||
) and
|
||||
delta = 0
|
||||
)
|
||||
}
|
||||
result = Lang::specificSsaRead(v, delta)
|
||||
or
|
||||
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta) and
|
||||
not Lang::ignoreSsaReadCopy(result)
|
||||
or
|
||||
result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e1 + delta` equals `e2`.
|
||||
*/
|
||||
predicate semValueFlowStep(SemExpr e2, SemExpr e1, int delta) {
|
||||
e2.(SemCopyValueExpr).getOperand() = e1 and delta = 0
|
||||
or
|
||||
e2.(SemStoreExpr).getOperand() = e1 and delta = 0
|
||||
or
|
||||
e2.(SemAddOneExpr).getOperand() = e1 and delta = 1
|
||||
or
|
||||
e2.(SemSubOneExpr).getOperand() = e1 and delta = -1
|
||||
or
|
||||
Specific::additionalValueFlowStep(e2, e1, delta)
|
||||
or
|
||||
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
|
||||
x.(SemConstantIntegerExpr).getIntValue() = delta
|
||||
)
|
||||
or
|
||||
exists(SemExpr x, SemSubExpr sub |
|
||||
e2 = sub and
|
||||
sub.getLeftOperand() = e1 and
|
||||
sub.getRightOperand() = x
|
||||
|
|
||||
x.(SemConstantIntegerExpr).getIntValue() = -delta
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Gets a condition that tests whether `v` equals `e + delta`.
|
||||
*
|
||||
* If the condition evaluates to `testIsTrue`:
|
||||
* - `isEq = true` : `v == e + delta`
|
||||
* - `isEq = false` : `v != e + delta`
|
||||
*/
|
||||
SemGuard semEqFlowCond(
|
||||
SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue
|
||||
) {
|
||||
exists(boolean eqpolarity |
|
||||
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
|
||||
(testIsTrue = true or testIsTrue = false) and
|
||||
eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
|
||||
)
|
||||
or
|
||||
exists(boolean testIsTrue0 |
|
||||
semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type used to track the specified expression's range information.
|
||||
*
|
||||
* Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
|
||||
* primitive types as the underlying primitive type.
|
||||
*/
|
||||
SemType getTrackedType(SemExpr e) {
|
||||
result = Specific::getAlternateType(e)
|
||||
or
|
||||
not exists(Specific::getAlternateType(e)) and result = e.getSemType()
|
||||
}
|
||||
/**
|
||||
* Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
|
||||
*/
|
||||
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, D::Delta delta) {
|
||||
exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
|
||||
defExpr.(SemCopyValueExpr).getOperand() = e and delta = D::fromFloat(0)
|
||||
or
|
||||
defExpr.(SemStoreExpr).getOperand() = e and delta = D::fromFloat(0)
|
||||
or
|
||||
defExpr.(SemAddOneExpr).getOperand() = e and delta = D::fromFloat(1)
|
||||
or
|
||||
defExpr.(SemSubOneExpr).getOperand() = e and delta = D::fromFloat(-1)
|
||||
or
|
||||
e = defExpr and
|
||||
not (
|
||||
defExpr instanceof SemCopyValueExpr or
|
||||
defExpr instanceof SemStoreExpr or
|
||||
defExpr instanceof SemAddOneExpr or
|
||||
defExpr instanceof SemSubOneExpr
|
||||
) and
|
||||
delta = D::fromFloat(0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type used to track the specified source variable's range information.
|
||||
*
|
||||
* Usually, this just `e.getType()`, but the language can override this to track immutable boxed
|
||||
* primitive types as the underlying primitive type.
|
||||
*/
|
||||
SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
|
||||
result = Specific::getAlternateTypeForSsaVariable(var)
|
||||
or
|
||||
not exists(Specific::getAlternateTypeForSsaVariable(var)) and result = var.getType()
|
||||
/**
|
||||
* Holds if `e1 + delta` equals `e2`.
|
||||
*/
|
||||
predicate semValueFlowStep(SemExpr e2, SemExpr e1, D::Delta delta) {
|
||||
e2.(SemCopyValueExpr).getOperand() = e1 and delta = D::fromFloat(0)
|
||||
or
|
||||
e2.(SemStoreExpr).getOperand() = e1 and delta = D::fromFloat(0)
|
||||
or
|
||||
e2.(SemAddOneExpr).getOperand() = e1 and delta = D::fromFloat(1)
|
||||
or
|
||||
e2.(SemSubOneExpr).getOperand() = e1 and delta = D::fromFloat(-1)
|
||||
or
|
||||
Lang::additionalValueFlowStep(e2, e1, delta)
|
||||
or
|
||||
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
|
||||
D::fromInt(x.(SemConstantIntegerExpr).getIntValue()) = delta
|
||||
)
|
||||
or
|
||||
exists(SemExpr x, SemSubExpr sub |
|
||||
e2 = sub and
|
||||
sub.getLeftOperand() = e1 and
|
||||
sub.getRightOperand() = x
|
||||
|
|
||||
D::fromInt(-x.(SemConstantIntegerExpr).getIntValue()) = delta
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type used to track the specified expression's range information.
|
||||
*
|
||||
* Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
|
||||
* primitive types as the underlying primitive type.
|
||||
*/
|
||||
SemType getTrackedType(SemExpr e) {
|
||||
result = Lang::getAlternateType(e)
|
||||
or
|
||||
not exists(Lang::getAlternateType(e)) and result = e.getSemType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type used to track the specified source variable's range information.
|
||||
*
|
||||
* Usually, this just `e.getType()`, but the language can override this to track immutable boxed
|
||||
* primitive types as the underlying primitive type.
|
||||
*/
|
||||
SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
|
||||
result = Lang::getAlternateTypeForSsaVariable(var)
|
||||
or
|
||||
not exists(Lang::getAlternateTypeForSsaVariable(var)) and result = var.getType()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,488 +6,494 @@
|
|||
* three-valued domain `{negative, zero, positive}`.
|
||||
*/
|
||||
|
||||
private import RangeAnalysisStage
|
||||
private import SignAnalysisSpecific as Specific
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
private import RangeUtils
|
||||
private import Sign
|
||||
|
||||
/**
|
||||
* An SSA definition for which the analysis can compute the sign.
|
||||
*
|
||||
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
|
||||
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
|
||||
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
|
||||
* recursive.
|
||||
*/
|
||||
abstract private class SignDef instanceof SemSsaVariable {
|
||||
final string toString() { result = super.toString() }
|
||||
module SignAnalysis<DeltaSig D, UtilSig<D> Utils> {
|
||||
/**
|
||||
* An SSA definition for which the analysis can compute the sign.
|
||||
*
|
||||
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
|
||||
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
|
||||
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
|
||||
* recursive.
|
||||
*/
|
||||
abstract private class SignDef instanceof SemSsaVariable {
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/** Gets the possible signs of this SSA definition. */
|
||||
abstract Sign getSign();
|
||||
}
|
||||
|
||||
/** An SSA definition whose sign is computed based on standard flow. */
|
||||
abstract private class FlowSignDef extends SignDef {
|
||||
abstract override Sign getSign();
|
||||
}
|
||||
|
||||
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
||||
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
|
||||
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
|
||||
}
|
||||
|
||||
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
||||
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
|
||||
final override Sign getSign() {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
edge.phiInput(this, inp) and
|
||||
result = semSsaSign(inp, edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** An SSA definition whose sign is computed by a language-specific implementation. */
|
||||
abstract class CustomSignDef extends SignDef {
|
||||
abstract override Sign getSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression for which the analysis can compute the sign.
|
||||
*
|
||||
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
|
||||
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
|
||||
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
|
||||
* recursive.
|
||||
*
|
||||
* Concrete implementations extend one of the following subclasses:
|
||||
* - `ConstantSignExpr`, for expressions with a compile-time constant value.
|
||||
* - `FlowSignExpr`, for expressions whose sign can be computed from the signs of their operands.
|
||||
* - `CustomsignExpr`, for expressions whose sign can be computed by a language-specific
|
||||
* implementation.
|
||||
*
|
||||
* If the same expression matches more than one of the above subclasses, the sign is computed as
|
||||
* follows:
|
||||
* - The sign of a `ConstantSignExpr` is computed solely from `ConstantSignExpr.getSign()`,
|
||||
* regardless of any other subclasses.
|
||||
* - If a non-`ConstantSignExpr` expression matches exactly one of `FlowSignExpr` or
|
||||
* `CustomSignExpr`, the sign is computed by that class' `getSign()` predicate.
|
||||
* - If a non-`ConstantSignExpr` expression matches both `FlowSignExpr` and `CustomSignExpr`, the
|
||||
* sign is the _intersection_ of the signs of those two classes' `getSign()` predicates. Thus,
|
||||
* both classes have the opportunity to _restrict_ the set of possible signs, not to generate new
|
||||
* possible signs.
|
||||
* - If an expression does not match any of the three subclasses, then it can have any sign.
|
||||
*
|
||||
* Note that the `getSign()` predicate is introduced only in subclasses of `SignExpr`.
|
||||
*/
|
||||
abstract class SignExpr instanceof SemExpr {
|
||||
SignExpr() { not Specific::ignoreExprSign(this) }
|
||||
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
abstract Sign getSign();
|
||||
}
|
||||
|
||||
/** An expression whose sign is determined by its constant numeric value. */
|
||||
private class ConstantSignExpr extends SignExpr {
|
||||
ConstantSignExpr() {
|
||||
this instanceof SemConstantIntegerExpr or
|
||||
exists(this.(SemNumericLiteralExpr).getApproximateFloatValue())
|
||||
/** Gets the possible signs of this SSA definition. */
|
||||
abstract Sign getSign();
|
||||
}
|
||||
|
||||
final override Sign getSign() {
|
||||
exists(int i | this.(SemConstantIntegerExpr).getIntValue() = i |
|
||||
i < 0 and result = TNeg()
|
||||
/** An SSA definition whose sign is computed based on standard flow. */
|
||||
abstract private class FlowSignDef extends SignDef {
|
||||
abstract override Sign getSign();
|
||||
}
|
||||
|
||||
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
||||
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
|
||||
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
|
||||
}
|
||||
|
||||
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
||||
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
|
||||
final override Sign getSign() {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
edge.phiInput(this, inp) and
|
||||
result = semSsaSign(inp, edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** An SSA definition whose sign is computed by a language-specific implementation. */
|
||||
abstract class CustomSignDef extends SignDef {
|
||||
abstract override Sign getSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression for which the analysis can compute the sign.
|
||||
*
|
||||
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
|
||||
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
|
||||
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
|
||||
* recursive.
|
||||
*
|
||||
* Concrete implementations extend one of the following subclasses:
|
||||
* - `ConstantSignExpr`, for expressions with a compile-time constant value.
|
||||
* - `FlowSignExpr`, for expressions whose sign can be computed from the signs of their operands.
|
||||
* - `CustomsignExpr`, for expressions whose sign can be computed by a language-specific
|
||||
* implementation.
|
||||
*
|
||||
* If the same expression matches more than one of the above subclasses, the sign is computed as
|
||||
* follows:
|
||||
* - The sign of a `ConstantSignExpr` is computed solely from `ConstantSignExpr.getSign()`,
|
||||
* regardless of any other subclasses.
|
||||
* - If a non-`ConstantSignExpr` expression matches exactly one of `FlowSignExpr` or
|
||||
* `CustomSignExpr`, the sign is computed by that class' `getSign()` predicate.
|
||||
* - If a non-`ConstantSignExpr` expression matches both `FlowSignExpr` and `CustomSignExpr`, the
|
||||
* sign is the _intersection_ of the signs of those two classes' `getSign()` predicates. Thus,
|
||||
* both classes have the opportunity to _restrict_ the set of possible signs, not to generate new
|
||||
* possible signs.
|
||||
* - If an expression does not match any of the three subclasses, then it can have any sign.
|
||||
*
|
||||
* Note that the `getSign()` predicate is introduced only in subclasses of `SignExpr`.
|
||||
*/
|
||||
abstract class SignExpr instanceof SemExpr {
|
||||
SignExpr() { not Specific::ignoreExprSign(this) }
|
||||
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
abstract Sign getSign();
|
||||
}
|
||||
|
||||
/** An expression whose sign is determined by its constant numeric value. */
|
||||
private class ConstantSignExpr extends SignExpr {
|
||||
ConstantSignExpr() {
|
||||
this instanceof SemConstantIntegerExpr or
|
||||
exists(this.(SemNumericLiteralExpr).getApproximateFloatValue())
|
||||
}
|
||||
|
||||
final override Sign getSign() {
|
||||
exists(int i | this.(SemConstantIntegerExpr).getIntValue() = i |
|
||||
i < 0 and result = TNeg()
|
||||
or
|
||||
i = 0 and result = TZero()
|
||||
or
|
||||
i > 0 and result = TPos()
|
||||
)
|
||||
or
|
||||
i = 0 and result = TZero()
|
||||
or
|
||||
i > 0 and result = TPos()
|
||||
)
|
||||
or
|
||||
not exists(this.(SemConstantIntegerExpr).getIntValue()) and
|
||||
exists(float f | f = this.(SemNumericLiteralExpr).getApproximateFloatValue() |
|
||||
f < 0 and result = TNeg()
|
||||
or
|
||||
f = 0 and result = TZero()
|
||||
or
|
||||
f > 0 and result = TPos()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class NonConstantSignExpr extends SignExpr {
|
||||
NonConstantSignExpr() { not this instanceof ConstantSignExpr }
|
||||
|
||||
final override Sign getSign() {
|
||||
// The result is the _intersection_ of the signs computed from flow and by the language.
|
||||
(result = this.(FlowSignExpr).getSignRestriction() or not this instanceof FlowSignExpr) and
|
||||
(result = this.(CustomSignExpr).getSignRestriction() or not this instanceof CustomSignExpr)
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression whose sign is computed from the signs of its operands. */
|
||||
abstract private class FlowSignExpr extends NonConstantSignExpr {
|
||||
abstract Sign getSignRestriction();
|
||||
}
|
||||
|
||||
/** An expression whose sign is computed by a language-specific implementation. */
|
||||
abstract class CustomSignExpr extends NonConstantSignExpr {
|
||||
abstract Sign getSignRestriction();
|
||||
}
|
||||
|
||||
/** An expression whose sign is unknown. */
|
||||
private class UnknownSignExpr extends SignExpr {
|
||||
UnknownSignExpr() {
|
||||
not this instanceof FlowSignExpr and
|
||||
not this instanceof CustomSignExpr and
|
||||
not this instanceof ConstantSignExpr and
|
||||
(
|
||||
// Only track numeric types.
|
||||
getTrackedType(this) instanceof SemNumericType
|
||||
or
|
||||
// Unless the language says to track this expression anyway.
|
||||
Specific::trackUnknownNonNumericExpr(this)
|
||||
)
|
||||
not exists(this.(SemConstantIntegerExpr).getIntValue()) and
|
||||
exists(float f | f = this.(SemNumericLiteralExpr).getApproximateFloatValue() |
|
||||
f < 0 and result = TNeg()
|
||||
or
|
||||
f = 0 and result = TZero()
|
||||
or
|
||||
f > 0 and result = TPos()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
final override Sign getSign() { semAnySign(result) }
|
||||
}
|
||||
abstract private class NonConstantSignExpr extends SignExpr {
|
||||
NonConstantSignExpr() { not this instanceof ConstantSignExpr }
|
||||
|
||||
/**
|
||||
* A `Load` expression whose sign is computed from the sign of its SSA definition, restricted by
|
||||
* inference from any intervening guards.
|
||||
*/
|
||||
class UseSignExpr extends FlowSignExpr {
|
||||
SemSsaVariable v;
|
||||
|
||||
UseSignExpr() { v.getAUse() = this }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
// Propagate via SSA
|
||||
// Propagate the sign from the def of `v`, incorporating any inference from guards.
|
||||
result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
|
||||
or
|
||||
// No block for this read. Just use the sign of the def.
|
||||
// REVIEW: How can this happen?
|
||||
not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
|
||||
result = semSsaDefSign(v)
|
||||
final override Sign getSign() {
|
||||
// The result is the _intersection_ of the signs computed from flow and by the language.
|
||||
(result = this.(FlowSignExpr).getSignRestriction() or not this instanceof FlowSignExpr) and
|
||||
(result = this.(CustomSignExpr).getSignRestriction() or not this instanceof CustomSignExpr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A binary expression whose sign is computed from the signs of its operands. */
|
||||
private class BinarySignExpr extends FlowSignExpr {
|
||||
SemBinaryExpr binary;
|
||||
/** An expression whose sign is computed from the signs of its operands. */
|
||||
abstract private class FlowSignExpr extends NonConstantSignExpr {
|
||||
abstract Sign getSignRestriction();
|
||||
}
|
||||
|
||||
BinarySignExpr() { binary = this }
|
||||
/** An expression whose sign is computed by a language-specific implementation. */
|
||||
abstract class CustomSignExpr extends NonConstantSignExpr {
|
||||
abstract Sign getSignRestriction();
|
||||
}
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
exists(SemExpr left, SemExpr right |
|
||||
binaryExprOperands(binary, left, right) and
|
||||
/** An expression whose sign is unknown. */
|
||||
private class UnknownSignExpr extends SignExpr {
|
||||
UnknownSignExpr() {
|
||||
not this instanceof FlowSignExpr and
|
||||
not this instanceof CustomSignExpr and
|
||||
not this instanceof ConstantSignExpr and
|
||||
(
|
||||
// Only track numeric types.
|
||||
Utils::getTrackedType(this) instanceof SemNumericType
|
||||
or
|
||||
// Unless the language says to track this expression anyway.
|
||||
Specific::trackUnknownNonNumericExpr(this)
|
||||
)
|
||||
}
|
||||
|
||||
final override Sign getSign() { semAnySign(result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Load` expression whose sign is computed from the sign of its SSA definition, restricted by
|
||||
* inference from any intervening guards.
|
||||
*/
|
||||
class UseSignExpr extends FlowSignExpr {
|
||||
SemSsaVariable v;
|
||||
|
||||
UseSignExpr() { v.getAUse() = this }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
// Propagate via SSA
|
||||
// Propagate the sign from the def of `v`, incorporating any inference from guards.
|
||||
result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
|
||||
or
|
||||
// No block for this read. Just use the sign of the def.
|
||||
// REVIEW: How can this happen?
|
||||
not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
|
||||
result = semSsaDefSign(v)
|
||||
}
|
||||
}
|
||||
|
||||
/** A binary expression whose sign is computed from the signs of its operands. */
|
||||
private class BinarySignExpr extends FlowSignExpr {
|
||||
SemBinaryExpr binary;
|
||||
|
||||
BinarySignExpr() { binary = this }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
exists(SemExpr left, SemExpr right |
|
||||
binaryExprOperands(binary, left, right) and
|
||||
result =
|
||||
semExprSign(pragma[only_bind_out](left))
|
||||
.applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
|
||||
)
|
||||
or
|
||||
exists(SemDivExpr div | div = binary |
|
||||
result = semExprSign(div.getLeftOperand()) and
|
||||
result != TZero() and
|
||||
div.getRightOperand().(SemFloatingPointLiteralExpr).getFloatValue() = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
|
||||
binary.getLeftOperand() = left and binary.getRightOperand() = right
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert`, `Box`, or `Unbox` expression.
|
||||
*/
|
||||
private class SemCastExpr instanceof SemUnaryExpr {
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
SemCastExpr() {
|
||||
this instanceof SemConvertExpr
|
||||
or
|
||||
this instanceof SemBoxExpr
|
||||
or
|
||||
this instanceof SemUnboxExpr
|
||||
}
|
||||
}
|
||||
|
||||
/** A unary expression whose sign is computed from the sign of its operand. */
|
||||
private class UnarySignExpr extends FlowSignExpr {
|
||||
SemUnaryExpr unary;
|
||||
|
||||
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result =
|
||||
semExprSign(pragma[only_bind_out](left))
|
||||
.applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
|
||||
)
|
||||
or
|
||||
exists(SemDivExpr div | div = binary |
|
||||
result = semExprSign(div.getLeftOperand()) and
|
||||
result != TZero() and
|
||||
div.getRightOperand().(SemFloatingPointLiteralExpr).getFloatValue() = 0
|
||||
semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert`, `Box`, or `Unbox` expression, whose sign is computed based on
|
||||
* the sign of its operand and the source and destination types.
|
||||
*/
|
||||
abstract private class CastSignExpr extends FlowSignExpr {
|
||||
SemUnaryExpr cast;
|
||||
|
||||
CastSignExpr() { cast = this and cast instanceof SemCastExpr }
|
||||
|
||||
override Sign getSignRestriction() { result = semExprSign(cast.getOperand()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert` expression.
|
||||
*/
|
||||
private class ConvertSignExpr extends CastSignExpr {
|
||||
override SemConvertExpr cast;
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Box` expression.
|
||||
*/
|
||||
private class BoxSignExpr extends CastSignExpr {
|
||||
override SemBoxExpr cast;
|
||||
}
|
||||
|
||||
/**
|
||||
* An `Unbox` expression.
|
||||
*/
|
||||
private class UnboxSignExpr extends CastSignExpr {
|
||||
override SemUnboxExpr cast;
|
||||
|
||||
UnboxSignExpr() {
|
||||
exists(SemType fromType | fromType = Utils::getTrackedType(cast.getOperand()) |
|
||||
// Only numeric source types are handled here.
|
||||
fromType instanceof SemNumericType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate unknownSign(SemExpr e) { e instanceof UnknownSignExpr }
|
||||
|
||||
/**
|
||||
* Holds if `lowerbound` is a lower bound for `v` at `pos`. This is restricted
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate lowerBound(
|
||||
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(lowerbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
comp.getLesserOperand() = lowerbound and
|
||||
comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||
or
|
||||
testIsTrue = false and
|
||||
comp.getGreaterOperand() = lowerbound and
|
||||
comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
|
||||
binary.getLeftOperand() = left and binary.getRightOperand() = right
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert`, `Box`, or `Unbox` expression.
|
||||
*/
|
||||
private class SemCastExpr extends SemUnaryExpr {
|
||||
SemCastExpr() {
|
||||
this instanceof SemConvertExpr
|
||||
or
|
||||
this instanceof SemBoxExpr
|
||||
or
|
||||
this instanceof SemUnboxExpr
|
||||
}
|
||||
}
|
||||
|
||||
/** A unary expression whose sign is computed from the sign of its operand. */
|
||||
private class UnarySignExpr extends FlowSignExpr {
|
||||
SemUnaryExpr unary;
|
||||
|
||||
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result = semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert`, `Box`, or `Unbox` expression, whose sign is computed based on
|
||||
* the sign of its operand and the source and destination types.
|
||||
*/
|
||||
abstract private class CastSignExpr extends FlowSignExpr {
|
||||
SemUnaryExpr cast;
|
||||
|
||||
CastSignExpr() { cast = this and cast instanceof SemCastExpr }
|
||||
|
||||
override Sign getSignRestriction() { result = semExprSign(cast.getOperand()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert` expression.
|
||||
*/
|
||||
private class ConvertSignExpr extends CastSignExpr {
|
||||
override SemConvertExpr cast;
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Box` expression.
|
||||
*/
|
||||
private class BoxSignExpr extends CastSignExpr {
|
||||
override SemBoxExpr cast;
|
||||
}
|
||||
|
||||
/**
|
||||
* An `Unbox` expression.
|
||||
*/
|
||||
private class UnboxSignExpr extends CastSignExpr {
|
||||
override SemUnboxExpr cast;
|
||||
|
||||
UnboxSignExpr() {
|
||||
exists(SemType fromType | fromType = getTrackedType(cast.getOperand()) |
|
||||
// Only numeric source types are handled here.
|
||||
fromType instanceof SemNumericType
|
||||
/**
|
||||
* Holds if `upperbound` is an upper bound for `v` at `pos`. This is restricted
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate upperBound(
|
||||
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(upperbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
comp.getGreaterOperand() = upperbound and
|
||||
comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||
or
|
||||
testIsTrue = false and
|
||||
comp.getLesserOperand() = upperbound and
|
||||
comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate unknownSign(SemExpr e) { e instanceof UnknownSignExpr }
|
||||
/**
|
||||
* Holds if `eqbound` is an equality/inequality for `v` at `pos`. This is
|
||||
* restricted to only include bounds for which we might determine a sign. The
|
||||
* boolean `isEq` gives the polarity:
|
||||
* - `isEq = true` : `v = eqbound`
|
||||
* - `isEq = false` : `v != eqbound`
|
||||
*/
|
||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
|
||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(guard, pos, testIsTrue) and
|
||||
guard.isEquality(eqbound, Utils::semSsaRead(v, D::fromInt(0)), polarity) and
|
||||
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
||||
not unknownSign(eqbound)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `lowerbound` is a lower bound for `v` at `pos`. This is restricted
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate lowerBound(
|
||||
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(lowerbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
comp.getLesserOperand() = lowerbound and
|
||||
comp.getGreaterOperand() = semSsaRead(v, 0) and
|
||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||
/**
|
||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
|
||||
* order for `v` to be positive.
|
||||
*/
|
||||
private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
upperBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
|
||||
* order for `v` to be negative.
|
||||
*/
|
||||
private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
|
||||
* can be zero.
|
||||
*/
|
||||
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) or
|
||||
upperBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, _)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be positive at `pos`. */
|
||||
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
posBound(bound, v, pos) and TPos() = semExprSign(bound)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be negative at `pos`. */
|
||||
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be zero at `pos`. */
|
||||
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
|
||||
or
|
||||
testIsTrue = false and
|
||||
comp.getGreaterOperand() = lowerbound and
|
||||
comp.getLesserOperand() = semSsaRead(v, 0) and
|
||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `upperbound` is an upper bound for `v` at `pos`. This is restricted
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate upperBound(
|
||||
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(upperbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
comp.getGreaterOperand() = upperbound and
|
||||
comp.getLesserOperand() = semSsaRead(v, 0) and
|
||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||
or
|
||||
testIsTrue = false and
|
||||
comp.getLesserOperand() = upperbound and
|
||||
comp.getGreaterOperand() = semSsaRead(v, 0) and
|
||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||
)
|
||||
}
|
||||
upperBound(bound, v, pos, _) and TPos() = semExprSign(bound)
|
||||
or
|
||||
upperBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||
or
|
||||
eqBound(bound, v, pos, true) and TZero() = semExprSign(bound)
|
||||
or
|
||||
eqBound(bound, v, pos, false) and TZero() != semExprSign(bound)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `eqbound` is an equality/inequality for `v` at `pos`. This is
|
||||
* restricted to only include bounds for which we might determine a sign. The
|
||||
* boolean `isEq` gives the polarity:
|
||||
* - `isEq = true` : `v = eqbound`
|
||||
* - `isEq = false` : `v != eqbound`
|
||||
*/
|
||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
|
||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity |
|
||||
/**
|
||||
* Holds if there is a bound that might restrict whether `v` has the sign `s`
|
||||
* at `pos`.
|
||||
*/
|
||||
private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
|
||||
s = TPos() and posBound(_, v, pos)
|
||||
or
|
||||
s = TNeg() and negBound(_, v, pos)
|
||||
or
|
||||
s = TZero() and zeroBound(_, v, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at `pos` based on its definition, where the sign
|
||||
* might be ruled out by a guard.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(guard, pos, testIsTrue) and
|
||||
guard.isEquality(eqbound, semSsaRead(v, 0), polarity) and
|
||||
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
||||
not unknownSign(eqbound)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
|
||||
* order for `v` to be positive.
|
||||
*/
|
||||
private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
upperBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
|
||||
* order for `v` to be negative.
|
||||
*/
|
||||
private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
|
||||
* can be zero.
|
||||
*/
|
||||
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) or
|
||||
upperBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, _)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be positive at `pos`. */
|
||||
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
posBound(bound, v, pos) and TPos() = semExprSign(bound)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be negative at `pos`. */
|
||||
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be zero at `pos`. */
|
||||
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
|
||||
or
|
||||
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||
or
|
||||
upperBound(bound, v, pos, _) and TPos() = semExprSign(bound)
|
||||
or
|
||||
upperBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||
or
|
||||
eqBound(bound, v, pos, true) and TZero() = semExprSign(bound)
|
||||
or
|
||||
eqBound(bound, v, pos, false) and TZero() != semExprSign(bound)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a bound that might restrict whether `v` has the sign `s`
|
||||
* at `pos`.
|
||||
*/
|
||||
private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
|
||||
s = TPos() and posBound(_, v, pos)
|
||||
or
|
||||
s = TNeg() and negBound(_, v, pos)
|
||||
or
|
||||
s = TZero() and zeroBound(_, v, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at `pos` based on its definition, where the sign
|
||||
* might be ruled out by a guard.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
hasGuard(v, pos, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at `pos` based on its definition, where no guard
|
||||
* can rule it out.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
not hasGuard(v, pos, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at read position `pos`, where a guard could have
|
||||
* ruled out the sign but does not.
|
||||
* This does not check that the definition of `v` also allows the sign.
|
||||
*/
|
||||
private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = TPos() and
|
||||
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
|
||||
or
|
||||
result = TNeg() and
|
||||
forex(SemExpr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos))
|
||||
or
|
||||
result = TZero() and
|
||||
forex(SemExpr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos))
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `v` at `pos`. */
|
||||
private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = unguardedSsaSign(v, pos)
|
||||
or
|
||||
result = guardedSsaSign(v, pos) and
|
||||
result = guardedSsaSignOk(v, pos)
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `v`. */
|
||||
pragma[nomagic]
|
||||
Sign semSsaDefSign(SemSsaVariable v) { result = v.(SignDef).getSign() }
|
||||
|
||||
/** Gets a possible sign for `e`. */
|
||||
cached
|
||||
Sign semExprSign(SemExpr e) {
|
||||
exists(Sign s | s = e.(SignExpr).getSign() |
|
||||
if
|
||||
getTrackedType(e) instanceof SemUnsignedIntegerType and
|
||||
s = TNeg() and
|
||||
not Specific::ignoreTypeRestrictions(e)
|
||||
then result = TPos()
|
||||
else result = s
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy predicate that holds for any sign. This is added to improve readability
|
||||
* of cases where the sign is unrestricted.
|
||||
*/
|
||||
predicate semAnySign(Sign s) { any() }
|
||||
|
||||
/** Holds if `e` can be positive and cannot be negative. */
|
||||
predicate semPositive(SemExpr e) {
|
||||
semExprSign(e) = TPos() and
|
||||
not semExprSign(e) = TNeg()
|
||||
}
|
||||
|
||||
/** Holds if `e` can be negative and cannot be positive. */
|
||||
predicate semNegative(SemExpr e) {
|
||||
semExprSign(e) = TNeg() and
|
||||
not semExprSign(e) = TPos()
|
||||
}
|
||||
|
||||
/** Holds if `e` is strictly positive. */
|
||||
predicate semStrictlyPositive(SemExpr e) {
|
||||
semExprSign(e) = TPos() and
|
||||
not semExprSign(e) = TNeg() and
|
||||
not semExprSign(e) = TZero()
|
||||
}
|
||||
|
||||
/** Holds if `e` is strictly negative. */
|
||||
predicate semStrictlyNegative(SemExpr e) {
|
||||
semExprSign(e) = TNeg() and
|
||||
not semExprSign(e) = TPos() and
|
||||
not semExprSign(e) = TZero()
|
||||
hasGuard(v, pos, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at `pos` based on its definition, where no guard
|
||||
* can rule it out.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
not hasGuard(v, pos, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at read position `pos`, where a guard could have
|
||||
* ruled out the sign but does not.
|
||||
* This does not check that the definition of `v` also allows the sign.
|
||||
*/
|
||||
private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = TPos() and
|
||||
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
|
||||
or
|
||||
result = TNeg() and
|
||||
forex(SemExpr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos))
|
||||
or
|
||||
result = TZero() and
|
||||
forex(SemExpr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos))
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `v` at `pos`. */
|
||||
private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = unguardedSsaSign(v, pos)
|
||||
or
|
||||
result = guardedSsaSign(v, pos) and
|
||||
result = guardedSsaSignOk(v, pos)
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `v`. */
|
||||
pragma[nomagic]
|
||||
Sign semSsaDefSign(SemSsaVariable v) { result = v.(SignDef).getSign() }
|
||||
|
||||
/** Gets a possible sign for `e`. */
|
||||
cached
|
||||
Sign semExprSign(SemExpr e) {
|
||||
exists(Sign s | s = e.(SignExpr).getSign() |
|
||||
if
|
||||
Utils::getTrackedType(e) instanceof SemUnsignedIntegerType and
|
||||
s = TNeg() and
|
||||
not Specific::ignoreTypeRestrictions(e)
|
||||
then result = TPos()
|
||||
else result = s
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy predicate that holds for any sign. This is added to improve readability
|
||||
* of cases where the sign is unrestricted.
|
||||
*/
|
||||
predicate semAnySign(Sign s) { any() }
|
||||
|
||||
/** Holds if `e` can be positive and cannot be negative. */
|
||||
predicate semPositive(SemExpr e) {
|
||||
semExprSign(e) = TPos() and
|
||||
not semExprSign(e) = TNeg()
|
||||
}
|
||||
|
||||
/** Holds if `e` can be negative and cannot be positive. */
|
||||
predicate semNegative(SemExpr e) {
|
||||
semExprSign(e) = TNeg() and
|
||||
not semExprSign(e) = TPos()
|
||||
}
|
||||
|
||||
/** Holds if `e` is strictly positive. */
|
||||
predicate semStrictlyPositive(SemExpr e) {
|
||||
semExprSign(e) = TPos() and
|
||||
not semExprSign(e) = TNeg() and
|
||||
not semExprSign(e) = TZero()
|
||||
}
|
||||
|
||||
/** Holds if `e` is strictly negative. */
|
||||
predicate semStrictlyNegative(SemExpr e) {
|
||||
semExprSign(e) = TNeg() and
|
||||
not semExprSign(e) = TPos() and
|
||||
not semExprSign(e) = TZero()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: codeql/cpp-all
|
||||
version: 0.5.1-dev
|
||||
version: 0.5.2-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
|
|
@ -45,6 +45,16 @@ module Consistency {
|
|||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */
|
||||
predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */
|
||||
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
|
@ -246,6 +256,7 @@ module Consistency {
|
|||
query predicate uniqueParameterNodeAtPosition(
|
||||
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||
) {
|
||||
not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and
|
||||
isParameterNode(p, c, pos) and
|
||||
not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and
|
||||
msg = "Parameters with overlapping positions."
|
||||
|
@ -254,6 +265,7 @@ module Consistency {
|
|||
query predicate uniqueParameterNodePosition(
|
||||
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||
) {
|
||||
not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and
|
||||
isParameterNode(p, c, pos) and
|
||||
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
||||
msg = "Parameter node with multiple positions."
|
||||
|
|
|
@ -45,6 +45,16 @@ module Consistency {
|
|||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */
|
||||
predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */
|
||||
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
|
@ -246,6 +256,7 @@ module Consistency {
|
|||
query predicate uniqueParameterNodeAtPosition(
|
||||
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||
) {
|
||||
not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and
|
||||
isParameterNode(p, c, pos) and
|
||||
not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and
|
||||
msg = "Parameters with overlapping positions."
|
||||
|
@ -254,6 +265,7 @@ module Consistency {
|
|||
query predicate uniqueParameterNodePosition(
|
||||
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||
) {
|
||||
not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and
|
||||
isParameterNode(p, c, pos) and
|
||||
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
||||
msg = "Parameter node with multiple positions."
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
## 0.5.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/no-space-for-terminator` and `cpp/uncontrolled-allocation-size` queries have been enhanced with heuristic detection of allocations. These queries now find more results.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
|
|
@ -15,76 +15,24 @@
|
|||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
||||
import TaintedWithPath
|
||||
|
||||
string getATopLevelDomain() {
|
||||
result =
|
||||
[
|
||||
"com", "ru", "net", "org", "de", "jp", "uk", "br", "pl", "in", "it", "fr", "au", "info", "nl",
|
||||
"cn", "ir", "es", "cz", "biz", "ca", "eu", "ua", "kr", "za", "co", "gr", "ro", "se", "tw",
|
||||
"vn", "mx", "ch", "tr", "at", "be", "hu", "tv", "dk", "me", "ar", "us", "no", "sk", "fi",
|
||||
"id", "cl", "nz", "by", "xyz", "pt", "ie", "il", "kz", "my", "hk", "lt", "cc", "sg", "io",
|
||||
"edu", "gov"
|
||||
]
|
||||
}
|
||||
|
||||
predicate hardCodedAddressOrIP(StringLiteral txt) {
|
||||
exists(string s | s = txt.getValueText() |
|
||||
// Hard-coded ip addresses, such as 127.0.0.1
|
||||
s.regexpMatch("\"[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+\"") or
|
||||
// Hard-coded addresses such as www.mycompany.com
|
||||
s.matches("\"www.%\"") or
|
||||
s.matches("\"http:%\"") or
|
||||
s.matches("\"https:%\"") or
|
||||
s.matches("\"%.com\"") or
|
||||
s.matches("\"%.ru\"") or
|
||||
s.matches("\"%.net\"") or
|
||||
s.matches("\"%.org\"") or
|
||||
s.matches("\"%.de\"") or
|
||||
s.matches("\"%.jp\"") or
|
||||
s.matches("\"%.uk\"") or
|
||||
s.matches("\"%.br\"") or
|
||||
s.matches("\"%.pl\"") or
|
||||
s.matches("\"%.in\"") or
|
||||
s.matches("\"%.it\"") or
|
||||
s.matches("\"%.fr\"") or
|
||||
s.matches("\"%.au\"") or
|
||||
s.matches("\"%.info\"") or
|
||||
s.matches("\"%.nl\"") or
|
||||
s.matches("\"%.cn\"") or
|
||||
s.matches("\"%.ir\"") or
|
||||
s.matches("\"%.es\"") or
|
||||
s.matches("\"%.cz\"") or
|
||||
s.matches("\"%.biz\"") or
|
||||
s.matches("\"%.ca\"") or
|
||||
s.matches("\"%.eu\"") or
|
||||
s.matches("\"%.ua\"") or
|
||||
s.matches("\"%.kr\"") or
|
||||
s.matches("\"%.za\"") or
|
||||
s.matches("\"%.co\"") or
|
||||
s.matches("\"%.gr\"") or
|
||||
s.matches("\"%.ro\"") or
|
||||
s.matches("\"%.se\"") or
|
||||
s.matches("\"%.tw\"") or
|
||||
s.matches("\"%.vn\"") or
|
||||
s.matches("\"%.mx\"") or
|
||||
s.matches("\"%.ch\"") or
|
||||
s.matches("\"%.tr\"") or
|
||||
s.matches("\"%.at\"") or
|
||||
s.matches("\"%.be\"") or
|
||||
s.matches("\"%.hu\"") or
|
||||
s.matches("\"%.tv\"") or
|
||||
s.matches("\"%.dk\"") or
|
||||
s.matches("\"%.me\"") or
|
||||
s.matches("\"%.ar\"") or
|
||||
s.matches("\"%.us\"") or
|
||||
s.matches("\"%.no\"") or
|
||||
s.matches("\"%.sk\"") or
|
||||
s.matches("\"%.fi\"") or
|
||||
s.matches("\"%.id\"") or
|
||||
s.matches("\"%.cl\"") or
|
||||
s.matches("\"%.nz\"") or
|
||||
s.matches("\"%.by\"") or
|
||||
s.matches("\"%.xyz\"") or
|
||||
s.matches("\"%.pt\"") or
|
||||
s.matches("\"%.ie\"") or
|
||||
s.matches("\"%.il\"") or
|
||||
s.matches("\"%.kz\"") or
|
||||
s.matches("\"%.my\"") or
|
||||
s.matches("\"%.hk\"") or
|
||||
s.matches("\"%.lt\"") or
|
||||
s.matches("\"%.cc\"") or
|
||||
s.matches("\"%.sg\"") or
|
||||
s.matches("\"%.io\"") or
|
||||
s.matches("\"%.edu\"") or
|
||||
s.matches("\"%.gov\"")
|
||||
s.regexpMatch("\"(www\\.|http:|https:).*\"") or
|
||||
s.regexpMatch("\".*\\.(" + strictconcat(getATopLevelDomain(), "|") + ")\"")
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.5.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/no-space-for-terminator` and `cpp/uncontrolled-allocation-size` queries have been enhanced with heuristic detection of allocations. These queries now find more results.
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
lastReleaseVersion: 0.5.0
|
||||
lastReleaseVersion: 0.5.1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: codeql/cpp-queries
|
||||
version: 0.5.1-dev
|
||||
version: 0.5.2-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
|
|
@ -207,34 +207,35 @@ bad_asts.cpp:
|
|||
# 27| Type = [SpecifiedType] const Point
|
||||
# 27| ValueCategory = lvalue
|
||||
# 28| getStmt(1): [ReturnStmt] return ...
|
||||
# 30| [TopLevelFunction] void Bad::errorExpr()
|
||||
# 30| <params>:
|
||||
# 30| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 31| getStmt(0): [DeclStmt] declaration
|
||||
# 31| getDeclarationEntry(0): [VariableDeclarationEntry] definition of intref
|
||||
# 31| Type = [LValueReferenceType] int &
|
||||
# 31| getVariable().getInitializer(): [Initializer] initializer for intref
|
||||
# 31| getExpr(): [ErrorExpr] <error expr>
|
||||
# 31| Type = [ErroneousType] error
|
||||
# 31| ValueCategory = prvalue
|
||||
# 32| getStmt(1): [DeclStmt] declaration
|
||||
# 32| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
|
||||
# 32| Type = [IntType] int
|
||||
# 32| getVariable().getInitializer(): [Initializer] initializer for x
|
||||
# 32| getExpr(): [ErrorExpr] <error expr>
|
||||
# 32| Type = [ErroneousType] error
|
||||
# 32| ValueCategory = prvalue
|
||||
# 33| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 33| getExpr(): [AssignExpr] ... = ...
|
||||
# 33| Type = [IntType] int
|
||||
# 33| ValueCategory = lvalue
|
||||
# 33| getLValue(): [VariableAccess] x
|
||||
# 33| Type = [IntType] int
|
||||
# 33| ValueCategory = lvalue
|
||||
# 33| getRValue(): [ErrorExpr] <error expr>
|
||||
# 33| Type = [ErroneousType] error
|
||||
# 33| ValueCategory = prvalue(load)
|
||||
# 34| getStmt(3): [ReturnStmt] return ...
|
||||
bad_stmts.cpp:
|
||||
# 5| [TopLevelFunction] void Bad::errorExpr()
|
||||
# 5| <params>:
|
||||
# 5| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 6| getStmt(0): [DeclStmt] declaration
|
||||
# 6| getDeclarationEntry(0): [VariableDeclarationEntry] definition of intref
|
||||
# 6| Type = [LValueReferenceType] int &
|
||||
# 6| getVariable().getInitializer(): [Initializer] initializer for intref
|
||||
# 6| getExpr(): [ErrorExpr] <error expr>
|
||||
# 6| Type = [ErroneousType] error
|
||||
# 6| ValueCategory = prvalue
|
||||
# 7| getStmt(1): [DeclStmt] declaration
|
||||
# 7| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
|
||||
# 7| Type = [IntType] int
|
||||
# 7| getVariable().getInitializer(): [Initializer] initializer for x
|
||||
# 7| getExpr(): [ErrorExpr] <error expr>
|
||||
# 7| Type = [ErroneousType] error
|
||||
# 7| ValueCategory = prvalue
|
||||
# 8| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 8| getExpr(): [AssignExpr] ... = ...
|
||||
# 8| Type = [IntType] int
|
||||
# 8| ValueCategory = lvalue
|
||||
# 8| getLValue(): [VariableAccess] x
|
||||
# 8| Type = [IntType] int
|
||||
# 8| ValueCategory = lvalue
|
||||
# 8| getRValue(): [ErrorExpr] <error expr>
|
||||
# 8| Type = [ErroneousType] error
|
||||
# 8| ValueCategory = prvalue(load)
|
||||
# 9| getStmt(3): [ReturnStmt] return ...
|
||||
clang.cpp:
|
||||
# 5| [TopLevelFunction] int* globalIntAddress()
|
||||
# 5| <params>:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// semmle-extractor-options: -std=c++17 --expect_errors
|
||||
// semmle-extractor-options: -std=c++17
|
||||
|
||||
// Test cases that illustrate known bad ASTs that we have to work around in IR generation.
|
||||
namespace Bad {
|
||||
|
@ -26,10 +26,4 @@ namespace Bad {
|
|||
void CallCopyConstructor(const Point& a) {
|
||||
Point b = a; // Copy constructor contains literal expressions with no values.
|
||||
}
|
||||
|
||||
void errorExpr() {
|
||||
int &intref = 0;
|
||||
int x = 0[0];
|
||||
x = 1[1];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// semmle-extractor-options: -std=c++17 --expect_errors
|
||||
|
||||
// Test cases that illustrate known bad ASTs that we have to work around in IR generation.
|
||||
namespace Bad {
|
||||
void errorExpr() {
|
||||
int &intref = 0;
|
||||
int x = 0[0];
|
||||
x = 1[1];
|
||||
}
|
||||
}
|
|
@ -98,17 +98,17 @@
|
|||
| bad_asts.cpp:27:15:27:15 | StoreValue | r27_6 |
|
||||
| bad_asts.cpp:27:15:27:15 | Unary | r27_3 |
|
||||
| bad_asts.cpp:27:15:27:15 | Unary | r27_4 |
|
||||
| bad_asts.cpp:30:8:30:16 | ChiPartial | partial:m30_3 |
|
||||
| bad_asts.cpp:30:8:30:16 | ChiTotal | total:m30_2 |
|
||||
| bad_asts.cpp:30:8:30:16 | SideEffect | m30_3 |
|
||||
| bad_asts.cpp:31:10:31:15 | Address | &:r31_1 |
|
||||
| bad_asts.cpp:31:18:31:19 | StoreValue | r31_2 |
|
||||
| bad_asts.cpp:32:9:32:9 | Address | &:r32_1 |
|
||||
| bad_asts.cpp:32:12:32:16 | StoreValue | r32_2 |
|
||||
| bad_asts.cpp:33:5:33:5 | Address | &:r33_3 |
|
||||
| bad_asts.cpp:33:5:33:12 | Address | &:r33_1 |
|
||||
| bad_asts.cpp:33:5:33:12 | Load | ~m30_4 |
|
||||
| bad_asts.cpp:33:5:33:12 | StoreValue | r33_2 |
|
||||
| bad_stmts.cpp:5:8:5:16 | ChiPartial | partial:m5_3 |
|
||||
| bad_stmts.cpp:5:8:5:16 | ChiTotal | total:m5_2 |
|
||||
| bad_stmts.cpp:5:8:5:16 | SideEffect | m5_3 |
|
||||
| bad_stmts.cpp:6:10:6:15 | Address | &:r6_1 |
|
||||
| bad_stmts.cpp:6:18:6:19 | StoreValue | r6_2 |
|
||||
| bad_stmts.cpp:7:9:7:9 | Address | &:r7_1 |
|
||||
| bad_stmts.cpp:7:12:7:16 | StoreValue | r7_2 |
|
||||
| bad_stmts.cpp:8:5:8:5 | Address | &:r8_3 |
|
||||
| bad_stmts.cpp:8:5:8:12 | Address | &:r8_1 |
|
||||
| bad_stmts.cpp:8:5:8:12 | Load | ~m5_4 |
|
||||
| bad_stmts.cpp:8:5:8:12 | StoreValue | r8_2 |
|
||||
| clang.cpp:5:6:5:21 | Address | &:r5_5 |
|
||||
| clang.cpp:5:6:5:21 | ChiPartial | partial:m5_3 |
|
||||
| clang.cpp:5:6:5:21 | ChiTotal | total:m5_2 |
|
||||
|
|
|
@ -120,25 +120,26 @@ bad_asts.cpp:
|
|||
# 26| v26_10(void) = AliasedUse : ~m?
|
||||
# 26| v26_11(void) = ExitFunction :
|
||||
|
||||
# 30| void Bad::errorExpr()
|
||||
# 30| Block 0
|
||||
# 30| v30_1(void) = EnterFunction :
|
||||
# 30| mu30_2(unknown) = AliasedDefinition :
|
||||
# 30| mu30_3(unknown) = InitializeNonLocal :
|
||||
# 31| r31_1(glval<int &>) = VariableAddress[intref] :
|
||||
# 31| r31_2(error) = Error :
|
||||
# 31| mu31_3(int &) = Store[intref] : &:r31_1, r31_2
|
||||
# 32| r32_1(glval<int>) = VariableAddress[x] :
|
||||
# 32| r32_2(error) = Error :
|
||||
# 32| mu32_3(int) = Store[x] : &:r32_1, r32_2
|
||||
# 33| r33_1(glval<error>) = Error :
|
||||
# 33| r33_2(error) = Load[?] : &:r33_1, ~m?
|
||||
# 33| r33_3(glval<int>) = VariableAddress[x] :
|
||||
# 33| mu33_4(int) = Store[x] : &:r33_3, r33_2
|
||||
# 34| v34_1(void) = NoOp :
|
||||
# 30| v30_4(void) = ReturnVoid :
|
||||
# 30| v30_5(void) = AliasedUse : ~m?
|
||||
# 30| v30_6(void) = ExitFunction :
|
||||
bad_stmts.cpp:
|
||||
# 5| void Bad::errorExpr()
|
||||
# 5| Block 0
|
||||
# 5| v5_1(void) = EnterFunction :
|
||||
# 5| mu5_2(unknown) = AliasedDefinition :
|
||||
# 5| mu5_3(unknown) = InitializeNonLocal :
|
||||
# 6| r6_1(glval<int &>) = VariableAddress[intref] :
|
||||
# 6| r6_2(error) = Error :
|
||||
# 6| mu6_3(int &) = Store[intref] : &:r6_1, r6_2
|
||||
# 7| r7_1(glval<int>) = VariableAddress[x] :
|
||||
# 7| r7_2(error) = Error :
|
||||
# 7| mu7_3(int) = Store[x] : &:r7_1, r7_2
|
||||
# 8| r8_1(glval<error>) = Error :
|
||||
# 8| r8_2(error) = Load[?] : &:r8_1, ~m?
|
||||
# 8| r8_3(glval<int>) = VariableAddress[x] :
|
||||
# 8| mu8_4(int) = Store[x] : &:r8_3, r8_2
|
||||
# 9| v9_1(void) = NoOp :
|
||||
# 5| v5_4(void) = ReturnVoid :
|
||||
# 5| v5_5(void) = AliasedUse : ~m?
|
||||
# 5| v5_6(void) = ExitFunction :
|
||||
|
||||
clang.cpp:
|
||||
# 5| int* globalIntAddress()
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.ModulusAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
|
||||
import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module ModulusAnalysisInstantiated =
|
||||
ModulusAnalysis<FloatDelta, Bounds, RangeUtil<FloatDelta, CppLangImpl>>;
|
||||
|
||||
class ModulusAnalysisTest extends InlineExpectationsTest {
|
||||
ModulusAnalysisTest() { this = "ModulusAnalysisTest" }
|
||||
|
||||
|
@ -23,7 +30,7 @@ class ModulusAnalysisTest extends InlineExpectationsTest {
|
|||
|
||||
private string getAModString(SemExpr e) {
|
||||
exists(SemBound b, int delta, int mod |
|
||||
semExprModulus(e, b, delta, mod) and
|
||||
ModulusAnalysisInstantiated::semExprModulus(e, b, delta, mod) and
|
||||
result = b.toString() + "," + delta.toString() + "," + mod.toString() and
|
||||
not (delta = 0 and mod = 0)
|
||||
)
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.SignAnalysisCommon
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
|
||||
import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module SignAnalysisInstantiated = SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImpl>>;
|
||||
|
||||
class SignAnalysisTest extends InlineExpectationsTest {
|
||||
SignAnalysisTest() { this = "SignAnalysisTest" }
|
||||
|
||||
|
@ -21,4 +26,6 @@ class SignAnalysisTest extends InlineExpectationsTest {
|
|||
}
|
||||
}
|
||||
|
||||
private string getASignString(SemExpr e) { result = strictconcat(semExprSign(e).toString(), "") }
|
||||
private string getASignString(SemExpr e) {
|
||||
result = strictconcat(SignAnalysisInstantiated::semExprSign(e).toString(), "")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
struct Foo
|
||||
struct Allocators
|
||||
{
|
||||
Foo(int x, int y) : m_x(x), m_y(y) {}
|
||||
~Foo() {m_x = m_y = 0;}
|
||||
Allocators(int x, int y) : m_x(x), m_y(y) {}
|
||||
~Allocators() {m_x = m_y = 0;}
|
||||
|
||||
// NB: In Microsoft mode, size_t is predeclared.
|
||||
static void* operator new(size_t sz, int z, int w) { return nullptr; }
|
||||
|
@ -13,7 +13,7 @@ struct Foo
|
|||
|
||||
int main()
|
||||
{
|
||||
auto foo = new(11, 22) Foo(33, 44);
|
||||
auto foo = new(11, 22) Allocators(33, 44);
|
||||
delete foo;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
struct Foo {
|
||||
~Foo();
|
||||
struct ArrayDelete {
|
||||
~ArrayDelete();
|
||||
};
|
||||
|
||||
void f() {
|
||||
delete[] (Foo*)nullptr;
|
||||
delete[] (ArrayDelete*)nullptr;
|
||||
}
|
||||
|
|
|
@ -74,8 +74,8 @@ argHasPostUpdate
|
|||
| ir.cpp:625:5:625:5 | s | ArgumentNode is missing PostUpdateNode. |
|
||||
postWithInFlow
|
||||
| VacuousDestructorCall.cpp:10:22:10:22 | i [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:11:4:13 | m_x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:17:4:19 | m_y [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:18:4:20 | m_x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:24:4:26 | m_y [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| assignexpr.cpp:9:4:9:4 | i [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| builtin.c:34:23:34:31 | staticint [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| builtin.c:39:37:39:45 | carry_out [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
|
|
|
@ -1483,17 +1483,17 @@ postWithInFlow
|
|||
| aggregateinitializer.c:3:6:3:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| aggregateinitializer.c:3:11:3:27 | PointerAdd [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| aggregateinitializer.c:3:11:3:27 | PointerAdd [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:3:23:3:28 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:3:31:3:36 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:11:4:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:11:4:13 | m_x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:17:4:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:17:4:19 | m_y [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:3:30:3:35 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:3:38:3:43 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:18:4:20 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:18:4:20 | m_x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:24:4:26 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:4:24:4:26 | m_y [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:7:56:7:70 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:16:8:16:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:16:14:16:36 | Call [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:16:14:16:36 | new [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:16:14:16:36 | new [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:16:14:16:43 | Call [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:16:14:16:43 | new [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:16:14:16:43 | new [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| allocators.cpp:18:1:18:1 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| assignexpr.cpp:9:4:9:4 | i [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| bad_asts.cpp:10:7:10:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
|
|
|
@ -168,4 +168,34 @@ int main(int argc, char **argv) {
|
|||
int i10 = (int) argv[1];
|
||||
printf((char *) i10);
|
||||
printWrapper((char *) i10);
|
||||
|
||||
// BAD: b value comes from argv
|
||||
{
|
||||
char b[64];
|
||||
char *bp = &b[0];
|
||||
char *t;
|
||||
if (0) {
|
||||
t = 0;
|
||||
} else {
|
||||
t = bp;
|
||||
}
|
||||
memcpy(t, argv[1] + 1, 1);
|
||||
printf(bp);
|
||||
printWrapper(bp);
|
||||
}
|
||||
|
||||
// BAD: b value comes from argv
|
||||
{
|
||||
char b[64];
|
||||
char *bp = &b[0];
|
||||
char *t;
|
||||
if (1) {
|
||||
t = ++bp;
|
||||
} else {
|
||||
t = 0;
|
||||
}
|
||||
memcpy(t, argv[1] + 1, 1);
|
||||
printf(bp);
|
||||
printWrapper(bp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -260,6 +260,30 @@ edges
|
|||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:183:10:183:11 | (const char *)... |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:183:10:183:11 | (const char *)... |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:183:10:183:11 | bp |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:183:10:183:11 | bp |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:183:10:183:11 | bp indirection |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:183:10:183:11 | bp indirection |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:184:16:184:17 | bp |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:184:16:184:17 | bp |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:184:16:184:17 | bp |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:184:16:184:17 | bp |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:184:16:184:17 | bp indirection |
|
||||
| argvLocal.c:182:13:182:16 | argv | argvLocal.c:184:16:184:17 | bp indirection |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:198:10:198:11 | (const char *)... |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:198:10:198:11 | (const char *)... |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:198:10:198:11 | bp |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:198:10:198:11 | bp |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:198:10:198:11 | bp indirection |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:198:10:198:11 | bp indirection |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:199:16:199:17 | bp |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:199:16:199:17 | bp |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:199:16:199:17 | bp |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:199:16:199:17 | bp |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:199:16:199:17 | bp indirection |
|
||||
| argvLocal.c:197:13:197:16 | argv | argvLocal.c:199:16:199:17 | bp indirection |
|
||||
subpaths
|
||||
| argvLocal.c:102:15:102:16 | i1 indirection | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:9:25:9:31 | ReturnIndirection | argvLocal.c:102:15:102:16 | printWrapper output argument |
|
||||
| argvLocal.c:107:15:107:19 | access to array indirection | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:9:25:9:31 | ReturnIndirection | argvLocal.c:107:15:107:19 | printWrapper output argument |
|
||||
|
@ -396,6 +420,22 @@ nodes
|
|||
| argvLocal.c:170:15:170:26 | i10 indirection | semmle.label | i10 indirection |
|
||||
| argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 |
|
||||
| argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 |
|
||||
| argvLocal.c:182:13:182:16 | argv | semmle.label | argv |
|
||||
| argvLocal.c:182:13:182:16 | argv | semmle.label | argv |
|
||||
| argvLocal.c:183:10:183:11 | (const char *)... | semmle.label | (const char *)... |
|
||||
| argvLocal.c:183:10:183:11 | bp | semmle.label | bp |
|
||||
| argvLocal.c:183:10:183:11 | bp indirection | semmle.label | bp indirection |
|
||||
| argvLocal.c:184:16:184:17 | bp | semmle.label | bp |
|
||||
| argvLocal.c:184:16:184:17 | bp | semmle.label | bp |
|
||||
| argvLocal.c:184:16:184:17 | bp indirection | semmle.label | bp indirection |
|
||||
| argvLocal.c:197:13:197:16 | argv | semmle.label | argv |
|
||||
| argvLocal.c:197:13:197:16 | argv | semmle.label | argv |
|
||||
| argvLocal.c:198:10:198:11 | (const char *)... | semmle.label | (const char *)... |
|
||||
| argvLocal.c:198:10:198:11 | bp | semmle.label | bp |
|
||||
| argvLocal.c:198:10:198:11 | bp indirection | semmle.label | bp indirection |
|
||||
| argvLocal.c:199:16:199:17 | bp | semmle.label | bp |
|
||||
| argvLocal.c:199:16:199:17 | bp | semmle.label | bp |
|
||||
| argvLocal.c:199:16:199:17 | bp indirection | semmle.label | bp indirection |
|
||||
#select
|
||||
| argvLocal.c:95:9:95:15 | access to array | argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | argvLocal.c:95:9:95:12 | argv | argv |
|
||||
| argvLocal.c:96:15:96:21 | access to array | argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format). | argvLocal.c:96:15:96:18 | argv | argv |
|
||||
|
@ -425,3 +465,7 @@ nodes
|
|||
| argvLocal.c:165:15:165:17 | i91 | argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format). | argvLocal.c:163:22:163:25 | argv | argv |
|
||||
| argvLocal.c:169:18:169:20 | i10 | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:18:169:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | argvLocal.c:168:18:168:21 | argv | argv |
|
||||
| argvLocal.c:170:24:170:26 | i10 | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format). | argvLocal.c:168:18:168:21 | argv | argv |
|
||||
| argvLocal.c:183:10:183:11 | bp | argvLocal.c:182:13:182:16 | argv | argvLocal.c:183:10:183:11 | bp | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | argvLocal.c:182:13:182:16 | argv | argv |
|
||||
| argvLocal.c:184:16:184:17 | bp | argvLocal.c:182:13:182:16 | argv | argvLocal.c:184:16:184:17 | bp | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format). | argvLocal.c:182:13:182:16 | argv | argv |
|
||||
| argvLocal.c:198:10:198:11 | bp | argvLocal.c:197:13:197:16 | argv | argvLocal.c:198:10:198:11 | bp | The value of this argument may come from $@ and is being used as a formatting argument to printf(format). | argvLocal.c:197:13:197:16 | argv | argv |
|
||||
| argvLocal.c:199:16:199:17 | bp | argvLocal.c:197:13:197:16 | argv | argvLocal.c:199:16:199:17 | bp | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format). | argvLocal.c:197:13:197:16 | argv | argv |
|
||||
|
|
|
@ -17,6 +17,24 @@ edges
|
|||
| test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address |
|
||||
| test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address |
|
||||
| test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address indirection |
|
||||
| test.cpp:49:25:49:30 | call to getenv | test.cpp:52:14:52:20 | address |
|
||||
| test.cpp:49:25:49:30 | call to getenv | test.cpp:52:14:52:20 | address |
|
||||
| test.cpp:49:25:49:30 | call to getenv | test.cpp:52:14:52:20 | address indirection |
|
||||
| test.cpp:49:25:49:30 | call to getenv | test.cpp:56:14:56:20 | address |
|
||||
| test.cpp:49:25:49:30 | call to getenv | test.cpp:56:14:56:20 | address |
|
||||
| test.cpp:49:25:49:30 | call to getenv | test.cpp:56:14:56:20 | address indirection |
|
||||
| test.cpp:49:25:49:30 | call to getenv | test.cpp:60:14:60:20 | address |
|
||||
| test.cpp:49:25:49:30 | call to getenv | test.cpp:60:14:60:20 | address |
|
||||
| test.cpp:49:25:49:30 | call to getenv | test.cpp:60:14:60:20 | address indirection |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | test.cpp:52:14:52:20 | address |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | test.cpp:52:14:52:20 | address |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | test.cpp:52:14:52:20 | address indirection |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | test.cpp:56:14:56:20 | address |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | test.cpp:56:14:56:20 | address |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | test.cpp:56:14:56:20 | address indirection |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | test.cpp:60:14:60:20 | address |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | test.cpp:60:14:60:20 | address |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | test.cpp:60:14:60:20 | address indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| test.cpp:16:25:16:30 | call to getenv | semmle.label | call to getenv |
|
||||
|
@ -34,7 +52,21 @@ nodes
|
|||
| test.cpp:42:14:42:20 | address | semmle.label | address |
|
||||
| test.cpp:42:14:42:20 | address | semmle.label | address |
|
||||
| test.cpp:42:14:42:20 | address indirection | semmle.label | address indirection |
|
||||
| test.cpp:49:25:49:30 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:49:25:49:42 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:52:14:52:20 | address | semmle.label | address |
|
||||
| test.cpp:52:14:52:20 | address | semmle.label | address |
|
||||
| test.cpp:52:14:52:20 | address indirection | semmle.label | address indirection |
|
||||
| test.cpp:56:14:56:20 | address | semmle.label | address |
|
||||
| test.cpp:56:14:56:20 | address | semmle.label | address |
|
||||
| test.cpp:56:14:56:20 | address indirection | semmle.label | address indirection |
|
||||
| test.cpp:60:14:60:20 | address | semmle.label | address |
|
||||
| test.cpp:60:14:60:20 | address | semmle.label | address |
|
||||
| test.cpp:60:14:60:20 | address indirection | semmle.label | address indirection |
|
||||
#select
|
||||
| test.cpp:20:7:20:12 | call to strcmp | test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:16:25:16:30 | call to getenv | call to getenv |
|
||||
| test.cpp:31:7:31:12 | call to strcmp | test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:27:25:27:30 | call to getenv | call to getenv |
|
||||
| test.cpp:42:7:42:12 | call to strcmp | test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:38:25:38:30 | call to getenv | call to getenv |
|
||||
| test.cpp:52:7:52:12 | call to strcmp | test.cpp:49:25:49:30 | call to getenv | test.cpp:52:14:52:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:49:25:49:30 | call to getenv | call to getenv |
|
||||
| test.cpp:56:7:56:12 | call to strcmp | test.cpp:49:25:49:30 | call to getenv | test.cpp:56:14:56:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:49:25:49:30 | call to getenv | call to getenv |
|
||||
| test.cpp:60:7:60:12 | call to strcmp | test.cpp:49:25:49:30 | call to getenv | test.cpp:60:14:60:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:49:25:49:30 | call to getenv | call to getenv |
|
||||
|
|
|
@ -43,3 +43,27 @@ void processRequest3()
|
|||
isServer = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void processRequest4()
|
||||
{
|
||||
const char *address = getenv("SERVERIP");
|
||||
bool cond = false;
|
||||
|
||||
if (strcmp(address, "127.0.0.1")) { cond = true; } // BAD
|
||||
if (strcmp(address, "127_0_0_1")) { cond = true; } // GOOD (not an IP)
|
||||
if (strcmp(address, "127.0.0")) { cond = true; } // GOOD (not an IP)
|
||||
if (strcmp(address, "127.0.0.0.1")) { cond = true; } // GOOD (not an IP)
|
||||
if (strcmp(address, "http://mycompany")) { cond = true; } // BAD
|
||||
if (strcmp(address, "http_//mycompany")) { cond = true; } // GOOD (not an address)
|
||||
if (strcmp(address, "htt://mycompany")) { cond = true; } // GOOD (not an address)
|
||||
if (strcmp(address, "httpp://mycompany")) { cond = true; } // GOOD (not an address)
|
||||
if (strcmp(address, "mycompany.com")) { cond = true; } // BAD
|
||||
if (strcmp(address, "mycompany_com")) { cond = true; } // GOOD (not an address)
|
||||
if (strcmp(address, "mycompany.c")) { cond = true; } // GOOD (not an address)
|
||||
if (strcmp(address, "mycompany.comm")) { cond = true; } // GOOD (not an address)
|
||||
|
||||
if (cond) {
|
||||
isServer = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,2 @@
|
|||
description: Remove operators from the virtualizable type.
|
||||
compatibility: full
|
|
@ -92,7 +92,8 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
yield return Tuples.cil_parameter_out(pe);
|
||||
if (p.Attributes.HasFlag(ParameterAttributes.In))
|
||||
yield return Tuples.cil_parameter_in(pe);
|
||||
Attribute.Populate(Context, pe, p.GetCustomAttributes());
|
||||
foreach (var c in Attribute.Populate(Context, pe, p.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
|
||||
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
|
||||
|
@ -205,7 +206,8 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
yield return Tuples.cil_newslot(this);
|
||||
|
||||
// Populate attributes
|
||||
Attribute.Populate(Context, this, md.GetCustomAttributes());
|
||||
foreach (var c in Attribute.Populate(Context, this, md.GetCustomAttributes()))
|
||||
yield return c;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
## 1.4.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.4.0
|
||||
|
||||
No user-facing changes.
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
## 1.4.1
|
||||
|
||||
No user-facing changes.
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
lastReleaseVersion: 1.4.0
|
||||
lastReleaseVersion: 1.4.1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: codeql/csharp-solorigate-all
|
||||
version: 1.4.1-dev
|
||||
version: 1.4.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
## 1.4.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.4.0
|
||||
|
||||
No user-facing changes.
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
## 1.4.1
|
||||
|
||||
No user-facing changes.
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
lastReleaseVersion: 1.4.0
|
||||
lastReleaseVersion: 1.4.1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.4.1-dev
|
||||
version: 1.4.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
## 0.5.1
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Added library support for generic attributes (also for CIL extracted attributes).
|
||||
* `cil.ConstructedType::getName` was changed to include printing of the type arguments.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Attributes on methods in CIL are now extracted (Bugfix).
|
||||
* Support for `static virtual` and `static abstract` interface members.
|
||||
* Support for *operators* in interface definitions.
|
||||
* C# 11: Added support for the unsigned right shift `>>>` and unsigned right shift assignment `>>>=` operators.
|
||||
* Query id's have been aligned such that they are prefixed with `cs` instead of `csharp`.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Query id's have been aligned such that they are prefixed with `cs` instead of `csharp`.
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C# 11: Added support for the unsigned right shift `>>>` and unsigned right shift assignment `>>>=` operators.
|
|
@ -0,0 +1,14 @@
|
|||
## 0.5.1
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Added library support for generic attributes (also for CIL extracted attributes).
|
||||
* `cil.ConstructedType::getName` was changed to include printing of the type arguments.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Attributes on methods in CIL are now extracted (Bugfix).
|
||||
* Support for `static virtual` and `static abstract` interface members.
|
||||
* Support for *operators* in interface definitions.
|
||||
* C# 11: Added support for the unsigned right shift `>>>` and unsigned right shift assignment `>>>=` operators.
|
||||
* Query id's have been aligned such that they are prefixed with `cs` instead of `csharp`.
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
lastReleaseVersion: 0.5.0
|
||||
lastReleaseVersion: 0.5.1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: codeql/csharp-all
|
||||
version: 0.5.1-dev
|
||||
version: 0.5.2-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
|
|
@ -27,3 +27,19 @@ class Attribute extends Element, @cil_attribute {
|
|||
|
||||
override CS::Location getLocation() { result = getDeclaration().getLocation() }
|
||||
}
|
||||
|
||||
/** A generic attribute to a declaration. */
|
||||
class GenericAttribute extends Attribute {
|
||||
private ConstructedType type;
|
||||
|
||||
GenericAttribute() { type = this.getType() }
|
||||
|
||||
/** Gets the total number of type arguments. */
|
||||
int getNumberOfTypeArguments() { result = count(int i | cil_type_argument(type, i, _)) }
|
||||
|
||||
/** Gets the `i`th type argument, if any. */
|
||||
Type getTypeArgument(int i) { result = type.getTypeArgument(i) }
|
||||
|
||||
/** Get a type argument. */
|
||||
Type getATypeArgument() { result = this.getTypeArgument(_) }
|
||||
}
|
||||
|
|
|
@ -28,6 +28,12 @@ class ConstructedGeneric extends Generic, DotNet::ConstructedGeneric {
|
|||
final override Type getTypeArgument(int n) { cil_type_argument(this, n, result) }
|
||||
}
|
||||
|
||||
/** Gets the concatenation of the `getName()` of type arguments. */
|
||||
language[monotonicAggregates]
|
||||
private string getTypeArgumentsNames(ConstructedGeneric cg) {
|
||||
result = strictconcat(Type t, int i | t = cg.getTypeArgument(i) | t.getName(), "," order by i)
|
||||
}
|
||||
|
||||
/** An unbound generic type. */
|
||||
class UnboundGenericType extends UnboundGeneric, Type { }
|
||||
|
||||
|
@ -41,6 +47,10 @@ class ConstructedType extends ConstructedGeneric, Type {
|
|||
override predicate isInterface() { this.getUnboundType().isInterface() }
|
||||
|
||||
override predicate isClass() { this.getUnboundType().isClass() }
|
||||
|
||||
final override string getName() {
|
||||
result = this.getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">"
|
||||
}
|
||||
}
|
||||
|
||||
/** A constructed generic method. */
|
||||
|
|
|
@ -37,8 +37,14 @@ class Attributable extends @attributable {
|
|||
}
|
||||
|
||||
private string getAttributeName(Attribute a) {
|
||||
exists(string type | type = a.getType().getName() |
|
||||
if type.matches("%Attribute") then result = type.prefix(type.length() - 9) else result = type
|
||||
exists(string type, string pattern |
|
||||
type = a.getType().getName() and pattern = "(.*)Attribute(<.*>)?"
|
||||
|
|
||||
type.regexpMatch(pattern) and
|
||||
result = concat(int i | i = [1, 2] | type.regexpCapture(pattern, i) order by i)
|
||||
or
|
||||
not type.regexpMatch(pattern) and
|
||||
result = type
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -99,6 +105,31 @@ class Attribute extends TopLevelExprParent, @attribute {
|
|||
override string getAPrimaryQlClass() { result = "Attribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic attribute, for example `[...]` on line 1 in
|
||||
*
|
||||
* ```csharp
|
||||
* [MyGenericAttribute<int>(0)]
|
||||
* public void SomeMethod(string s) { }
|
||||
* ```
|
||||
*/
|
||||
class GenericAttribute extends Attribute {
|
||||
private ConstructedClass type;
|
||||
|
||||
GenericAttribute() { type = this.getType() }
|
||||
|
||||
/** Gets the total number of type arguments. */
|
||||
int getNumberOfTypeArguments() { result = count(int i | type_arguments(_, i, type)) }
|
||||
|
||||
/** Gets the `i`th type argument, if any. */
|
||||
Type getTypeArgument(int i) { result = type.getTypeArgument(i) }
|
||||
|
||||
/** Get a type argument. */
|
||||
Type getATypeArgument() { result = this.getTypeArgument(_) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "GenericAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An attribute with default kind, for example `[...]` on line 1 in
|
||||
* ```csharp
|
||||
|
@ -110,6 +141,17 @@ class DefaultAttribute extends Attribute, @attribute_default {
|
|||
override string getAPrimaryQlClass() { result = "DefaultAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic attribute with default kind, for example `[...]` on line 1 in
|
||||
* ```csharp
|
||||
* [MyAttribute<string>(0)]
|
||||
* int SomeMethod() { return 1; }
|
||||
* ```
|
||||
*/
|
||||
class GenericDefaultAttribute extends GenericAttribute, DefaultAttribute {
|
||||
override string getAPrimaryQlClass() { result = "GenericDefaultAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An attribute with return kind, for example `[...]` on line 1 in
|
||||
* ```csharp
|
||||
|
@ -123,6 +165,17 @@ class ReturnAttribute extends Attribute, @attribute_return {
|
|||
override string getAPrimaryQlClass() { result = "ReturnAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic attribute with return kind, for example `[...]` on line 1 in
|
||||
* ```csharp
|
||||
* [return: MyAttribute<object>(0)]
|
||||
* int SomeMethod() { return 1; }
|
||||
* ```
|
||||
*/
|
||||
class GenericReturnAttribute extends GenericAttribute, ReturnAttribute {
|
||||
override string getAPrimaryQlClass() { result = "GenericReturnAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An attribute with assembly kind, for example `[...]` on line 1 in
|
||||
* ```csharp
|
||||
|
@ -135,6 +188,16 @@ class AssemblyAttribute extends Attribute, @attribute_assembly {
|
|||
override string getAPrimaryQlClass() { result = "AssemblyAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic attribute with assembly kind, for example `[...]` on line 1 in
|
||||
* ```csharp
|
||||
* [assembly: MyAttribute<string>(0)]
|
||||
* ```
|
||||
*/
|
||||
class GenericAssemblyAttribute extends GenericAttribute, AssemblyAttribute {
|
||||
override string getAPrimaryQlClass() { result = "GenericAssemblyAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An attribute with module kind, for example `[...]` on line 1 in
|
||||
* ```csharp
|
||||
|
@ -146,3 +209,13 @@ class ModuleAttribute extends Attribute, @attribute_module {
|
|||
|
||||
override string getAPrimaryQlClass() { result = "ModuleAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic attribute with module kind, for example `[...]` on line 1 in
|
||||
* ```csharp
|
||||
* [module: MyAttribute<string>(0)]
|
||||
* ```
|
||||
*/
|
||||
class GenericModuleAttribute extends GenericAttribute, ModuleAttribute {
|
||||
override string getAPrimaryQlClass() { result = "GenericModuleAttribute" }
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ pragma[nomagic]
|
|||
private Virtualizable getACompatibleInterfaceMemberAux(Virtualizable m) {
|
||||
result = getACompatibleInterfaceAccessor(m) or
|
||||
result = getACompatibleInterfaceIndexer(m) or
|
||||
result = getACompatibleInterfaceMethod(m)
|
||||
result = getACompatibleRelevantInterfaceMember(m)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,11 +210,13 @@ private predicate getACompatibleInterfaceIndexerAux(Indexer i, ValueOrRefType t)
|
|||
t = getAPossibleImplementor(i.getDeclaringType())
|
||||
}
|
||||
|
||||
private Method getACompatibleInterfaceMethod0(Method m, int i) {
|
||||
result = getAnInterfaceMethodCandidate(m) and
|
||||
private RelevantInterfaceMember getACompatibleRelevantInterfaceMember0(
|
||||
RelevantInterfaceMember m, int i
|
||||
) {
|
||||
result = getARelevantInterfaceMemberCandidate(m) and
|
||||
i = -1
|
||||
or
|
||||
result = getACompatibleInterfaceMethod0(m, i - 1) and
|
||||
result = getACompatibleRelevantInterfaceMember0(m, i - 1) and
|
||||
exists(Type t1, Type t2 |
|
||||
t1 = getArgumentOrReturnType(m, i) and
|
||||
t2 = getArgumentOrReturnType(result, i)
|
||||
|
@ -223,32 +225,47 @@ private Method getACompatibleInterfaceMethod0(Method m, int i) {
|
|||
)
|
||||
}
|
||||
|
||||
private Method getACompatibleInterfaceMethod(Method m) {
|
||||
result = getACompatibleInterfaceMethod0(m, m.getNumberOfParameters())
|
||||
/**
|
||||
* A class of callables relevant for interface member compatibility.
|
||||
*/
|
||||
private class RelevantInterfaceMember extends Callable {
|
||||
RelevantInterfaceMember() {
|
||||
this instanceof Method or
|
||||
this instanceof Operator
|
||||
}
|
||||
|
||||
predicate isPublic() {
|
||||
this.(Method).isPublic() or
|
||||
this.(Operator).isPublic()
|
||||
}
|
||||
}
|
||||
|
||||
private RelevantInterfaceMember getACompatibleRelevantInterfaceMember(RelevantInterfaceMember m) {
|
||||
result = getACompatibleRelevantInterfaceMember0(m, m.getNumberOfParameters())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an interface method that may potentially be implemented by `m`.
|
||||
* Gets an interface method or operator that may potentially be implemented by `m`.
|
||||
*
|
||||
* That is, a method with the same name, same number of parameters, and declared
|
||||
* in a type that is a possible implementor type for the interface type.
|
||||
*/
|
||||
private Method getAnInterfaceMethodCandidate(Method m) {
|
||||
getAPotentialInterfaceMethodAux(result, m.getDeclaringType(), m.getUndecoratedName(),
|
||||
private RelevantInterfaceMember getARelevantInterfaceMemberCandidate(RelevantInterfaceMember m) {
|
||||
getAPotentialRelevantInterfaceMemberAux(result, m.getDeclaringType(), m.getUndecoratedName(),
|
||||
m.getNumberOfParameters()) and
|
||||
m.isPublic()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate getAPotentialInterfaceMethodAux(
|
||||
Method m, ValueOrRefType t, string name, int params
|
||||
private predicate getAPotentialRelevantInterfaceMemberAux(
|
||||
RelevantInterfaceMember m, ValueOrRefType t, string name, int params
|
||||
) {
|
||||
t = getAPossibleImplementor(m.getDeclaringType()) and
|
||||
name = m.getUndecoratedName() and
|
||||
params = m.getNumberOfParameters()
|
||||
}
|
||||
|
||||
private Type getArgumentOrReturnType(Method m, int i) {
|
||||
private Type getArgumentOrReturnType(RelevantInterfaceMember m, int i) {
|
||||
i = 0 and result = m.getReturnType()
|
||||
or
|
||||
result = m.getParameter(i - 1).getType()
|
||||
|
|
|
@ -184,7 +184,7 @@ private class TOverridable = @virtualizable or @callable_accessor;
|
|||
|
||||
/**
|
||||
* A declaration that can be overridden or implemented. That is, a method,
|
||||
* a property, an indexer, an event, or an accessor.
|
||||
* a property, an indexer, an event, an accessor, or an operator.
|
||||
*
|
||||
* Unlike `Virtualizable`, this class includes accessors.
|
||||
*/
|
||||
|
@ -360,7 +360,7 @@ class Overridable extends Declaration, TOverridable {
|
|||
|
||||
/**
|
||||
* A member where the `virtual` modifier is valid. That is, a method,
|
||||
* a property, an indexer, or an event.
|
||||
* a property, an indexer, an event, or an operator.
|
||||
*
|
||||
* Equivalently, these are the members that can be defined in an interface.
|
||||
*
|
||||
|
|
|
@ -45,6 +45,16 @@ module Consistency {
|
|||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */
|
||||
predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */
|
||||
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
|
@ -246,6 +256,7 @@ module Consistency {
|
|||
query predicate uniqueParameterNodeAtPosition(
|
||||
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||
) {
|
||||
not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and
|
||||
isParameterNode(p, c, pos) and
|
||||
not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and
|
||||
msg = "Parameters with overlapping positions."
|
||||
|
@ -254,6 +265,7 @@ module Consistency {
|
|||
query predicate uniqueParameterNodePosition(
|
||||
DataFlowCallable c, ParameterPosition pos, Node p, string msg
|
||||
) {
|
||||
not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and
|
||||
isParameterNode(p, c, pos) and
|
||||
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
||||
msg = "Parameter node with multiple positions."
|
||||
|
|
|
@ -39,6 +39,11 @@ module Public {
|
|||
)
|
||||
or
|
||||
exists(ReturnKind rk | this = TReturnSummaryComponent(rk) and result = "return (" + rk + ")")
|
||||
or
|
||||
exists(SummaryComponent::SyntheticGlobal sg |
|
||||
this = TSyntheticGlobalSummaryComponent(sg) and
|
||||
result = "synthetic global (" + sg + ")"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,24 +164,24 @@ module Public {
|
|||
SummaryComponentStack return(ReturnKind rk) { result = singleton(SummaryComponent::return(rk)) }
|
||||
}
|
||||
|
||||
private predicate noComponentSpecificCsv(SummaryComponent sc) {
|
||||
not exists(getComponentSpecificCsv(sc))
|
||||
private predicate noComponentSpecific(SummaryComponent sc) {
|
||||
not exists(getComponentSpecific(sc))
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this component used for flow summaries. */
|
||||
private string getComponentCsv(SummaryComponent sc) {
|
||||
result = getComponentSpecificCsv(sc)
|
||||
private string getComponent(SummaryComponent sc) {
|
||||
result = getComponentSpecific(sc)
|
||||
or
|
||||
noComponentSpecificCsv(sc) and
|
||||
noComponentSpecific(sc) and
|
||||
(
|
||||
exists(ArgumentPosition pos |
|
||||
sc = TParameterSummaryComponent(pos) and
|
||||
result = "Parameter[" + getArgumentPositionCsv(pos) + "]"
|
||||
result = "Parameter[" + getArgumentPosition(pos) + "]"
|
||||
)
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
sc = TArgumentSummaryComponent(pos) and
|
||||
result = "Argument[" + getParameterPositionCsv(pos) + "]"
|
||||
result = "Argument[" + getParameterPosition(pos) + "]"
|
||||
)
|
||||
or
|
||||
sc = TReturnSummaryComponent(getReturnValueKind()) and result = "ReturnValue"
|
||||
|
@ -184,16 +189,16 @@ module Public {
|
|||
}
|
||||
|
||||
/** Gets a textual representation of this stack used for flow summaries. */
|
||||
string getComponentStackCsv(SummaryComponentStack stack) {
|
||||
string getComponentStack(SummaryComponentStack stack) {
|
||||
exists(SummaryComponent head, SummaryComponentStack tail |
|
||||
head = stack.head() and
|
||||
tail = stack.tail() and
|
||||
result = getComponentStackCsv(tail) + "." + getComponentCsv(head)
|
||||
result = getComponentStack(tail) + "." + getComponent(head)
|
||||
)
|
||||
or
|
||||
exists(SummaryComponent c |
|
||||
stack = TSingletonSummaryComponentStack(c) and
|
||||
result = getComponentCsv(c)
|
||||
result = getComponent(c)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1217,8 +1222,8 @@ module Private {
|
|||
c.relevantSummary(input, output, preservesValue) and
|
||||
csv =
|
||||
c.getCallableCsv() // Callable information
|
||||
+ getComponentStackCsv(input) + ";" // input
|
||||
+ getComponentStackCsv(output) + ";" // output
|
||||
+ getComponentStack(input) + ";" // input
|
||||
+ getComponentStack(output) + ";" // output
|
||||
+ renderKind(preservesValue) + ";" // kind
|
||||
+ renderProvenance(c) // provenance
|
||||
)
|
||||
|
|
|
@ -178,7 +178,7 @@ SummaryComponent interpretComponentSpecific(AccessPathToken c) {
|
|||
}
|
||||
|
||||
/** Gets the textual representation of the content in the format used for flow summaries. */
|
||||
private string getContentSpecificCsv(Content c) {
|
||||
private string getContentSpecific(Content c) {
|
||||
c = TElementContent() and result = "Element"
|
||||
or
|
||||
exists(Field f | c = TFieldContent(f) and result = "Field[" + f.getQualifiedName() + "]")
|
||||
|
@ -189,8 +189,8 @@ private string getContentSpecificCsv(Content c) {
|
|||
}
|
||||
|
||||
/** Gets the textual representation of a summary component in the format used for flow summaries. */
|
||||
string getComponentSpecificCsv(SummaryComponent sc) {
|
||||
exists(Content c | sc = TContentSummaryComponent(c) and result = getContentSpecificCsv(c))
|
||||
string getComponentSpecific(SummaryComponent sc) {
|
||||
exists(Content c | sc = TContentSummaryComponent(c) and result = getContentSpecific(c))
|
||||
or
|
||||
sc = TWithoutContentSummaryComponent(_) and result = "WithoutElement"
|
||||
or
|
||||
|
@ -204,7 +204,7 @@ string getComponentSpecificCsv(SummaryComponent sc) {
|
|||
}
|
||||
|
||||
/** Gets the textual representation of a parameter position in the format used for flow summaries. */
|
||||
string getParameterPositionCsv(ParameterPosition pos) {
|
||||
string getParameterPosition(ParameterPosition pos) {
|
||||
result = pos.getPosition().toString()
|
||||
or
|
||||
pos.isThisParameter() and
|
||||
|
@ -212,7 +212,7 @@ string getParameterPositionCsv(ParameterPosition pos) {
|
|||
}
|
||||
|
||||
/** Gets the textual representation of an argument position in the format used for flow summaries. */
|
||||
string getArgumentPositionCsv(ArgumentPosition pos) {
|
||||
string getArgumentPosition(ArgumentPosition pos) {
|
||||
result = pos.getPosition().toString()
|
||||
or
|
||||
pos.isQualifier() and
|
||||
|
|
|
@ -670,7 +670,7 @@ compiler_generated(unique int id: @modifiable ref);
|
|||
|
||||
@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
|
||||
|
||||
@virtualizable = @method | @property | @indexer | @event;
|
||||
@virtualizable = @method | @property | @indexer | @event | @operator;
|
||||
|
||||
exprorstmt_name(
|
||||
unique int parent_id: @named_exprorstmt ref,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,2 @@
|
|||
description: Add operators to the virtualizable type.
|
||||
compatibility: full
|
|
@ -1,3 +1,7 @@
|
|||
## 0.5.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### New Queries
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
## 0.5.1
|
||||
|
||||
No user-facing changes.
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
lastReleaseVersion: 0.5.0
|
||||
lastReleaseVersion: 0.5.1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: codeql/csharp-queries
|
||||
version: 0.5.1-dev
|
||||
version: 0.5.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6,7 +6,8 @@ private predicate isOsSpecific(Declaration d) {
|
|||
.matches("%" +
|
||||
[
|
||||
"libobjc", "libproc", "System.Diagnostics.Tracing.XplatEventLogger",
|
||||
"System.Threading.AutoreleasePool"
|
||||
"System.Threading.AutoreleasePool",
|
||||
"System.Diagnostics.Tracing.EventSource.<WriteEventString>"
|
||||
] + "%")
|
||||
}
|
||||
|
||||
|
|
|
@ -472,6 +472,12 @@
|
|||
| Parameter 0 of System.Collections.Generic.GenericArraySortHelper.LessThan | parameter | 32 |
|
||||
| Parameter 0 of System.Collections.Generic.GenericArraySortHelper.Swap | parameter | 32 |
|
||||
| Parameter 0 of System.Collections.Generic.GenericArraySortHelper.SwapIfGreater | parameter | 32 |
|
||||
| Parameter 0 of System.Collections.Generic.GenericArraySortHelper<!0,!1>.GreaterThan | parameter | 32 |
|
||||
| Parameter 0 of System.Collections.Generic.GenericArraySortHelper<!0,!1>.LessThan | parameter | 32 |
|
||||
| Parameter 0 of System.Collections.Generic.GenericArraySortHelper<!0>.GreaterThan | parameter | 32 |
|
||||
| Parameter 0 of System.Collections.Generic.GenericArraySortHelper<!0>.LessThan | parameter | 32 |
|
||||
| Parameter 0 of System.Collections.Generic.GenericArraySortHelper<!0>.Swap | parameter | 32 |
|
||||
| Parameter 0 of System.Collections.Generic.GenericArraySortHelper<!0>.SwapIfGreater | parameter | 32 |
|
||||
| Parameter 0 of System.ConsolePal.<UpdatedCachedCursorPosition>g__IncrementX\|113_1 | parameter | 32 |
|
||||
| Parameter 0 of System.ConsolePal.<UpdatedCachedCursorPosition>g__IncrementY\|113_0 | parameter | 32 |
|
||||
| Parameter 0 of System.ConsolePal.GetWindowSize | parameter | 32 |
|
||||
|
@ -661,6 +667,10 @@
|
|||
| Parameter 0 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder.GetStateMachineBox | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<!0>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<!0>.GetStateMachineBox | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<VoidTaskResult>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.CastHelpers.Element | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.CastHelpers.HashShift | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.CastHelpers.KeyToBucket | parameter | 32 |
|
||||
|
@ -672,6 +682,9 @@
|
|||
| Parameter 0 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder.GetStateMachineBox | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<!0>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<!0>.GetStateMachineBox | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.InteropServices.ComWrappers.GetIUnknownImpl | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.InteropServices.ComWrappers.GetIUnknownImplInternal | parameter | 32 |
|
||||
| Parameter 0 of System.Runtime.InteropServices.MemoryMarshal.CreateReadOnlySpan | parameter | 32 |
|
||||
|
@ -737,6 +750,7 @@
|
|||
| Parameter 0 of System.Threading.Thread.VolatileRead | parameter | 32 |
|
||||
| Parameter 0 of System.Threading.Thread.VolatileWrite | parameter | 32 |
|
||||
| Parameter 0 of System.Threading.ThreadLocal.GrowTable | parameter | 32 |
|
||||
| Parameter 0 of System.Threading.ThreadLocal<!0>.GrowTable | parameter | 32 |
|
||||
| Parameter 0 of System.Threading.ThreadPool.GetAvailableThreads | parameter | 32 |
|
||||
| Parameter 0 of System.Threading.ThreadPool.GetAvailableThreadsNative | parameter | 32 |
|
||||
| Parameter 0 of System.Threading.ThreadPool.GetMaxThreads | parameter | 32 |
|
||||
|
@ -789,6 +803,7 @@
|
|||
| Parameter 1 of System.Buffers.Binary.BinaryPrimitives.TryReadUInt64BigEndian | parameter | 32 |
|
||||
| Parameter 1 of System.Buffers.Binary.BinaryPrimitives.TryReadUInt64LittleEndian | parameter | 32 |
|
||||
| Parameter 1 of System.Buffers.MemoryManager.TryGetArray | parameter | 32 |
|
||||
| Parameter 1 of System.Buffers.MemoryManager<!0>.TryGetArray | parameter | 32 |
|
||||
| Parameter 1 of System.Buffers.StandardFormat.ParseHelper | parameter | 32 |
|
||||
| Parameter 1 of System.Buffers.StandardFormat.TryParse | parameter | 32 |
|
||||
| Parameter 1 of System.Buffers.Text.FormattingHelpers.CountDecimalTrailingZeros | parameter | 32 |
|
||||
|
@ -835,20 +850,36 @@
|
|||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueue.TryDequeueSlow | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueue.TryPeek | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueue.TryTake | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueue<!0>.SnapForObservation | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueue<!0>.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueue<!0>.TryDequeueSlow | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueue<!0>.TryPeek | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueue<Object>.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueueSegment.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueueSegment.TryPeek | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueueSegment<!0>.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.ConcurrentQueueSegment<!0>.TryPeek | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.IProducerConsumerCollection.TryTake | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Concurrent.IProducerConsumerCollection<!0>.TryTake | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.DictionaryEntry.Deconstruct | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.EnumerableHelpers.ToArray | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper.GreaterThan | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper.LessThan | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper.Swap | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper.SwapIfGreater | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper<!0,!1>.GreaterThan | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper<!0,!1>.LessThan | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper<!0>.GreaterThan | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper<!0>.LessThan | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper<!0>.Swap | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.GenericArraySortHelper<!0>.SwapIfGreater | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.KeyValuePair.Deconstruct | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.KeyValuePair<String,ResourceSet>.Deconstruct | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.Queue.MoveNext | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.Queue.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.Queue.TryPeek | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.Stack.TryPop | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.Queue<!0>.MoveNext | parameter | 32 |
|
||||
| Parameter 1 of System.Collections.Generic.Stack<ConsoleKeyInfo>.TryPop | parameter | 32 |
|
||||
| Parameter 1 of System.ConsolePal.GetWindowSize | parameter | 32 |
|
||||
| Parameter 1 of System.ConsolePal.TryGetCachedCursorPosition | parameter | 32 |
|
||||
| Parameter 1 of System.ConsolePal.TryGetCursorPosition | parameter | 32 |
|
||||
|
@ -974,6 +1005,21 @@
|
|||
| Parameter 1 of System.Half.TryParse | parameter | 32 |
|
||||
| Parameter 1 of System.HashCode.Initialize | parameter | 32 |
|
||||
| Parameter 1 of System.INumber.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<Byte>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<Char>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<Decimal>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<Double>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<Half>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<Int16>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<Int32>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<Int64>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<IntPtr>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<SByte>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<Single>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<UInt16>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<UInt32>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<UInt64>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.INumber<UIntPtr>.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerable.DelegateEnumerator.ShouldIncludeEntry | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerable.DelegateEnumerator.ShouldRecurseIntoEntry | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerable.DelegateEnumerator.TransformEntry | parameter | 32 |
|
||||
|
@ -983,6 +1029,8 @@
|
|||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerable.FindTransform.BeginInvoke | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerable.FindTransform.EndInvoke | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerable.FindTransform.Invoke | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerable<!0>.FindPredicate.Invoke | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerable<!0>.FindTransform.Invoke | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerableFactory.<>c.<DirectoryInfos>b__7_0 | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerableFactory.<>c.<FileInfos>b__6_0 | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerableFactory.<>c.<FileSystemInfos>b__8_0 | parameter | 32 |
|
||||
|
@ -999,6 +1047,9 @@
|
|||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerator.ShouldIncludeEntry | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerator.ShouldRecurseIntoEntry | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerator.TransformEntry | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerator<!0>.ShouldIncludeEntry | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerator<!0>.ShouldRecurseIntoEntry | parameter | 32 |
|
||||
| Parameter 1 of System.IO.Enumeration.FileSystemEnumerator<!0>.TransformEntry | parameter | 32 |
|
||||
| Parameter 1 of System.IO.FileSystem.DirectoryExists | parameter | 32 |
|
||||
| Parameter 1 of System.IO.FileSystem.FileExists | parameter | 32 |
|
||||
| Parameter 1 of System.IO.FileSystemInfo.Init | parameter | 32 |
|
||||
|
@ -1073,7 +1124,14 @@
|
|||
| Parameter 1 of System.OrdinalComparer.IsWellKnownOrdinalComparerCore | parameter | 32 |
|
||||
| Parameter 1 of System.ParseNumbers.EatWhiteSpace | parameter | 32 |
|
||||
| Parameter 1 of System.ReadOnlyMemory.GetObjectStartLength | parameter | 32 |
|
||||
| Parameter 1 of System.ReadOnlyMemory<!0>.GetObjectStartLength | parameter | 32 |
|
||||
| Parameter 1 of System.ReadOnlyMemory<Char>.GetObjectStartLength | parameter | 32 |
|
||||
| Parameter 1 of System.ReadOnlySpan..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.ReadOnlySpan<!0>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.ReadOnlySpan<Byte>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.ReadOnlySpan<Char>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.ReadOnlySpan<Int32>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.ReadOnlySpan<Object>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Reflection.Binder.ReorderArgumentArray | parameter | 32 |
|
||||
| Parameter 1 of System.Reflection.CustomAttribute.FilterCustomAttributeRecord | parameter | 32 |
|
||||
| Parameter 1 of System.Reflection.CustomAttribute.GetPropertyOrFieldData | parameter | 32 |
|
||||
|
@ -1107,9 +1165,27 @@
|
|||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetNotificationForWaitCompletion | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<!0>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<!0>.GetStateMachineBox | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<!0>.SetException | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<!0>.SetNotificationForWaitCompletion | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<Boolean>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<Boolean>.Start | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<Byte[]>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<Byte[]>.Start | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<String>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<String>.Start | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<String[]>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<String[]>.Start | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<VoidTaskResult>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<VoidTaskResult>.SetException | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<VoidTaskResult>.SetNotificationForWaitCompletion | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder.Start | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<Int32>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<Int32>.Start | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncVoidMethodBuilder.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncVoidMethodBuilder.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Start | parameter | 32 |
|
||||
|
@ -1120,6 +1196,13 @@
|
|||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder.GetStateMachineBox | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder.SetException | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder.Start | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<!0>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<!0>.GetStateMachineBox | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<!0>.SetException | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<Int32>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<Int32>.Start | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<VoidTaskResult>.SetException | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.QCallAssembly..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.QCallModule..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Runtime.CompilerServices.QCallTypeHandle..ctor | parameter | 32 |
|
||||
|
@ -1195,6 +1278,8 @@
|
|||
| Parameter 1 of System.RuntimeType.RuntimeTypeCache.GetMemberList | parameter | 32 |
|
||||
| Parameter 1 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache.AddSpecialInterface | parameter | 32 |
|
||||
| Parameter 1 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache.Insert | parameter | 32 |
|
||||
| Parameter 1 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache<!0>.AddSpecialInterface | parameter | 32 |
|
||||
| Parameter 1 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache<!0>.Insert | parameter | 32 |
|
||||
| Parameter 1 of System.RuntimeType.SplitName | parameter | 32 |
|
||||
| Parameter 1 of System.RuntimeTypeHandle.CopyRuntimeTypeHandles | parameter | 32 |
|
||||
| Parameter 1 of System.RuntimeTypeHandle.GetActivationInfo | parameter | 32 |
|
||||
|
@ -1204,6 +1289,13 @@
|
|||
| Parameter 1 of System.Single.TryCreate | parameter | 32 |
|
||||
| Parameter 1 of System.Single.TryParse | parameter | 32 |
|
||||
| Parameter 1 of System.Span..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Span<!0>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Span<!1>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Span<Byte>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Span<Char>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Span<GuidResult>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Span<Int32>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.Span<Object>..ctor | parameter | 32 |
|
||||
| Parameter 1 of System.SpanHelpers.SequenceEqual | parameter | 32 |
|
||||
| Parameter 1 of System.String.Create | parameter | 32 |
|
||||
| Parameter 1 of System.String.IndexOfNewlineChar | parameter | 32 |
|
||||
|
@ -1260,9 +1352,13 @@
|
|||
| Parameter 1 of System.Threading.SpinLock.Enter | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.SpinLock.TryEnter | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.IProducerConsumerQueue.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.IProducerConsumerQueue<!0>.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.IProducerConsumerQueue<Task>.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.MultiProducerMultiConsumerQueue.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.SingleProducerSingleConsumerQueue.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.SingleProducerSingleConsumerQueue.TryDequeueSlow | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.SingleProducerSingleConsumerQueue<!0>.TryDequeue | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.SingleProducerSingleConsumerQueue<!0>.TryDequeueSlow | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.Task.AddToList | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.Task.CreationOptionsFromContinuationOptions | parameter | 32 |
|
||||
| Parameter 1 of System.Threading.Tasks.Task.ExecuteWithThreadLocal | parameter | 32 |
|
||||
|
@ -1310,6 +1406,9 @@
|
|||
| Parameter 1 of System.UIntPtr.TryParse | parameter | 32 |
|
||||
| Parameter 1 of System.Version.TryParse | parameter | 32 |
|
||||
| Parameter 1 of System.WeakReference.TryGetTarget | parameter | 32 |
|
||||
| Parameter 1 of System.WeakReference<AssemblyLoadContext>.TryGetTarget | parameter | 32 |
|
||||
| Parameter 1 of System.WeakReference<CounterGroup>.TryGetTarget | parameter | 32 |
|
||||
| Parameter 1 of System.WeakReference<EventSource>.TryGetTarget | parameter | 32 |
|
||||
| Parameter 1 of System.__DTString.GetRegularToken | parameter | 32 |
|
||||
| Parameter 2 of Internal.Runtime.InteropServices.IClassFactory.CreateInstance | parameter | 32 |
|
||||
| Parameter 2 of Interop.Globalization.GetJapaneseEraStartDate | parameter | 32 |
|
||||
|
@ -1370,15 +1469,49 @@
|
|||
| Parameter 2 of System.Char.TryFormat | parameter | 32 |
|
||||
| Parameter 2 of System.Char.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Concurrent.ConcurrentQueue.SnapForObservation | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Concurrent.ConcurrentQueue<!0>.SnapForObservation | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.DictionaryEntry.Deconstruct | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary.CollectionsMarshalHelper.GetValueRefOrAddDefault | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary.Remove | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<!0,!1>.CollectionsMarshalHelper.GetValueRefOrAddDefault | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<Int32,ChannelInfo>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<Int32,CultureInfo>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<Int32,HashSet<Token>>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<Int32,String>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<Int32,Task>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<MemberInfo,NullabilityState>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<Module,NotAnnotatedStatus>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<Object,Object>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<ReadOnlyMemory<Char>,ConsoleKeyInfo>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,Assembly>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,Boolean>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,CultureData>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,CultureInfo>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,Int32>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,IntPtr>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,IsolatedComponentLoadContext>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,List<Int32>>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,List<RuntimePropertyInfo>>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,LocalDataStoreSlot>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,Object>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,ResourceLocator>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,ResourceSet>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,String>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,TimeZoneInfo>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<String,Type>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<Type,AttributeUsageAttribute>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<Type,TraceLoggingTypeInfo>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<UInt64,Char>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.Dictionary<UInt64,String>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.HashSet.AddIfNotPresent | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.HashSet.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.HashSet<!0>.AddIfNotPresent | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.IDictionary.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.IDictionary<String,String>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.IReadOnlyDictionary.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.KeyValuePair.Deconstruct | parameter | 32 |
|
||||
| Parameter 2 of System.Collections.Generic.KeyValuePair<String,ResourceSet>.Deconstruct | parameter | 32 |
|
||||
| Parameter 2 of System.ComponentModel.DefaultValueAttribute.ctor>g__TryConvertFromInvariantString\|2_0 | parameter | 32 |
|
||||
| Parameter 2 of System.ConsolePal.<TryGetCursorPosition>g__BufferUntil\|83_1 | parameter | 32 |
|
||||
| Parameter 2 of System.Convert.CopyToTempBufferWithoutWhiteSpace | parameter | 32 |
|
||||
|
@ -1509,8 +1642,50 @@
|
|||
| Parameter 2 of System.IO.UnmanagedMemoryAccessor.Read | parameter | 32 |
|
||||
| Parameter 2 of System.IO.UnmanagedMemoryAccessor.Write | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Byte>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Char>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<DateOnly>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<DateTime>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<DateTimeOffset>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Decimal>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Double>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Guid>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Half>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Int16>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Int32>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Int64>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<IntPtr>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<SByte>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<Single>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<TimeOnly>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<TimeSpan>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<UInt16>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<UInt32>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<UInt64>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.IParseable<UIntPtr>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanFormattable.TryFormat | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Byte>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Char>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<DateOnly>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<DateTime>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<DateTimeOffset>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Decimal>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Double>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Guid>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Half>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Int16>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Int32>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Int64>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<IntPtr>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<SByte>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<Single>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<TimeOnly>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<TimeSpan>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<UInt16>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<UInt32>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<UInt64>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.ISpanParseable<UIntPtr>.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.Int16.TryFormat | parameter | 32 |
|
||||
| Parameter 2 of System.Int16.TryParse | parameter | 32 |
|
||||
| Parameter 2 of System.Int32.TryFormat | parameter | 32 |
|
||||
|
@ -1550,6 +1725,8 @@
|
|||
| Parameter 2 of System.ParseNumbers.GrabLongs | parameter | 32 |
|
||||
| Parameter 2 of System.ParseNumbers.IsDigit | parameter | 32 |
|
||||
| Parameter 2 of System.ReadOnlyMemory.GetObjectStartLength | parameter | 32 |
|
||||
| Parameter 2 of System.ReadOnlyMemory<!0>.GetObjectStartLength | parameter | 32 |
|
||||
| Parameter 2 of System.ReadOnlyMemory<Char>.GetObjectStartLength | parameter | 32 |
|
||||
| Parameter 2 of System.Reflection.AssemblyName.EscapeAsciiChar | parameter | 32 |
|
||||
| Parameter 2 of System.Reflection.CustomAttribute.AttributeUsageCheck | parameter | 32 |
|
||||
| Parameter 2 of System.Reflection.CustomAttribute.ParseAttributeUsageAttribute | parameter | 32 |
|
||||
|
@ -1610,18 +1787,35 @@
|
|||
| Parameter 2 of System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<!0>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<Boolean>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<Byte[]>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<String>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<String[]>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncTaskMethodBuilder<VoidTaskResult>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<Int32>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncVoidMethodBuilder.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.AsyncVoidMethodBuilder.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable.Container.FindEntry | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable.Container.TryGetEntry | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable.Container.TryGetValueWorker | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable<!0,!1>.Container.FindEntry | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable<!0,!1>.Container.TryGetEntry | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable<!0,!1>.Container.TryGetValueWorker | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable<!0,!1>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable<Assembly,DllImportResolver>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ConditionalWeakTable<Object,SerializationInfo>.TryGetValue | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ICastable.IsInstanceOfInterface | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.ICastableHelpers.IsInstanceOfInterface | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<!0>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<Int32>.AwaitUnsafeOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder<VoidTaskResult>.AwaitOnCompleted | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.InteropServices.CollectionsMarshal.GetValueRefOrAddDefault | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.InteropServices.ComTypes.IBindCtx.GetObjectParam | parameter | 32 |
|
||||
| Parameter 2 of System.Runtime.InteropServices.ComTypes.IConnectionPoint.Advise | parameter | 32 |
|
||||
|
@ -1724,6 +1918,7 @@
|
|||
| Parameter 2 of System.Text.UTF8Encoding.DecodeFirstRune | parameter | 32 |
|
||||
| Parameter 2 of System.Text.UTF8Encoding.TryGetByteCount | parameter | 32 |
|
||||
| Parameter 2 of System.Text.Unicode.TextSegmentationUtility.DecodeFirstRune.Invoke | parameter | 32 |
|
||||
| Parameter 2 of System.Text.Unicode.TextSegmentationUtility.DecodeFirstRune<!0>.Invoke | parameter | 32 |
|
||||
| Parameter 2 of System.Text.Unicode.Utf8.FromUtf16 | parameter | 32 |
|
||||
| Parameter 2 of System.Text.Unicode.Utf8.ToUtf16 | parameter | 32 |
|
||||
| Parameter 2 of System.Text.Unicode.Utf8Utility.GetPointerToFirstInvalidByte | parameter | 32 |
|
||||
|
@ -1748,6 +1943,8 @@
|
|||
| Parameter 2 of System.Threading.SpinLock.TryEnter | parameter | 32 |
|
||||
| Parameter 2 of System.Threading.Tasks.SingleProducerSingleConsumerQueue.EnqueueSlow | parameter | 32 |
|
||||
| Parameter 2 of System.Threading.Tasks.SingleProducerSingleConsumerQueue.TryDequeueSlow | parameter | 32 |
|
||||
| Parameter 2 of System.Threading.Tasks.SingleProducerSingleConsumerQueue<!0>.EnqueueSlow | parameter | 32 |
|
||||
| Parameter 2 of System.Threading.Tasks.SingleProducerSingleConsumerQueue<!0>.TryDequeueSlow | parameter | 32 |
|
||||
| Parameter 2 of System.Threading.Tasks.Task.CreationOptionsFromContinuationOptions | parameter | 32 |
|
||||
| Parameter 2 of System.Threading.ThreadPool.GetNextConfigUInt32Value | parameter | 32 |
|
||||
| Parameter 2 of System.Threading.ThreadPoolWorkQueue.Dequeue | parameter | 32 |
|
||||
|
@ -1810,6 +2007,7 @@
|
|||
| Parameter 3 of System.Byte.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.Char.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.Collections.Concurrent.ConcurrentQueue.SnapForObservation | parameter | 32 |
|
||||
| Parameter 3 of System.Collections.Concurrent.ConcurrentQueue<!0>.SnapForObservation | parameter | 32 |
|
||||
| Parameter 3 of System.Collections.Hashtable.InitHash | parameter | 32 |
|
||||
| Parameter 3 of System.ConsolePal.<TryGetCursorPosition>g__AppendToStdInReaderUntil\|83_2 | parameter | 32 |
|
||||
| Parameter 3 of System.ConsolePal.<TryGetCursorPosition>g__BufferUntil\|83_1 | parameter | 32 |
|
||||
|
@ -1868,6 +2066,21 @@
|
|||
| Parameter 3 of System.Half.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.HashCode.Initialize | parameter | 32 |
|
||||
| Parameter 3 of System.INumber.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<Byte>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<Char>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<Decimal>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<Double>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<Half>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<Int16>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<Int32>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<Int64>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<IntPtr>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<SByte>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<Single>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<UInt16>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<UInt32>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<UInt64>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.INumber<UIntPtr>.TryParse | parameter | 32 |
|
||||
| Parameter 3 of System.IO.BufferedStream.WriteToBuffer | parameter | 32 |
|
||||
| Parameter 3 of System.IO.Path.TryJoin | parameter | 32 |
|
||||
| Parameter 3 of System.IO.StdInReader.GetKeyFromCharValue | parameter | 32 |
|
||||
|
@ -1947,6 +2160,7 @@
|
|||
| Parameter 3 of System.Resources.ResourceReader.GetResourceData | parameter | 32 |
|
||||
| Parameter 3 of System.Resources.RuntimeResourceSet.ReadValue | parameter | 32 |
|
||||
| Parameter 3 of System.Runtime.CompilerServices.ConditionalWeakTable.Container.TryGetEntry | parameter | 32 |
|
||||
| Parameter 3 of System.Runtime.CompilerServices.ConditionalWeakTable<!0,!1>.Container.TryGetEntry | parameter | 32 |
|
||||
| Parameter 3 of System.Runtime.InteropServices.ComTypes.IMoniker.BindToObject | parameter | 32 |
|
||||
| Parameter 3 of System.Runtime.InteropServices.ComTypes.IMoniker.BindToStorage | parameter | 32 |
|
||||
| Parameter 3 of System.Runtime.InteropServices.ComTypes.IMoniker.ComposeWith | parameter | 32 |
|
||||
|
@ -1981,6 +2195,8 @@
|
|||
| Parameter 3 of System.RuntimeType.GetType | parameter | 32 |
|
||||
| Parameter 3 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache.PopulateLiteralFields | parameter | 32 |
|
||||
| Parameter 3 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache.PopulateRtFields | parameter | 32 |
|
||||
| Parameter 3 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache<!0>.PopulateLiteralFields | parameter | 32 |
|
||||
| Parameter 3 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache<!0>.PopulateRtFields | parameter | 32 |
|
||||
| Parameter 3 of System.RuntimeTypeHandle.GetActivationInfo | parameter | 32 |
|
||||
| Parameter 3 of System.RuntimeTypeHandle.GetTypeByName | parameter | 32 |
|
||||
| Parameter 3 of System.SByte.TryParse | parameter | 32 |
|
||||
|
@ -2005,6 +2221,7 @@
|
|||
| Parameter 3 of System.Text.UTF8Encoding.DecodeFirstRune | parameter | 32 |
|
||||
| Parameter 3 of System.Text.UTF8Encoding.EncodeRune | parameter | 32 |
|
||||
| Parameter 3 of System.Text.Unicode.TextSegmentationUtility.DecodeFirstRune.Invoke | parameter | 32 |
|
||||
| Parameter 3 of System.Text.Unicode.TextSegmentationUtility.DecodeFirstRune<!0>.Invoke | parameter | 32 |
|
||||
| Parameter 3 of System.Text.Unicode.Utf8.FromUtf16 | parameter | 32 |
|
||||
| Parameter 3 of System.Text.Unicode.Utf8.ToUtf16 | parameter | 32 |
|
||||
| Parameter 3 of System.Text.Unicode.Utf8Utility.GetPointerToFirstInvalidByte | parameter | 32 |
|
||||
|
@ -2015,6 +2232,7 @@
|
|||
| Parameter 3 of System.Threading.SpinLock.ContinueTryEnterWithThreadTracking | parameter | 32 |
|
||||
| Parameter 3 of System.Threading.Tasks.AwaitTaskContinuation.RunCallback | parameter | 32 |
|
||||
| Parameter 3 of System.Threading.Tasks.SingleProducerSingleConsumerQueue.TryDequeueSlow | parameter | 32 |
|
||||
| Parameter 3 of System.Threading.Tasks.SingleProducerSingleConsumerQueue<!0>.TryDequeueSlow | parameter | 32 |
|
||||
| Parameter 3 of System.Threading.Tasks.Task.AtomicStateUpdate | parameter | 32 |
|
||||
| Parameter 3 of System.Threading.ThreadPool.GetNextConfigUInt32Value | parameter | 32 |
|
||||
| Parameter 3 of System.TimeOnly.TryParse | parameter | 32 |
|
||||
|
@ -2052,6 +2270,7 @@
|
|||
| Parameter 4 of System.Buffers.Text.Utf8Parser.TryParseAsSpecialFloatingPoint | parameter | 32 |
|
||||
| Parameter 4 of System.Buffers.Text.Utf8Parser.TryParseNumber | parameter | 32 |
|
||||
| Parameter 4 of System.Collections.Concurrent.ConcurrentQueue.SnapForObservation | parameter | 32 |
|
||||
| Parameter 4 of System.Collections.Concurrent.ConcurrentQueue<!0>.SnapForObservation | parameter | 32 |
|
||||
| Parameter 4 of System.Collections.Hashtable.InitHash | parameter | 32 |
|
||||
| Parameter 4 of System.ConsolePal.<TryGetCursorPosition>g__AppendToStdInReaderUntil\|83_2 | parameter | 32 |
|
||||
| Parameter 4 of System.ConsolePal.<TryGetCursorPosition>g__BufferUntil\|83_1 | parameter | 32 |
|
||||
|
@ -2163,6 +2382,7 @@
|
|||
| Parameter 4 of System.RuntimeFieldHandle.GetValue | parameter | 32 |
|
||||
| Parameter 4 of System.RuntimeType.FilterHelper | parameter | 32 |
|
||||
| Parameter 4 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache.PopulateEvents | parameter | 32 |
|
||||
| Parameter 4 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache<!0>.PopulateEvents | parameter | 32 |
|
||||
| Parameter 4 of System.RuntimeTypeHandle.GetActivationInfo | parameter | 32 |
|
||||
| Parameter 4 of System.TermInfo.ParameterizedStrings.EvaluateInternal | parameter | 32 |
|
||||
| Parameter 4 of System.Text.ASCIIEncoding.GetByteCountFast | parameter | 32 |
|
||||
|
@ -2228,6 +2448,8 @@
|
|||
| Parameter 5 of System.RuntimeType.FilterHelper | parameter | 32 |
|
||||
| Parameter 5 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache.PopulateProperties | parameter | 32 |
|
||||
| Parameter 5 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache.PopulateRtFields | parameter | 32 |
|
||||
| Parameter 5 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache<!0>.PopulateProperties | parameter | 32 |
|
||||
| Parameter 5 of System.RuntimeType.RuntimeTypeCache.MemberInfoCache<!0>.PopulateRtFields | parameter | 32 |
|
||||
| Parameter 5 of System.TermInfo.ParameterizedStrings.EvaluateInternal | parameter | 32 |
|
||||
| Parameter 5 of System.Text.ASCIIEncoding.GetBytesFast | parameter | 32 |
|
||||
| Parameter 5 of System.Text.ASCIIEncoding.GetCharsFast | parameter | 32 |
|
||||
|
@ -2336,10 +2558,16 @@
|
|||
| Parameter 21 of System.TupleExtensions.Deconstruct | parameter | 32 |
|
||||
| System.ByReference.Value | property | 32 |
|
||||
| System.ByReference.get_Value | method | 32 |
|
||||
| System.ByReference<!0>.get_Value | method | 32 |
|
||||
| System.ByReference<Byte>.get_Value | method | 32 |
|
||||
| System.Collections.Generic.Dictionary.CollectionsMarshalHelper.GetValueRefOrAddDefault | method | 32 |
|
||||
| System.Collections.Generic.Dictionary.FindValue | method | 32 |
|
||||
| System.Collections.Generic.Dictionary.GetBucket | method | 32 |
|
||||
| System.Collections.Generic.Dictionary<!0,!1>.CollectionsMarshalHelper.GetValueRefOrAddDefault | method | 32 |
|
||||
| System.Collections.Generic.Dictionary<!0,!1>.FindValue | method | 32 |
|
||||
| System.Collections.Generic.Dictionary<!0,!1>.GetBucket | method | 32 |
|
||||
| System.Collections.Generic.HashSet.GetBucketRef | method | 32 |
|
||||
| System.Collections.Generic.HashSet<!0>.GetBucketRef | method | 32 |
|
||||
| System.Decimal.AsMutable | method | 32 |
|
||||
| System.Decimal.Max | method | 32 |
|
||||
| System.Decimal.Min | method | 32 |
|
||||
|
@ -2350,6 +2578,16 @@
|
|||
| System.ReadOnlySpan.GetPinnableReference | method | 32 |
|
||||
| System.ReadOnlySpan.Item | property | 32 |
|
||||
| System.ReadOnlySpan.get_Item | method | 32 |
|
||||
| System.ReadOnlySpan<!0>.get_Item | method | 32 |
|
||||
| System.ReadOnlySpan<Boolean>.get_Item | method | 32 |
|
||||
| System.ReadOnlySpan<Byte>.GetPinnableReference | method | 32 |
|
||||
| System.ReadOnlySpan<Byte>.get_Item | method | 32 |
|
||||
| System.ReadOnlySpan<Char>.get_Item | method | 32 |
|
||||
| System.ReadOnlySpan<Int32>.get_Item | method | 32 |
|
||||
| System.ReadOnlySpan<Object>.get_Item | method | 32 |
|
||||
| System.ReadOnlySpan<SafeWaitHandle>.get_Item | method | 32 |
|
||||
| System.ReadOnlySpan<String>.get_Item | method | 32 |
|
||||
| System.ReadOnlySpan<WaitHandle>.get_Item | method | 32 |
|
||||
| System.Runtime.CompilerServices.CastHelpers.Element | method | 32 |
|
||||
| System.Runtime.CompilerServices.CastHelpers.LdelemaRef | method | 32 |
|
||||
| System.Runtime.CompilerServices.CastHelpers.TableData | method | 32 |
|
||||
|
@ -2371,6 +2609,19 @@
|
|||
| System.Span.GetPinnableReference | method | 32 |
|
||||
| System.Span.Item | property | 32 |
|
||||
| System.Span.get_Item | method | 32 |
|
||||
| System.Span<!0>.get_Item | method | 32 |
|
||||
| System.Span<!1>.get_Item | method | 32 |
|
||||
| System.Span<Byte>.GetPinnableReference | method | 32 |
|
||||
| System.Span<Byte>.get_Item | method | 32 |
|
||||
| System.Span<Char>.GetPinnableReference | method | 32 |
|
||||
| System.Span<Char>.get_Item | method | 32 |
|
||||
| System.Span<EventPipeProviderConfigurationNative>.GetPinnableReference | method | 32 |
|
||||
| System.Span<EventPipeProviderConfigurationNative>.get_Item | method | 32 |
|
||||
| System.Span<IOVector>.get_Item | method | 32 |
|
||||
| System.Span<Int32>.get_Item | method | 32 |
|
||||
| System.Span<IntPtr>.get_Item | method | 32 |
|
||||
| System.Span<Object>.get_Item | method | 32 |
|
||||
| System.Span<SafeWaitHandle>.get_Item | method | 32 |
|
||||
| System.SpanHelpers.Add | method | 32 |
|
||||
| System.String.GetPinnableReference | method | 32 |
|
||||
| System.String.GetRawStringData | method | 32 |
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
|
||||
[assembly: MyGenericAttribute<int>()]
|
||||
[module: MyGeneric2<object, object>()]
|
||||
|
||||
public class MyGenericAttribute<T> : Attribute { }
|
||||
public class MyGeneric2Attribute<T, U> : Attribute { }
|
||||
|
||||
public class TestGenericAttribute
|
||||
{
|
||||
|
||||
[MyGenericAttribute<int>()]
|
||||
public void M1() { }
|
||||
|
||||
[MyGeneric<string>()]
|
||||
public void M2() { }
|
||||
|
||||
[MyGeneric2<int, string>()]
|
||||
public void M3() { }
|
||||
|
||||
[return: MyGeneric<object>()]
|
||||
public int M4() { return 0; }
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
public interface INumber<T> where T : INumber<T>
|
||||
{
|
||||
static abstract T operator ++(T other);
|
||||
|
||||
static virtual T operator --(T other) => other;
|
||||
|
||||
static abstract T Add(T left, T right);
|
||||
|
||||
static virtual T Subtract(T left, T right) => left;
|
||||
|
||||
static T Zero() => default(T);
|
||||
}
|
||||
|
||||
public class Complex : INumber<Complex>
|
||||
{
|
||||
public double Real { get; private set; } = 0.0;
|
||||
public double Imaginary { get; private set; } = 0.0;
|
||||
|
||||
public Complex() { }
|
||||
|
||||
public static Complex Zero() => new Complex();
|
||||
|
||||
public static Complex operator ++(Complex other) =>
|
||||
new Complex { Real = other.Real + 1.0, Imaginary = other.Imaginary };
|
||||
|
||||
public static Complex operator --(Complex other) =>
|
||||
new Complex { Real = other.Real - 1.0, Imaginary = other.Imaginary };
|
||||
|
||||
public static Complex Add(Complex left, Complex right) =>
|
||||
new Complex { Real = left.Real + right.Real, Imaginary = left.Imaginary + right.Imaginary };
|
||||
|
||||
public static Complex Subtract(Complex left, Complex right) =>
|
||||
new Complex { Real = left.Real - right.Real, Imaginary = left.Imaginary - right.Imaginary };
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace Assembly
|
||||
{
|
||||
public class MyAssemblyGeneric1Attribute<T> : Attribute { }
|
||||
public class MyAssemblyGeneric2Attribute<T, U> : Attribute { }
|
||||
|
||||
public class TestAssemblyGenericAttribute
|
||||
{
|
||||
[MyAssemblyGeneric1Attribute<object>()]
|
||||
public void M1() { }
|
||||
|
||||
[MyAssemblyGeneric2<int, string>()]
|
||||
public void M2() { }
|
||||
}
|
||||
}
|
Двоичный файл не отображается.
|
@ -0,0 +1,7 @@
|
|||
using System;
|
||||
using Assembly;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
public static void Main(string[] args) { }
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
| assembly.dll:0:0:0:0 | [MyAssemblyGeneric1Attribute<Object>(...)] | MyAssemblyGeneric1Attribute<Object> | 1 | (Object) |
|
||||
| assembly.dll:0:0:0:0 | [MyAssemblyGeneric2Attribute<Int32,String>(...)] | MyAssemblyGeneric2Attribute<Int32,String> | 2 | (Int32,String) |
|
|
@ -0,0 +1,9 @@
|
|||
import semmle.code.cil.CIL
|
||||
|
||||
private string getTypeArguments(GenericAttribute a) {
|
||||
result = "(" + concat(Type t | t = a.getATypeArgument() | t.getName(), ",") + ")"
|
||||
}
|
||||
|
||||
from GenericAttribute a
|
||||
where a.getFile().getStem() = "assembly"
|
||||
select a, a.getType().getName(), a.getNumberOfTypeArguments(), getTypeArguments(a)
|
|
@ -0,0 +1 @@
|
|||
semmle-extractor-options: --cil
|
|
@ -0,0 +1,6 @@
|
|||
| GenericAttribute.cs:3:12:3:34 | [assembly: MyGeneric<Int32>(...)] | MyGenericAttribute<Int32> | 1 | (Int32) | GenericAssemblyAttribute |
|
||||
| GenericAttribute.cs:4:10:4:35 | [module: MyGeneric2<Object,Object>(...)] | MyGeneric2Attribute<Object,Object> | 2 | (Object) | GenericModuleAttribute |
|
||||
| GenericAttribute.cs:12:6:12:28 | [MyGeneric<Int32>(...)] | MyGenericAttribute<Int32> | 1 | (Int32) | GenericDefaultAttribute |
|
||||
| GenericAttribute.cs:15:6:15:22 | [MyGeneric<String>(...)] | MyGenericAttribute<String> | 1 | (String) | GenericDefaultAttribute |
|
||||
| GenericAttribute.cs:18:6:18:28 | [MyGeneric2<Int32,String>(...)] | MyGeneric2Attribute<Int32,String> | 2 | (Int32,String) | GenericDefaultAttribute |
|
||||
| GenericAttribute.cs:21:14:21:30 | [return: MyGeneric<Object>(...)] | MyGenericAttribute<Object> | 1 | (Object) | GenericReturnAttribute |
|
|
@ -0,0 +1,10 @@
|
|||
import csharp
|
||||
|
||||
private string getTypeArguments(GenericAttribute a) {
|
||||
result = "(" + concat(Type t | t = a.getATypeArgument() | t.getName(), ",") + ")"
|
||||
}
|
||||
|
||||
from GenericAttribute a
|
||||
where a.getFile().getStem() = "GenericAttribute"
|
||||
select a, a.getType().getName(), a.getNumberOfTypeArguments(), getTypeArguments(a),
|
||||
a.getAPrimaryQlClass()
|
|
@ -0,0 +1,20 @@
|
|||
interfacemembers
|
||||
| INumber<> | StaticInterfaceMembers.cs:3:32:3:33 | ++ | abstract |
|
||||
| INumber<> | StaticInterfaceMembers.cs:3:32:3:33 | ++ | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:3:32:3:33 | ++ | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:5:31:5:32 | -- | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:5:31:5:32 | -- | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:5:31:5:32 | -- | virtual |
|
||||
| INumber<> | StaticInterfaceMembers.cs:7:23:7:25 | Add | abstract |
|
||||
| INumber<> | StaticInterfaceMembers.cs:7:23:7:25 | Add | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:7:23:7:25 | Add | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:9:22:9:29 | Subtract | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:9:22:9:29 | Subtract | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:9:22:9:29 | Subtract | virtual |
|
||||
| INumber<> | StaticInterfaceMembers.cs:11:14:11:17 | Zero | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:11:14:11:17 | Zero | static |
|
||||
implements
|
||||
| StaticInterfaceMembers.cs:23:36:23:37 | ++ | StaticInterfaceMembers.cs:3:32:3:33 | ++ |
|
||||
| StaticInterfaceMembers.cs:26:36:26:37 | -- | StaticInterfaceMembers.cs:5:31:5:32 | -- |
|
||||
| StaticInterfaceMembers.cs:29:27:29:29 | Add | StaticInterfaceMembers.cs:7:23:7:25 | Add |
|
||||
| StaticInterfaceMembers.cs:32:27:32:34 | Subtract | StaticInterfaceMembers.cs:9:22:9:29 | Subtract |
|
|
@ -0,0 +1,18 @@
|
|||
import csharp
|
||||
|
||||
query predicate interfacemembers(string interface, Member m, string modifier) {
|
||||
exists(Interface i |
|
||||
i.isUnboundDeclaration() and
|
||||
i.getFile().getStem() = "StaticInterfaceMembers" and
|
||||
i.getName() = interface and
|
||||
m = i.getAMember() and
|
||||
modifier = m.getAModifier().getName()
|
||||
)
|
||||
}
|
||||
|
||||
query predicate implements(Overridable o, Virtualizable v) {
|
||||
v.getFile().getStem() = "StaticInterfaceMembers" and
|
||||
(v.isVirtual() or v.isAbstract()) and
|
||||
v.isStatic() and
|
||||
v.getAnImplementor() = o
|
||||
}
|
|
@ -7,6 +7,7 @@ type NUL && "%CODEQL_DIST%\codeql" database index-files ^
|
|||
--include-extension=.xml ^
|
||||
--size-limit 10m ^
|
||||
--language xml ^
|
||||
--working-dir=. ^
|
||||
-- ^
|
||||
"%CODEQL_EXTRACTOR_CSHARP_WIP_DATABASE%" ^
|
||||
>nul 2>&1
|
||||
|
|
|
@ -9,6 +9,7 @@ set -eu
|
|||
--include-extension=.xml \
|
||||
--size-limit 10m \
|
||||
--language xml \
|
||||
--working-dir=. \
|
||||
-- \
|
||||
"$CODEQL_EXTRACTOR_CSHARP_WIP_DATABASE" \
|
||||
> /dev/null 2>&1
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Contributing to CodeQL docs
|
||||
|
||||
We welcome contributions to our CodeQL docs. Want to improve existing docs or add new information you think would be helpful? Then please go ahead and open a pull request!
|
||||
|
||||
## Contributing to CodeQL docs on `codeql.github.com`
|
||||
|
||||
To make changes to the documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-overview/), you can make changes to the documentation files using the GitHub UI, a codespace, or a local text editor, and then open a pull request for review. For more information about the format and structure of the CodeQL documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-overview/), please see the [README](docs/codeql/README.rst).
|
||||
|
||||
## Contributing to CodeQL CLI docs on `docs.github.com`
|
||||
|
||||
We are in the process of moving all documentation about the CodeQL CLI from [github/codeql](docs/codeql) to the public [github/docs](https://github.com/github/docs) repository so that this documentation is published on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles that are currently published under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories on the CodeQL microsite. This will make it easier for code scanning users to find information about using CodeQL to query their codebases.
|
||||
|
||||
**Note**: For a brief time, we will have source files for CodeQL CLI documentation in two locations. During this period we will not accept changes to the old files in the `codeql` repository, only to the new files in the `docs` repository.
|
||||
|
||||
To contribute to these docs, which are located in the [`code-scanning`](https://github.com/github/docs/tree/main/content/code-security/code-scanning) directory, please refer to the [CONTRIBUTING.md](CONTRIBUTING.md) file in the `docs` repository.
|
||||
|
||||
|
||||
|
|
@ -12,6 +12,8 @@ see https://docutils.sourceforge.io/rst.html.
|
|||
|
||||
For more information on Sphinx, see https://www.sphinx-doc.org.
|
||||
|
||||
For information on contributing to CodeQL documentation, see the `contributing guide </CONTRIBUTING.md>`__.
|
||||
|
||||
Project structure
|
||||
*****************
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@ In summary, the kinds of expressions are:
|
|||
- These refer to predicates.
|
||||
- They can be simple :ref:`names <names>` or names with arities (for example in an :ref:`alias <aliases>`
|
||||
definition), or :ref:`selections <selections>`.
|
||||
- **signature expressions**
|
||||
- These refer to module signatures, type signatures, or predicate signatures.
|
||||
- They can be simple :ref:`names <names>`, names with arities, :ref:`selections <selections>`,
|
||||
or :ref:`instantiations <parameterized-modules>`.
|
||||
|
||||
.. _names:
|
||||
|
||||
|
@ -164,14 +168,27 @@ As in many other programming languages, a namespace is a mapping from **keys** t
|
|||
**entities**. A key is a kind of identifier, for example a name, and a QL entity is
|
||||
a :ref:`module <modules>`, a :ref:`type <types>`, or a :ref:`predicate <predicates>`.
|
||||
|
||||
Each module in QL has three namespaces:
|
||||
Each module in QL has six namespaces:
|
||||
|
||||
- The **module namespace**, where the keys are module names and the entities are modules.
|
||||
- The **type namespace**, where the keys are type names and the entities are types.
|
||||
- The **predicate namespace**, where the keys are pairs of predicate names and arities,
|
||||
and the entities are predicates.
|
||||
- The **module signature namespace**, where the keys are module signature names and the entities are module signatures.
|
||||
- The **type signature namespace**, where the keys are type signature names and the entities are type signatures.
|
||||
- The **predicate signature namespace**, where the keys are pairs of predicate signature names and arities,
|
||||
and the entities are predicate signatures.
|
||||
|
||||
It's important to know that there is no relation between names in different namespaces.
|
||||
The six namespaces of any module are not completely independent of each other:
|
||||
|
||||
- No keys may be shared between the **module namespace** and the **module signature namespace**.
|
||||
- No keys may be shared between the **type namespace** and the **type signature namespace**.
|
||||
- No keys may be shared between the **module namespace** and the **type signature namespace**.
|
||||
- No keys may be shared between the **type namespace** and the **module signature namespace**.
|
||||
- No keys may be shared between the **predicate namespace** and the **predicate signature namespace**.
|
||||
- No keys may be shared between the **module signature namespace** and the **type signature namespace**.
|
||||
|
||||
There is no relation between names in namespaces of different modules.
|
||||
For example, two different modules can define a predicate ``getLocation()`` without confusion. As long as
|
||||
it's clear which namespace you are in, the QL compiler resolves the name to the correct predicate.
|
||||
|
||||
|
@ -182,11 +199,12 @@ The namespaces containing all the built-in entities are called **global namespac
|
|||
and are automatically available in any module.
|
||||
In particular:
|
||||
|
||||
- The **global module namespace** is empty.
|
||||
- The **global module namespace** has a single entry ``QlBuiltins``.
|
||||
- The **global type namespace** has entries for the :ref:`primitive types <primitive-types>` ``int``, ``float``,
|
||||
``string``, ``boolean``, and ``date``, as well as any :ref:`database types <database-types>` defined in the database schema.
|
||||
- The **global predicate namespace** includes all the `built-in predicates <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#built-ins>`_,
|
||||
as well as any :ref:`database predicates <database-predicates>`.
|
||||
- The **global signature namespaces** are empty.
|
||||
|
||||
In practice, this means that you can use the built-in types and predicates directly in a QL module (without
|
||||
importing any libraries). You can also use any database predicates and types directly—these depend on the
|
||||
|
|
|
@ -86,13 +86,25 @@ use information from the database.
|
|||
Name resolution
|
||||
---------------
|
||||
|
||||
All modules have three environments that dictate name resolution. These are multimaps of keys to declarations.
|
||||
All modules have six environments that dictate name resolution. These are multimaps of keys to declarations.
|
||||
|
||||
The environments are:
|
||||
|
||||
- The *module environment*, whose keys are module names and whose values are modules.
|
||||
- The *type environment*, whose keys are type names and whose values are types.
|
||||
- The *predicate environment*, whose keys are pairs of predicate names and arities and whose values are predicates.
|
||||
- The *module signature environment*, whose keys are module signature names and whose values are module signatures.
|
||||
- The *type signature environment*, whose keys are type signature names and whose values are type signatures.
|
||||
- The *predicate signature environment*, whose keys are pairs of predicate signature names and arities and whose values are predicate signatures.
|
||||
|
||||
For each module, some namespaces are enforced to be disjoint:
|
||||
|
||||
- No keys may be shared between the **module namespace** and the **module signature namespace**.
|
||||
- No keys may be shared between the **type namespace** and the **type signature namespace**.
|
||||
- No keys may be shared between the **module namespace** and the **type signature namespace**.
|
||||
- No keys may be shared between the **type namespace** and the **module signature namespace**.
|
||||
- No keys may be shared between the **predicate namespace** and the **predicate signature namespace**.
|
||||
- No keys may be shared between the **module signature namespace** and the **type signature namespace**.
|
||||
|
||||
If not otherwise specified, then the environment for a piece of syntax is the same as the environment of its enclosing syntax.
|
||||
|
||||
|
@ -108,12 +120,14 @@ A *definite* environment has at most one entry for each key. Resolution is uniqu
|
|||
Global environments
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The global module environment is empty.
|
||||
The global module environment has a single entry ``QlBuiltins``.
|
||||
|
||||
The global type environment has entries for the primitive types ``int``, ``float``, ``string``, ``boolean``, and ``date``, as well as any types defined in the database schema.
|
||||
|
||||
The global predicate environment includes all the built-in classless predicates, as well as any extensional predicates declared in the database schema.
|
||||
|
||||
The three global signature environments are empty.
|
||||
|
||||
The program is invalid if any of these environments is not definite.
|
||||
|
||||
Module environments
|
||||
|
|
|
@ -148,6 +148,7 @@ and the CodeQL library pack ``codeql/javascript-all`` (`changelog <https://githu
|
|||
EJS, templating language
|
||||
electron, Runtime environment
|
||||
express, Server
|
||||
Fastify, Server
|
||||
handlebars, templating language
|
||||
hapi, Server
|
||||
hogan, templating language
|
||||
|
@ -166,6 +167,7 @@ and the CodeQL library pack ``codeql/javascript-all`` (`changelog <https://githu
|
|||
react, HTML framework
|
||||
react native, HTML framework
|
||||
request, Network communicator
|
||||
restify, Server
|
||||
sequelize, Database
|
||||
socket.io, Network communicator
|
||||
sqlite3, Database
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
## 0.4.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Breaking Changes
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
## 0.4.1
|
||||
|
||||
No user-facing changes.
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
lastReleaseVersion: 0.4.0
|
||||
lastReleaseVersion: 0.4.1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: codeql/go-all
|
||||
version: 0.4.1-dev
|
||||
version: 0.4.2-dev
|
||||
groups: go
|
||||
dbscheme: go.dbscheme
|
||||
extractor: go
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.dataflow.DataFlowForStringsNewReplacer
|
||||
|
||||
/** Provides predicates and classes for working with string operations. */
|
||||
module StringOps {
|
||||
|
@ -162,6 +163,114 @@ module StringOps {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that is equivalent to `strings.ReplaceAll(s, old, new)`.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `StringOps::ReplaceAll::Range` instead.
|
||||
*/
|
||||
class ReplaceAll extends DataFlow::Node instanceof ReplaceAll::Range {
|
||||
/**
|
||||
* Gets the `old` in `strings.ReplaceAll(s, old, new)`.
|
||||
*/
|
||||
string getReplacedString() { result = super.getReplacedString() }
|
||||
}
|
||||
|
||||
/** Provides predicates and classes for working with prefix checks. */
|
||||
module ReplaceAll {
|
||||
/**
|
||||
* An expression that is equivalent to `strings.ReplaceAll(s, old, new)`.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models, extend
|
||||
* `StringOps::ReplaceAll` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the `old` in `strings.ReplaceAll(s, old, new)`.
|
||||
*/
|
||||
abstract string getReplacedString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `strings.ReplaceAll` or `strings.Replace` with a negative `n`
|
||||
* so that all instances are replaced.
|
||||
*/
|
||||
private class StringsReplaceAll extends Range, DataFlow::CallNode {
|
||||
StringsReplaceAll() {
|
||||
exists(string name | this.getTarget().hasQualifiedName("strings", name) |
|
||||
name = "ReplaceAll"
|
||||
or
|
||||
name = "Replace" and
|
||||
this.getArgument(3).getNumericValue() < 0
|
||||
)
|
||||
}
|
||||
|
||||
override string getReplacedString() { result = this.getArgument(1).getStringValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `strings.NewReplacer`.
|
||||
*/
|
||||
private class StringsNewReplacerCall extends DataFlow::CallNode {
|
||||
StringsNewReplacerCall() { this.getTarget().hasQualifiedName("strings", "NewReplacer") }
|
||||
|
||||
/**
|
||||
* Gets an argument to this call corresponding to a string that will be
|
||||
* replaced.
|
||||
*/
|
||||
DataFlow::Node getAReplacedArgument() {
|
||||
exists(int n | n % 2 = 0 and result = this.getArgument(n))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration for tracking flow from a call to `strings.NewReplacer` to
|
||||
* the receiver of a call to `strings.Replacer.Replace` or
|
||||
* `strings.Replacer.WriteString`.
|
||||
*/
|
||||
private class StringsNewReplacerConfiguration extends DataFlowForStringsNewReplacer::Configuration {
|
||||
StringsNewReplacerConfiguration() { this = "StringsNewReplacerConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source instanceof StringsNewReplacerCall
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
sink = call.getReceiver() and
|
||||
call.getTarget().hasQualifiedName("strings", "Replacer", ["Replace", "WriteString"])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `strings.Replacer.Replace` or `strings.Replacer.WriteString`.
|
||||
*/
|
||||
private class StringsReplacerReplaceOrWriteString extends Range {
|
||||
string replacedString;
|
||||
|
||||
StringsReplacerReplaceOrWriteString() {
|
||||
exists(
|
||||
StringsNewReplacerConfiguration config, StringsNewReplacerCall source,
|
||||
DataFlow::Node sink, DataFlow::MethodCallNode call
|
||||
|
|
||||
config.hasFlow(source, sink) and
|
||||
sink = call.getReceiver() and
|
||||
replacedString = source.getAReplacedArgument().getStringValue() and
|
||||
(
|
||||
call.getTarget().hasQualifiedName("strings", "Replacer", "Replace") and
|
||||
this = call.getResult()
|
||||
or
|
||||
call.getTarget().hasQualifiedName("strings", "Replacer", "WriteString") and
|
||||
this = call.getArgument(1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override string getReplacedString() { result = replacedString }
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides predicates and classes for working with Printf-style formatters. */
|
||||
module Formatting {
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Provides a library for local (intra-procedural) and global (inter-procedural)
|
||||
* data flow analysis: deciding whether data can flow from a _source_ to a
|
||||
* _sink_.
|
||||
*
|
||||
* Unless configured otherwise, _flow_ means that the exact value of
|
||||
* the source may reach the sink. We do not track flow across pointer
|
||||
* dereferences or array indexing. To track these types of flow, where the
|
||||
* exact value may not be preserved, import
|
||||
* `semmle.code.go.dataflow.TaintTracking`.
|
||||
*
|
||||
* To use global (interprocedural) data flow, extend the class
|
||||
* `DataFlow::Configuration` as documented on that class. To use local
|
||||
* (intraprocedural) data flow, invoke `DataFlow::localFlow` or
|
||||
* `DataFlow::LocalFlowStep` with arguments of type `DataFlow::Node`.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
/**
|
||||
* Provides a library for local (intra-procedural) and global (inter-procedural)
|
||||
* data flow analysis.
|
||||
*/
|
||||
module DataFlowForStringsNewReplacer {
|
||||
import semmle.go.dataflow.internal.DataFlowImplForStringsNewReplacer
|
||||
import Properties
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче