Merge branch 'main' into import-refined
3
.github/workflows/check-qldoc.yml
vendored
@@ -26,9 +26,8 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
EXIT_CODE=0
|
||||
# TODO: remove the swift exception from the regex when we fix generated QLdoc
|
||||
# TODO: remove the shared exception from the regex when coverage of qlpacks without dbschemes is supported
|
||||
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!(swift|shared))[a-z]*/ql/lib' || true; } | sort -u)"
|
||||
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!(shared))[a-z]*/ql/lib' || true; } | sort -u)"
|
||||
for pack_dir in ${changed_lib_packs}; do
|
||||
lang="${pack_dir%/ql/lib}"
|
||||
codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"
|
||||
|
||||
@@ -68,7 +68,9 @@ class Declaration extends Locatable, @declaration {
|
||||
* Holds if this declaration has the fully-qualified name `qualifiedName`.
|
||||
* See `getQualifiedName`.
|
||||
*/
|
||||
predicate hasQualifiedName(string qualifiedName) { this.getQualifiedName() = qualifiedName }
|
||||
deprecated predicate hasQualifiedName(string qualifiedName) {
|
||||
this.getQualifiedName() = qualifiedName
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this declaration has a fully-qualified name with a name-space
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
...
|
||||
a = getc(f);
|
||||
if (a < 123) ret = 123/a; // BAD
|
||||
...
|
||||
if (a != 0) ret = 123/a; // GOOD
|
||||
...
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p> Possible cases of division by zero when using the return value from functions.</p>
|
||||
|
||||
</overview>
|
||||
|
||||
<example>
|
||||
<p>The following example shows the use of a function with an error when using the return value and without an error.</p>
|
||||
<sample src="DivideByZeroUsingReturnValue.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CERT Coding Standard:
|
||||
<a href="https://wiki.sei.cmu.edu/confluence/display/c/INT33-C.+Ensure+that+division+and+remainder+operations+do+not+result+in+divide-by-zero+errors">INT33-C. Ensure that division and remainder operations do not result in divide-by-zero errors - SEI CERT C Coding Standard - Confluence</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* @name Divide by zero using return value
|
||||
* @description Possible cases of division by zero when using the return value from functions.
|
||||
* @kind problem
|
||||
* @id cpp/divide-by-zero-using-return-value
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-369
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
/** Holds if function `fn` can return a value equal to value `val` */
|
||||
predicate mayBeReturnValue(Function fn, float val) {
|
||||
exists(Expr tmpExp, ReturnStmt rs |
|
||||
tmpExp.getValue().toFloat() = val and
|
||||
rs.getEnclosingFunction() = fn and
|
||||
(
|
||||
globalValueNumber(rs.getExpr()) = globalValueNumber(tmpExp)
|
||||
or
|
||||
exists(AssignExpr ae |
|
||||
ae.getLValue().(VariableAccess).getTarget() =
|
||||
globalValueNumber(rs.getExpr()).getAnExpr().(VariableAccess).getTarget() and
|
||||
globalValueNumber(ae.getRValue()) = globalValueNumber(tmpExp)
|
||||
)
|
||||
or
|
||||
exists(Initializer it |
|
||||
globalValueNumber(it.getExpr()) = globalValueNumber(tmpExp) and
|
||||
it.getDeclaration().(Variable).getAnAccess().getTarget() =
|
||||
globalValueNumber(rs.getExpr()).getAnExpr().(VariableAccess).getTarget()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if function `fn` can return a value equal zero */
|
||||
predicate mayBeReturnZero(Function fn) {
|
||||
mayBeReturnValue(fn, 0)
|
||||
or
|
||||
fn.hasName([
|
||||
"iswalpha", "iswlower", "iswprint", "iswspace", "iswblank", "iswupper", "iswcntrl",
|
||||
"iswctype", "iswalnum", "iswgraph", "iswxdigit", "iswdigit", "iswpunct", "isblank", "isupper",
|
||||
"isgraph", "isalnum", "ispunct", "islower", "isspace", "isprint", "isxdigit", "iscntrl",
|
||||
"isdigit", "isalpha", "timespec_get", "feof", "atomic_is_lock_free",
|
||||
"atomic_compare_exchange", "thrd_equal", "isfinite", "islessequal", "isnan", "isgreater",
|
||||
"signbit", "isinf", "islessgreater", "isnormal", "isless", "isgreaterequal", "isunordered",
|
||||
"ferror"
|
||||
])
|
||||
or
|
||||
fn.hasName([
|
||||
"thrd_sleep", "feenv", "feholdexcept", "feclearexcept", "feexceptflag", "feupdateenv",
|
||||
"remove", "fflush", "setvbuf", "fgetpos", "fsetpos", "fclose", "rename", "fseek", "raise"
|
||||
])
|
||||
or
|
||||
fn.hasName(["tss_get", "gets"])
|
||||
or
|
||||
fn.hasName(["getc", "atoi"])
|
||||
}
|
||||
|
||||
/** Gets the Guard which compares the expression `bound` */
|
||||
pragma[inline]
|
||||
GuardCondition checkByValue(Expr bound, Expr val) {
|
||||
exists(GuardCondition gc |
|
||||
(
|
||||
gc.ensuresEq(bound, val, _, _, _) or
|
||||
gc.ensuresEq(val, bound, _, _, _) or
|
||||
gc.ensuresLt(bound, val, _, _, _) or
|
||||
gc.ensuresLt(val, bound, _, _, _) or
|
||||
gc = globalValueNumber(bound).getAnExpr()
|
||||
) and
|
||||
result = gc
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if there are no comparisons between the value returned by possible function calls `compArg` and the value `valArg`, or when these comparisons do not exclude equality to the value `valArg`. */
|
||||
pragma[inline]
|
||||
predicate compareFunctionWithValue(Expr guardExp, Function compArg, Expr valArg) {
|
||||
not exists(Expr exp |
|
||||
exp.getAChild*() = globalValueNumber(compArg.getACallToThisFunction()).getAnExpr() and
|
||||
checkByValue(exp, valArg).controls(guardExp.getBasicBlock(), _)
|
||||
)
|
||||
or
|
||||
exists(GuardCondition gc |
|
||||
(
|
||||
gc.ensuresEq(globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), valArg, 0,
|
||||
guardExp.getBasicBlock(), true)
|
||||
or
|
||||
gc.ensuresEq(valArg, globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), 0,
|
||||
guardExp.getBasicBlock(), true)
|
||||
or
|
||||
gc.ensuresLt(globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), valArg, 0,
|
||||
guardExp.getBasicBlock(), false)
|
||||
or
|
||||
gc.ensuresLt(valArg, globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), 0,
|
||||
guardExp.getBasicBlock(), false)
|
||||
)
|
||||
or
|
||||
exists(Expr exp |
|
||||
exp.getValue().toFloat() > valArg.getValue().toFloat() and
|
||||
gc.ensuresLt(globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), exp, 0,
|
||||
guardExp.getBasicBlock(), true)
|
||||
or
|
||||
exp.getValue().toFloat() < valArg.getValue().toFloat() and
|
||||
gc.ensuresLt(exp, globalValueNumber(compArg.getACallToThisFunction()).getAnExpr(), 0,
|
||||
guardExp.getBasicBlock(), true)
|
||||
)
|
||||
)
|
||||
or
|
||||
valArg.getValue().toFloat() = 0 and
|
||||
exists(NotExpr ne, IfStmt ifne |
|
||||
ne.getOperand() = globalValueNumber(compArg.getACallToThisFunction()).getAnExpr() and
|
||||
ifne.getCondition() = ne and
|
||||
ifne.getThen().getAChild*() = guardExp
|
||||
)
|
||||
}
|
||||
|
||||
/** Wraping predicate for call `compareFunctionWithValue`. */
|
||||
pragma[inline]
|
||||
predicate checkConditions1(Expr div, Function fn, float changeInt) {
|
||||
exists(Expr val |
|
||||
val.getEnclosingFunction() = fn and
|
||||
val.getValue().toFloat() = changeInt and
|
||||
compareFunctionWithValue(div, fn, val)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if there are no comparisons between the value `compArg` and the value `valArg`, or when these comparisons do not exclude equality to the value `valArg`. */
|
||||
pragma[inline]
|
||||
predicate compareExprWithValue(Expr guardExp, Expr compArg, Expr valArg) {
|
||||
not exists(Expr exp |
|
||||
exp.getAChild*() = globalValueNumber(compArg).getAnExpr() and
|
||||
checkByValue(exp, valArg).controls(guardExp.getBasicBlock(), _)
|
||||
)
|
||||
or
|
||||
exists(GuardCondition gc |
|
||||
(
|
||||
gc.ensuresEq(globalValueNumber(compArg).getAnExpr(), valArg, 0, guardExp.getBasicBlock(), true)
|
||||
or
|
||||
gc.ensuresEq(valArg, globalValueNumber(compArg).getAnExpr(), 0, guardExp.getBasicBlock(), true)
|
||||
or
|
||||
gc.ensuresLt(globalValueNumber(compArg).getAnExpr(), valArg, 0, guardExp.getBasicBlock(),
|
||||
false)
|
||||
or
|
||||
gc.ensuresLt(valArg, globalValueNumber(compArg).getAnExpr(), 0, guardExp.getBasicBlock(),
|
||||
false)
|
||||
)
|
||||
or
|
||||
exists(Expr exp |
|
||||
exp.getValue().toFloat() > valArg.getValue().toFloat() and
|
||||
gc.ensuresLt(globalValueNumber(compArg).getAnExpr(), exp, 0, guardExp.getBasicBlock(), true)
|
||||
or
|
||||
exp.getValue().toFloat() < valArg.getValue().toFloat() and
|
||||
gc.ensuresLt(exp, globalValueNumber(compArg).getAnExpr(), 0, guardExp.getBasicBlock(), true)
|
||||
)
|
||||
)
|
||||
or
|
||||
valArg.getValue().toFloat() = 0 and
|
||||
exists(NotExpr ne, IfStmt ifne |
|
||||
ne.getOperand() = globalValueNumber(compArg).getAnExpr() and
|
||||
ifne.getCondition() = ne and
|
||||
ifne.getThen().getAChild*() = guardExp
|
||||
)
|
||||
}
|
||||
|
||||
/** Wraping predicate for call `compareExprWithValue`. */
|
||||
pragma[inline]
|
||||
predicate checkConditions2(Expr div, Expr divVal, float changeInt2) {
|
||||
exists(Expr val |
|
||||
(
|
||||
val.getEnclosingFunction() =
|
||||
div.getEnclosingFunction().getACallToThisFunction().getEnclosingFunction() or
|
||||
val.getEnclosingFunction() = div.getEnclosingFunction()
|
||||
) and
|
||||
val.getValue().toFloat() = changeInt2 and
|
||||
compareExprWithValue(div, divVal, val)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the value of the difference or summand from the expression `src`. */
|
||||
float getValueOperand(Expr src, Expr e1, Expr e2) {
|
||||
src.(SubExpr).hasOperands(e1, e2) and
|
||||
result = e2.getValue().toFloat()
|
||||
or
|
||||
src.(AddExpr).hasOperands(e1, e2) and
|
||||
result = -e2.getValue().toFloat()
|
||||
}
|
||||
|
||||
/** Function the return of the expression `e1` and the multiplication operands, or the left operand of division if `e1` contains a multiplication or division, respectively. */
|
||||
Expr getMulDivOperand(Expr e1) {
|
||||
result = e1 or
|
||||
result = e1.(MulExpr).getAnOperand() or
|
||||
result = e1.(DivExpr).getLeftOperand()
|
||||
}
|
||||
|
||||
/** The class that defines possible variants of the division expression or the search for the remainder. */
|
||||
class MyDiv extends Expr {
|
||||
MyDiv() {
|
||||
this instanceof DivExpr or
|
||||
this instanceof RemExpr or
|
||||
this instanceof AssignDivExpr or
|
||||
this instanceof AssignRemExpr
|
||||
}
|
||||
|
||||
Expr getRV() {
|
||||
result = this.(AssignArithmeticOperation).getRValue() or
|
||||
result = this.(BinaryArithmeticOperation).getRightOperand()
|
||||
}
|
||||
}
|
||||
|
||||
from Expr exp, string msg, Function fn, GVN findVal, float changeInt, MyDiv div
|
||||
where
|
||||
findVal = globalValueNumber(fn.getACallToThisFunction()) and
|
||||
(
|
||||
// Look for divide-by-zero operations possible due to the return value of the function `fn`.
|
||||
checkConditions1(div, fn, changeInt) and
|
||||
(
|
||||
// Function return value can be zero.
|
||||
mayBeReturnZero(fn) and
|
||||
getMulDivOperand(globalValueNumber(div.getRV()).getAnExpr()) = findVal.getAnExpr() and
|
||||
changeInt = 0
|
||||
or
|
||||
// Denominator can be sum or difference.
|
||||
changeInt = getValueOperand(div.getRV(), findVal.getAnExpr(), _) and
|
||||
mayBeReturnValue(fn, changeInt)
|
||||
) and
|
||||
exp = div and
|
||||
msg =
|
||||
"Can lead to division by 0, since the function " + fn.getName() + " can return a value " +
|
||||
changeInt.toString() + "."
|
||||
or
|
||||
// Search for situations where division by zero is possible inside the `divFn` function if the passed argument can be equal to a certain value.
|
||||
exists(int posArg, Expr divVal, FunctionCall divFc, float changeInt2 |
|
||||
// Division is associated with the function argument.
|
||||
exists(Function divFn |
|
||||
divFn.getParameter(posArg).getAnAccess() = divVal and
|
||||
divVal.getEnclosingStmt() = div.getEnclosingStmt() and
|
||||
divFc = divFn.getACallToThisFunction()
|
||||
) and
|
||||
(
|
||||
divVal = div.getRV() and
|
||||
divFc.getArgument(posArg) != findVal.getAnExpr() and
|
||||
(
|
||||
// Function return value can be zero.
|
||||
mayBeReturnZero(fn) and
|
||||
getMulDivOperand(globalValueNumber(divFc.getArgument(posArg)).getAnExpr()) =
|
||||
findVal.getAnExpr() and
|
||||
changeInt = 0 and
|
||||
changeInt2 = 0
|
||||
or
|
||||
// Denominator can be sum or difference.
|
||||
changeInt = getValueOperand(divFc.getArgument(posArg), findVal.getAnExpr(), _) and
|
||||
mayBeReturnValue(fn, changeInt) and
|
||||
changeInt2 = 0
|
||||
)
|
||||
or
|
||||
// Look for a situation where the difference or subtraction is considered as an argument, and it can be used in the same way.
|
||||
changeInt = getValueOperand(div.getRV(), divVal, _) and
|
||||
changeInt2 = changeInt and
|
||||
mayBeReturnValue(fn, changeInt) and
|
||||
divFc.getArgument(posArg) = findVal.getAnExpr()
|
||||
) and
|
||||
checkConditions2(div, divVal, changeInt2) and
|
||||
checkConditions1(divFc, fn, changeInt) and
|
||||
exp = divFc and
|
||||
msg =
|
||||
"Can lead to division by 0, since the function " + fn.getName() + " can return a value " +
|
||||
changeInt.toString() + "."
|
||||
)
|
||||
)
|
||||
select exp, msg
|
||||
@@ -0,0 +1,27 @@
|
||||
| test.cpp:47:24:47:31 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:48:15:48:34 | ... / ... | Can lead to division by 0, since the function getSize2 can return a value 0. |
|
||||
| test.cpp:53:10:53:17 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:65:15:65:22 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:68:15:68:22 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:71:9:71:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:74:9:74:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:77:21:77:28 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:79:25:79:32 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:81:24:81:31 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:128:10:128:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:135:10:135:16 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:141:10:141:23 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:153:12:153:19 | ... / ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:172:3:172:12 | ... /= ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:173:3:173:12 | ... %= ... | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:187:10:187:17 | ... / ... | Can lead to division by 0, since the function getSizeFloat can return a value 0. |
|
||||
| test.cpp:199:12:199:25 | ... / ... | Can lead to division by 0, since the function getSize can return a value -1. |
|
||||
| test.cpp:202:12:202:25 | ... / ... | Can lead to division by 0, since the function getSize can return a value 1. |
|
||||
| test.cpp:205:10:205:23 | ... / ... | Can lead to division by 0, since the function getSize can return a value 1. |
|
||||
| test.cpp:210:10:210:23 | ... / ... | Can lead to division by 0, since the function getSize can return a value 3. |
|
||||
| test.cpp:258:3:258:10 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value 0. |
|
||||
| test.cpp:259:3:259:10 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value 2. |
|
||||
| test.cpp:260:3:260:13 | call to badMySubDiv | Can lead to division by 0, since the function getSize can return a value 3. |
|
||||
| test.cpp:263:5:263:15 | call to badMySubDiv | Can lead to division by 0, since the function getSize can return a value 3. |
|
||||
| test.cpp:273:5:273:12 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value 3. |
|
||||
| test.cpp:275:5:275:12 | call to badMyDiv | Can lead to division by 0, since the function getSize can return a value -1. |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-369/DivideByZeroUsingReturnValue.ql
|
||||
@@ -0,0 +1,278 @@
|
||||
typedef struct {}
|
||||
FILE;
|
||||
int getc(FILE * stream);
|
||||
|
||||
int getSize(int type) {
|
||||
int st;
|
||||
switch (type) {
|
||||
case 1:
|
||||
st = 1;
|
||||
break;
|
||||
case 2:
|
||||
st = 2;
|
||||
break;
|
||||
case 3:
|
||||
st = 3;
|
||||
break;
|
||||
case 4:
|
||||
st = -1;
|
||||
break;
|
||||
default:
|
||||
st = 0;
|
||||
break;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
int getSize2(int type) {
|
||||
int st = 0;
|
||||
switch (type) {
|
||||
case 1:
|
||||
st = 1;
|
||||
break;
|
||||
case 2:
|
||||
st = 2;
|
||||
break;
|
||||
case 3:
|
||||
st = 3;
|
||||
break;
|
||||
case 4:
|
||||
st = -1;
|
||||
break;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
int badTestf1(int type, int met) {
|
||||
int is = getSize(type);
|
||||
if (met == 1) return 123 / is; // BAD
|
||||
else return 123 / getSize2(type); // BAD
|
||||
}
|
||||
int badTestf2(int type) {
|
||||
int is;
|
||||
is = getSize(type);
|
||||
return 123 / is; // BAD
|
||||
}
|
||||
|
||||
int badTestf3(int type, int met) {
|
||||
int is;
|
||||
is = getSize(type);
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is >= 0) return 123 / is; // BAD [NOT DETECTED]
|
||||
case 2:
|
||||
if (0 == is) return 123 / is; // BAD [NOT DETECTED]
|
||||
case 3:
|
||||
if (!is & 123 / is) // BAD
|
||||
return 123;
|
||||
case 4:
|
||||
if (!is | 123 / is) // BAD
|
||||
return 123;
|
||||
case 5:
|
||||
if (123 / is || !is) // BAD
|
||||
return 123;
|
||||
case 6:
|
||||
if (123 / is && !is) // BAD
|
||||
return 123;
|
||||
case 7:
|
||||
if (!is) return 123 / is; // BAD
|
||||
case 8:
|
||||
if (is > -1) return 123 / is; // BAD
|
||||
case 9:
|
||||
if (is < 2) return 123 / is; // BAD
|
||||
}
|
||||
if (is != 0) return -1;
|
||||
if (is == 0) type += 1;
|
||||
return 123 / is; // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
int goodTestf3(int type, int met) {
|
||||
int is = getSize(type);
|
||||
if (is == 0) return -1;
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is < 0) return 123 / is; // GOOD
|
||||
case 2:
|
||||
if (!is && 123 / is) // GOOD
|
||||
return 123;
|
||||
case 3:
|
||||
if (!is || 123 / is) // GOOD
|
||||
return 123;
|
||||
case 8:
|
||||
if (is < -1) return 123 / is; // GOOD
|
||||
case 9:
|
||||
if (is > 2) return 123 / is; // GOOD
|
||||
}
|
||||
return 123 / is;
|
||||
}
|
||||
|
||||
int goodTestf3a(int type, int met) {
|
||||
int is = getSize(type);
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is < 0)
|
||||
return 123 / is; // GOOD
|
||||
case 2:
|
||||
if (!is && 123 / is) // GOOD
|
||||
return 123;
|
||||
case 3:
|
||||
if (!is || 123 / is) // GOOD
|
||||
return 123;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int badTestf4(int type) {
|
||||
int is = getSize(type);
|
||||
int d;
|
||||
d = type * is;
|
||||
return 123 / d; // BAD
|
||||
}
|
||||
|
||||
int badTestf5(int type) {
|
||||
int is = getSize(type);
|
||||
int d;
|
||||
d = is / type;
|
||||
return 123 / d; // BAD
|
||||
}
|
||||
int badTestf6(int type) {
|
||||
int is = getSize(type);
|
||||
int d;
|
||||
d = is / type;
|
||||
return type * 123 / d; // BAD
|
||||
}
|
||||
|
||||
int badTestf7(int type, int met) {
|
||||
int is = getSize(type);
|
||||
if (is == 0) goto quit;
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is < 0)
|
||||
return 123 / is; // GOOD
|
||||
}
|
||||
quit:
|
||||
return 123 / is; // BAD
|
||||
}
|
||||
|
||||
int goodTestf7(int type, int met) {
|
||||
int is = getSize(type);
|
||||
if (is == 0) goto quit2;
|
||||
if (is == 0.) return -1;
|
||||
switch (met) {
|
||||
case 1:
|
||||
if (is < 0.)
|
||||
return 123 / is; // GOOD
|
||||
}
|
||||
return 123 / is; // GOOD
|
||||
quit2:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int badTestf8(int type) {
|
||||
int is = getSize(type);
|
||||
type /= is; // BAD
|
||||
type %= is; // BAD
|
||||
return type;
|
||||
}
|
||||
|
||||
float getSizeFloat(float type) {
|
||||
float st;
|
||||
if (type)
|
||||
st = 1.0;
|
||||
else
|
||||
st = 0.0;
|
||||
return st;
|
||||
}
|
||||
float badTestf9(float type) {
|
||||
float is = getSizeFloat(type);
|
||||
return 123 / is; // BAD
|
||||
}
|
||||
float goodTestf9(float type) {
|
||||
float is = getSizeFloat(type);
|
||||
if (is == 0.0) return -1;
|
||||
return 123 / is; // GOOD
|
||||
}
|
||||
|
||||
int badTestf10(int type) {
|
||||
int out = type;
|
||||
int is = getSize(type);
|
||||
if (is > -2) {
|
||||
out /= 123 / (is + 1); // BAD
|
||||
}
|
||||
if (is > 0) {
|
||||
return 123 / (is - 1); // BAD
|
||||
}
|
||||
if (is <= 0) return 0;
|
||||
return 123 / (is - 1); // BAD
|
||||
return 0;
|
||||
}
|
||||
int badTestf11(int type) {
|
||||
int is = getSize(type);
|
||||
return 123 / (is - 3); // BAD
|
||||
}
|
||||
|
||||
int goodTestf11(int type) {
|
||||
int is = getSize(type);
|
||||
if (is > 1) {
|
||||
return 123 / (is - 1); // GOOD
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int badTestf12(FILE * f) {
|
||||
int a;
|
||||
int ret = -1;
|
||||
a = getc(f);
|
||||
if (a == 0) ret = 123 / a; // BAD [NOT DETECTED]
|
||||
return ret;
|
||||
}
|
||||
|
||||
int goodTestf12(FILE * f) {
|
||||
int a;
|
||||
int ret = -1;
|
||||
a = getc(f);
|
||||
if (a != 0) ret = 123 / a; // GOOD
|
||||
return ret;
|
||||
}
|
||||
|
||||
int badMyDiv(int type, int is) {
|
||||
type /= is;
|
||||
type %= is;
|
||||
return type;
|
||||
}
|
||||
|
||||
int goodMyDiv(int type, int is) {
|
||||
if (is == 0) return -1;
|
||||
type /= is;
|
||||
type %= is;
|
||||
return type;
|
||||
}
|
||||
int badMySubDiv(int type, int is) {
|
||||
type /= (is - 3);
|
||||
type %= (is + 1);
|
||||
return type;
|
||||
}
|
||||
|
||||
void badTestf13(int type) {
|
||||
int is = getSize(type);
|
||||
badMyDiv(type, is); // BAD
|
||||
badMyDiv(type, is - 2); // BAD
|
||||
badMySubDiv(type, is); // BAD
|
||||
goodMyDiv(type, is); // GOOD
|
||||
if (is < 5)
|
||||
badMySubDiv(type, is); // BAD
|
||||
if (is < 0)
|
||||
badMySubDiv(type, is); // BAD [NOT DETECTED]
|
||||
if (is > 5)
|
||||
badMySubDiv(type, is); // GOOD
|
||||
if (is == 0)
|
||||
badMyDiv(type, is); // BAD
|
||||
if (is > 0)
|
||||
badMyDiv(type, is); // GOOD
|
||||
if (is < 5)
|
||||
badMyDiv(type, is - 3); // BAD
|
||||
if (is < 0)
|
||||
badMyDiv(type, is + 1); // BAD
|
||||
if (is > 5)
|
||||
badMyDiv(type, is - 3); // GOOD
|
||||
}
|
||||
@@ -10,6 +10,8 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
private Conversion(Context cx, IMethodSymbol init)
|
||||
: base(cx, init) { }
|
||||
|
||||
protected override MethodKind ExplicitlyImplementsKind => MethodKind.Conversion;
|
||||
|
||||
public static new Conversion Create(Context cx, IMethodSymbol symbol) =>
|
||||
ConversionFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
|
||||
@@ -83,10 +83,12 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual MethodKind ExplicitlyImplementsKind => MethodKind.Ordinary;
|
||||
|
||||
public void Overrides(TextWriter trapFile)
|
||||
{
|
||||
foreach (var explicitInterface in Symbol.ExplicitInterfaceImplementations
|
||||
.Where(sym => sym.MethodKind == MethodKind.Ordinary)
|
||||
.Where(sym => sym.MethodKind == ExplicitlyImplementsKind)
|
||||
.Select(impl => Type.Create(Context, impl.ContainingType)))
|
||||
{
|
||||
trapFile.explicitly_implements(this, explicitInterface.TypeRef);
|
||||
|
||||
@@ -85,6 +85,9 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
if (nt.IsRecord)
|
||||
HasModifier(cx, trapFile, key, Modifiers.Record);
|
||||
|
||||
if (nt.IsFileLocal)
|
||||
HasModifier(cx, trapFile, key, Modifiers.File);
|
||||
|
||||
if (nt.TypeKind == TypeKind.Struct)
|
||||
{
|
||||
if (nt.IsReadOnly)
|
||||
@@ -97,7 +100,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public static void ExtractModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol)
|
||||
{
|
||||
HasAccessibility(cx, trapFile, key, symbol.DeclaredAccessibility);
|
||||
// A file scoped type has declared accessibility `internal` which we shouldn't extract.
|
||||
// The file modifier is extracted as a source level modifier.
|
||||
if (symbol.Kind != SymbolKind.NamedType || !((INamedTypeSymbol)symbol).IsFileLocal)
|
||||
HasAccessibility(cx, trapFile, key, symbol.DeclaredAccessibility);
|
||||
|
||||
if (symbol.Kind == SymbolKind.ErrorType)
|
||||
trapFile.has_modifiers(key, Modifier.Create(cx, Accessibility.Public));
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ internal static class Modifiers
|
||||
public const string Async = "async";
|
||||
public const string Const = "const";
|
||||
public const string Extern = "extern";
|
||||
public const string File = "file";
|
||||
public const string Internal = "internal";
|
||||
public const string New = "new";
|
||||
public const string Override = "override";
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
protected UserOperator(Context cx, IMethodSymbol init)
|
||||
: base(cx, init) { }
|
||||
|
||||
protected override MethodKind ExplicitlyImplementsKind => MethodKind.UserDefinedOperator;
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
PopulateMethod(trapFile);
|
||||
@@ -37,6 +39,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
|
||||
ContainingType.PopulateGenerics();
|
||||
Overrides(trapFile);
|
||||
}
|
||||
|
||||
public override bool NeedsPopulation => Context.Defines(Symbol) || IsImplicitOperator(out _);
|
||||
|
||||
@@ -282,54 +282,60 @@ namespace Semmle.Extraction.CSharp
|
||||
public static IEnumerable<IFieldSymbol?> GetTupleElementsMaybeNull(this INamedTypeSymbol type) =>
|
||||
type.TupleElements;
|
||||
|
||||
private static void BuildQualifierAndName(INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined)
|
||||
{
|
||||
if (named.ContainingType is not null)
|
||||
{
|
||||
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
else if (named.ContainingNamespace is not null)
|
||||
{
|
||||
if (cx.ShouldAddAssemblyTrapPrefix && named.ContainingAssembly is not null)
|
||||
BuildAssembly(named.ContainingAssembly, trapFile);
|
||||
named.ContainingNamespace.BuildNamespace(cx, trapFile);
|
||||
}
|
||||
|
||||
var name = named.IsFileLocal ? named.MetadataName : named.Name;
|
||||
trapFile.Write(name);
|
||||
}
|
||||
|
||||
private static void BuildTupleId(INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined)
|
||||
{
|
||||
trapFile.Write('(');
|
||||
trapFile.BuildList(",", named.GetTupleElementsMaybeNull(),
|
||||
(i, f) =>
|
||||
{
|
||||
if (f is null)
|
||||
{
|
||||
trapFile.Write($"null({i})");
|
||||
}
|
||||
else
|
||||
{
|
||||
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
|
||||
trapFile.Write(":");
|
||||
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
}
|
||||
}
|
||||
);
|
||||
trapFile.Write(")");
|
||||
}
|
||||
|
||||
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
|
||||
{
|
||||
if (!constructUnderlyingTupleType && named.IsTupleType)
|
||||
{
|
||||
trapFile.Write('(');
|
||||
trapFile.BuildList(",", named.GetTupleElementsMaybeNull(),
|
||||
(i, f) =>
|
||||
{
|
||||
if (f is null)
|
||||
{
|
||||
trapFile.Write($"null({i})");
|
||||
}
|
||||
else
|
||||
{
|
||||
trapFile.Write((f.CorrespondingTupleField ?? f).Name);
|
||||
trapFile.Write(":");
|
||||
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
}
|
||||
}
|
||||
);
|
||||
trapFile.Write(")");
|
||||
BuildTupleId(named, cx, trapFile, symbolBeingDefined);
|
||||
return;
|
||||
}
|
||||
|
||||
void AddContaining()
|
||||
{
|
||||
if (named.ContainingType is not null)
|
||||
{
|
||||
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
else if (named.ContainingNamespace is not null)
|
||||
{
|
||||
if (cx.ShouldAddAssemblyTrapPrefix && named.ContainingAssembly is not null)
|
||||
BuildAssembly(named.ContainingAssembly, trapFile);
|
||||
named.ContainingNamespace.BuildNamespace(cx, trapFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (named.TypeParameters.IsEmpty)
|
||||
{
|
||||
AddContaining();
|
||||
trapFile.Write(named.Name);
|
||||
BuildQualifierAndName(named, cx, trapFile, symbolBeingDefined);
|
||||
}
|
||||
else if (named.IsReallyUnbound())
|
||||
{
|
||||
AddContaining();
|
||||
trapFile.Write(named.Name);
|
||||
BuildQualifierAndName(named, cx, trapFile, symbolBeingDefined);
|
||||
trapFile.Write("`");
|
||||
trapFile.Write(named.TypeParameters.Length);
|
||||
}
|
||||
|
||||
4
csharp/ql/lib/change-notes/2023-02-17-filescopedtypes.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C# 11: Added extractor and library support for `file` scoped types.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C# 11: Support for explicit interface member implementation of operators.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `cs/static-field-written-by-instance` is updated to handle properties.
|
||||
@@ -434,7 +434,7 @@ class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @de
|
||||
* Either a unary operator (`UnaryOperator`), a binary operator
|
||||
* (`BinaryOperator`), or a conversion operator (`ConversionOperator`).
|
||||
*/
|
||||
class Operator extends Callable, Member, Attributable, @operator {
|
||||
class Operator extends Callable, Member, Attributable, Overridable, @operator {
|
||||
/**
|
||||
* DEPRECATED: use `getFunctionName()` instead.
|
||||
*
|
||||
|
||||
@@ -93,6 +93,9 @@ class Modifiable extends Declaration, @modifiable {
|
||||
/** Holds if this declaration has the modifier `required`. */
|
||||
predicate isRequired() { this.hasModifier("required") }
|
||||
|
||||
/** Holds if this declaration is `file` local. */
|
||||
predicate isFile() { this.hasModifier("file") }
|
||||
|
||||
/** Holds if this declaration is `unsafe`. */
|
||||
predicate isUnsafe() {
|
||||
this.hasModifier("unsafe") or
|
||||
@@ -183,6 +186,8 @@ class Member extends DotNet::Member, Modifiable, @member {
|
||||
override predicate isStatic() { Modifiable.super.isStatic() }
|
||||
|
||||
override predicate isRequired() { Modifiable.super.isRequired() }
|
||||
|
||||
override predicate isFile() { Modifiable.super.isFile() }
|
||||
}
|
||||
|
||||
private class TOverridable = @virtualizable or @callable_accessor;
|
||||
|
||||
@@ -137,6 +137,8 @@ private class RecordConstructorFlow extends SummarizedCallable {
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasProvenance(string provenance) { provenance = "manual" }
|
||||
}
|
||||
|
||||
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
|
||||
|
||||
@@ -248,7 +248,9 @@ module Public {
|
||||
/**
|
||||
* Holds if all the summaries that apply to `this` are auto generated and not manually created.
|
||||
*/
|
||||
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
|
||||
final predicate isAutoGenerated() {
|
||||
this.hasProvenance(["generated", "ai-generated"]) and not this.isManual()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a manual summary that applies to `this`.
|
||||
@@ -268,7 +270,7 @@ module Public {
|
||||
/**
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { neutralElement(this, "generated") }
|
||||
predicate isAutoGenerated() { neutralElement(this, ["generated", "ai-generated"]) }
|
||||
|
||||
/**
|
||||
* Holds if there exists a manual neutral that applies to `this`.
|
||||
@@ -1202,11 +1204,11 @@ module Private {
|
||||
}
|
||||
|
||||
private string renderProvenance(SummarizedCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
if c.isManual() then result = "manual" else c.hasProvenance(result)
|
||||
}
|
||||
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
if c.isManual() then result = "manual" else c.hasProvenance(result)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -86,6 +86,8 @@ module EntityFramework {
|
||||
abstract class EFSummarizedCallable extends SummarizedCallable {
|
||||
bindingset[this]
|
||||
EFSummarizedCallable() { any() }
|
||||
|
||||
override predicate hasProvenance(string provenance) { provenance = "manual" }
|
||||
}
|
||||
|
||||
private class DbSetAddOrUpdateRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
|
||||
|
||||
@@ -83,6 +83,9 @@ class Member extends Declaration, @dotnet_member {
|
||||
/** Holds if this member is declared `required`. */
|
||||
predicate isRequired() { none() }
|
||||
|
||||
/** Holds if this member is declared `file` local. */
|
||||
predicate isFile() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this member has name `name` and is defined in type `type`
|
||||
* with namespace `namespace`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @name Static field written by instance method
|
||||
* @description Finds instance methods that write static fields.
|
||||
* @description Finds instance methods and properties that write to static fields.
|
||||
* This is tricky to get right if multiple instances are being manipulated,
|
||||
* and generally bad practice.
|
||||
* @kind problem
|
||||
@@ -14,12 +14,12 @@
|
||||
|
||||
import csharp
|
||||
|
||||
from FieldWrite fw, Field f, Callable m
|
||||
from FieldWrite fw, Field f, Callable c
|
||||
where
|
||||
fw.getTarget() = f and
|
||||
f.isStatic() and
|
||||
m = fw.getEnclosingCallable() and
|
||||
not m.(Member).isStatic() and
|
||||
f.getDeclaringType() = m.getDeclaringType() and
|
||||
m.fromSource()
|
||||
select fw.(VariableAccess), "Write to static field from instance method or constructor."
|
||||
c = fw.getEnclosingCallable() and
|
||||
not [c.(Member), c.(Accessor).getDeclaration()].isStatic() and
|
||||
f.getDeclaringType() = c.getDeclaringType() and
|
||||
c.fromSource()
|
||||
select fw.(VariableAccess), "Write to static field from instance method, property, or constructor."
|
||||
|
||||
25
csharp/ql/test/library-tests/csharp11/FileScoped1.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
file interface I1 { }
|
||||
|
||||
file interface I2 { }
|
||||
|
||||
file class C1 : I1 { }
|
||||
|
||||
public class C2 { }
|
||||
|
||||
public class C3 : I2 { }
|
||||
|
||||
file interface IC { }
|
||||
|
||||
file class C4<T> { }
|
||||
|
||||
file class C5<S> : C4<S> { }
|
||||
|
||||
file struct S1 { }
|
||||
|
||||
file enum E1 { }
|
||||
|
||||
file delegate void D1();
|
||||
|
||||
file record R1 { }
|
||||
|
||||
file record struct RS1 { }
|
||||
23
csharp/ql/test/library-tests/csharp11/FileScoped2.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
file interface I1 { }
|
||||
|
||||
public interface I2 { }
|
||||
|
||||
file class C1 { }
|
||||
|
||||
file class C2 : I2 { }
|
||||
|
||||
file class IC { }
|
||||
|
||||
file class C4<T> { }
|
||||
|
||||
file class C5<S> : C4<S> { }
|
||||
|
||||
file struct S1 { }
|
||||
|
||||
file enum E1 { }
|
||||
|
||||
file delegate void D1();
|
||||
|
||||
file record R1 { }
|
||||
|
||||
file record struct RS1 { }
|
||||
7
csharp/ql/test/library-tests/csharp11/FileScoped3.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace TestFileScoped;
|
||||
|
||||
file interface I10 { }
|
||||
|
||||
file class C10 { }
|
||||
|
||||
public class C11 : I10 { }
|
||||
7
csharp/ql/test/library-tests/csharp11/FileScoped4.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace TestFileScoped;
|
||||
|
||||
public interface I10 { }
|
||||
|
||||
file class C10 { }
|
||||
|
||||
file class C11 : I10 { }
|
||||
@@ -216,6 +216,103 @@ CheckedOperators.cs:
|
||||
# 55| 0: [TypeMention] short
|
||||
# 55| 1: [PropertyCall] access to property Value
|
||||
# 55| -1: [ParameterAccess] access to parameter n
|
||||
FileScoped1.cs:
|
||||
# 1| [Interface] I1
|
||||
# 3| [Interface] I2
|
||||
# 5| [Class] C1
|
||||
#-----| 3: (Base types)
|
||||
# 5| 1: [TypeMention] I1
|
||||
# 7| [Class] C2
|
||||
# 9| [Class] C3
|
||||
#-----| 3: (Base types)
|
||||
# 9| 1: [TypeMention] I2
|
||||
# 11| [Interface] IC
|
||||
# 13| [Class] C4<>
|
||||
#-----| 1: (Type parameters)
|
||||
# 13| 0: [TypeParameter] T
|
||||
# 15| [Class] C5<>
|
||||
#-----| 1: (Type parameters)
|
||||
# 15| 0: [TypeParameter] S
|
||||
#-----| 3: (Base types)
|
||||
# 15| 0: [TypeMention] C4<S>
|
||||
# 15| 1: [TypeMention] S
|
||||
# 17| [Struct] S1
|
||||
# 19| [Enum] E1
|
||||
# 21| [DelegateType] D1
|
||||
# 23| [RecordClass] R1
|
||||
# 23| 12: [NEOperator] !=
|
||||
#-----| 2: (Parameters)
|
||||
# 23| 0: [Parameter] left
|
||||
# 23| 1: [Parameter] right
|
||||
# 23| 13: [EQOperator] ==
|
||||
#-----| 2: (Parameters)
|
||||
# 23| 0: [Parameter] left
|
||||
# 23| 1: [Parameter] right
|
||||
# 23| 14: [Property] EqualityContract
|
||||
# 23| 3: [Getter] get_EqualityContract
|
||||
# 25| [RecordStruct] RS1
|
||||
# 25| 10: [NEOperator] !=
|
||||
#-----| 2: (Parameters)
|
||||
# 25| 0: [Parameter] left
|
||||
# 25| 1: [Parameter] right
|
||||
# 25| 11: [EQOperator] ==
|
||||
#-----| 2: (Parameters)
|
||||
# 25| 0: [Parameter] left
|
||||
# 25| 1: [Parameter] right
|
||||
FileScoped2.cs:
|
||||
# 1| [Interface] I1
|
||||
# 3| [Interface] I2
|
||||
# 5| [Class] C1
|
||||
# 7| [Class] C2
|
||||
#-----| 3: (Base types)
|
||||
# 7| 1: [TypeMention] I2
|
||||
# 9| [Class] IC
|
||||
# 11| [Class] C4<>
|
||||
#-----| 1: (Type parameters)
|
||||
# 11| 0: [TypeParameter] T
|
||||
# 13| [Class] C5<>
|
||||
#-----| 1: (Type parameters)
|
||||
# 13| 0: [TypeParameter] S
|
||||
#-----| 3: (Base types)
|
||||
# 13| 0: [TypeMention] C4<S>
|
||||
# 13| 1: [TypeMention] S
|
||||
# 15| [Struct] S1
|
||||
# 17| [Enum] E1
|
||||
# 19| [DelegateType] D1
|
||||
# 21| [RecordClass] R1
|
||||
# 21| 12: [NEOperator] !=
|
||||
#-----| 2: (Parameters)
|
||||
# 21| 0: [Parameter] left
|
||||
# 21| 1: [Parameter] right
|
||||
# 21| 13: [EQOperator] ==
|
||||
#-----| 2: (Parameters)
|
||||
# 21| 0: [Parameter] left
|
||||
# 21| 1: [Parameter] right
|
||||
# 21| 14: [Property] EqualityContract
|
||||
# 21| 3: [Getter] get_EqualityContract
|
||||
# 23| [RecordStruct] RS1
|
||||
# 23| 10: [NEOperator] !=
|
||||
#-----| 2: (Parameters)
|
||||
# 23| 0: [Parameter] left
|
||||
# 23| 1: [Parameter] right
|
||||
# 23| 11: [EQOperator] ==
|
||||
#-----| 2: (Parameters)
|
||||
# 23| 0: [Parameter] left
|
||||
# 23| 1: [Parameter] right
|
||||
FileScoped3.cs:
|
||||
# 1| [NamespaceDeclaration] namespace ... { ... }
|
||||
# 3| 1: [Interface] I10
|
||||
# 5| 2: [Class] C10
|
||||
# 7| 3: [Class] C11
|
||||
#-----| 3: (Base types)
|
||||
# 7| 1: [TypeMention] I10
|
||||
FileScoped4.cs:
|
||||
# 1| [NamespaceDeclaration] namespace ... { ... }
|
||||
# 3| 1: [Interface] I10
|
||||
# 5| 2: [Class] C10
|
||||
# 7| 3: [Class] C11
|
||||
#-----| 3: (Base types)
|
||||
# 7| 1: [TypeMention] I10
|
||||
GenericAttribute.cs:
|
||||
# 3| [GenericAssemblyAttribute] [assembly: MyGeneric<Int32>(...)]
|
||||
# 3| 0: [TypeMention] MyGenericAttribute<int>
|
||||
@@ -954,14 +1051,14 @@ StaticInterfaceMembers.cs:
|
||||
# 5| 0: [Parameter] other
|
||||
# 5| -1: [TypeMention] T
|
||||
# 5| 4: [ParameterAccess] access to parameter other
|
||||
# 7| 6: [Method] Add
|
||||
# 7| 6: [AddOperator] +
|
||||
# 7| -1: [TypeMention] T
|
||||
#-----| 2: (Parameters)
|
||||
# 7| 0: [Parameter] left
|
||||
# 7| -1: [TypeMention] T
|
||||
# 7| 1: [Parameter] right
|
||||
# 7| -1: [TypeMention] T
|
||||
# 9| 7: [Method] Subtract
|
||||
# 9| 7: [SubOperator] -
|
||||
# 9| -1: [TypeMention] T
|
||||
#-----| 2: (Parameters)
|
||||
# 9| 0: [Parameter] left
|
||||
@@ -969,121 +1066,265 @@ StaticInterfaceMembers.cs:
|
||||
# 9| 1: [Parameter] right
|
||||
# 9| -1: [TypeMention] T
|
||||
# 9| 4: [ParameterAccess] access to parameter left
|
||||
# 11| 8: [Method] Zero
|
||||
# 11| -1: [TypeMention] T
|
||||
# 11| 4: [DefaultValueExpr] default(...)
|
||||
# 11| 0: [TypeAccess] access to type T
|
||||
# 11| 0: [TypeMention] T
|
||||
# 14| [Class] Complex
|
||||
# 11| 8: [ExplicitConversionOperator] explicit conversion
|
||||
# 11| -1: [TypeMention] int
|
||||
#-----| 2: (Parameters)
|
||||
# 11| 0: [Parameter] n
|
||||
# 11| -1: [TypeMention] T
|
||||
# 13| 9: [ExplicitConversionOperator] explicit conversion
|
||||
# 13| -1: [TypeMention] short
|
||||
#-----| 2: (Parameters)
|
||||
# 13| 0: [Parameter] n
|
||||
# 13| -1: [TypeMention] T
|
||||
# 15| 10: [Method] Inc
|
||||
# 15| -1: [TypeMention] T
|
||||
#-----| 2: (Parameters)
|
||||
# 15| 0: [Parameter] other
|
||||
# 15| -1: [TypeMention] T
|
||||
# 17| 11: [Method] Dec
|
||||
# 17| -1: [TypeMention] T
|
||||
#-----| 2: (Parameters)
|
||||
# 17| 0: [Parameter] other
|
||||
# 17| -1: [TypeMention] T
|
||||
# 17| 4: [ParameterAccess] access to parameter other
|
||||
# 19| 12: [Method] Add
|
||||
# 19| -1: [TypeMention] T
|
||||
#-----| 2: (Parameters)
|
||||
# 19| 0: [Parameter] left
|
||||
# 19| -1: [TypeMention] T
|
||||
# 19| 1: [Parameter] right
|
||||
# 19| -1: [TypeMention] T
|
||||
# 21| 13: [Method] Subtract
|
||||
# 21| -1: [TypeMention] T
|
||||
#-----| 2: (Parameters)
|
||||
# 21| 0: [Parameter] left
|
||||
# 21| -1: [TypeMention] T
|
||||
# 21| 1: [Parameter] right
|
||||
# 21| -1: [TypeMention] T
|
||||
# 21| 4: [ParameterAccess] access to parameter left
|
||||
# 23| 14: [Method] Zero
|
||||
# 23| -1: [TypeMention] T
|
||||
# 23| 4: [DefaultValueExpr] default(...)
|
||||
# 23| 0: [TypeAccess] access to type T
|
||||
# 23| 0: [TypeMention] T
|
||||
# 26| [Class] Complex
|
||||
#-----| 3: (Base types)
|
||||
# 16| 4: [Property] Real
|
||||
# 16| -1: [TypeMention] double
|
||||
# 16| 2: [AssignExpr] ... = ...
|
||||
# 16| 0: [PropertyCall] access to property Real
|
||||
# 16| 1: [DoubleLiteral] 0
|
||||
# 16| 3: [Getter] get_Real
|
||||
# 16| 4: [Setter] set_Real
|
||||
# 28| 4: [Property] Real
|
||||
# 28| -1: [TypeMention] double
|
||||
# 28| 2: [AssignExpr] ... = ...
|
||||
# 28| 0: [PropertyCall] access to property Real
|
||||
# 28| 1: [DoubleLiteral] 0
|
||||
# 28| 3: [Getter] get_Real
|
||||
# 28| 4: [Setter] set_Real
|
||||
#-----| 2: (Parameters)
|
||||
# 16| 0: [Parameter] value
|
||||
# 17| 5: [Property] Imaginary
|
||||
# 17| -1: [TypeMention] double
|
||||
# 17| 2: [AssignExpr] ... = ...
|
||||
# 17| 0: [PropertyCall] access to property Imaginary
|
||||
# 17| 1: [DoubleLiteral] 0
|
||||
# 17| 3: [Getter] get_Imaginary
|
||||
# 17| 4: [Setter] set_Imaginary
|
||||
# 28| 0: [Parameter] value
|
||||
# 29| 5: [Property] Imaginary
|
||||
# 29| -1: [TypeMention] double
|
||||
# 29| 2: [AssignExpr] ... = ...
|
||||
# 29| 0: [PropertyCall] access to property Imaginary
|
||||
# 29| 1: [DoubleLiteral] 0
|
||||
# 29| 3: [Getter] get_Imaginary
|
||||
# 29| 4: [Setter] set_Imaginary
|
||||
#-----| 2: (Parameters)
|
||||
# 17| 0: [Parameter] value
|
||||
# 19| 6: [InstanceConstructor] Complex
|
||||
# 19| 4: [BlockStmt] {...}
|
||||
# 21| 7: [Method] Zero
|
||||
# 21| -1: [TypeMention] Complex
|
||||
# 21| 4: [ObjectCreation] object creation of type Complex
|
||||
# 21| 0: [TypeMention] Complex
|
||||
# 23| 8: [IncrementOperator] ++
|
||||
# 23| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 23| 0: [Parameter] other
|
||||
# 23| -1: [TypeMention] Complex
|
||||
# 24| 4: [ObjectCreation] object creation of type Complex
|
||||
# 24| -2: [TypeMention] Complex
|
||||
# 24| -1: [ObjectInitializer] { ..., ... }
|
||||
# 24| 0: [MemberInitializer] ... = ...
|
||||
# 24| 0: [PropertyCall] access to property Real
|
||||
# 24| 1: [AddExpr] ... + ...
|
||||
# 24| 0: [PropertyCall] access to property Real
|
||||
# 24| -1: [ParameterAccess] access to parameter other
|
||||
# 24| 1: [DoubleLiteral] 1
|
||||
# 24| 1: [MemberInitializer] ... = ...
|
||||
# 24| 0: [PropertyCall] access to property Imaginary
|
||||
# 24| 1: [PropertyCall] access to property Imaginary
|
||||
# 24| -1: [ParameterAccess] access to parameter other
|
||||
# 26| 9: [DecrementOperator] --
|
||||
# 26| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 26| 0: [Parameter] other
|
||||
# 26| -1: [TypeMention] Complex
|
||||
# 27| 4: [ObjectCreation] object creation of type Complex
|
||||
# 27| -2: [TypeMention] Complex
|
||||
# 27| -1: [ObjectInitializer] { ..., ... }
|
||||
# 27| 0: [MemberInitializer] ... = ...
|
||||
# 27| 0: [PropertyCall] access to property Real
|
||||
# 27| 1: [SubExpr] ... - ...
|
||||
# 27| 0: [PropertyCall] access to property Real
|
||||
# 27| -1: [ParameterAccess] access to parameter other
|
||||
# 27| 1: [DoubleLiteral] 1
|
||||
# 27| 1: [MemberInitializer] ... = ...
|
||||
# 27| 0: [PropertyCall] access to property Imaginary
|
||||
# 27| 1: [PropertyCall] access to property Imaginary
|
||||
# 27| -1: [ParameterAccess] access to parameter other
|
||||
# 29| 10: [Method] Add
|
||||
# 29| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 29| 0: [Parameter] left
|
||||
# 29| -1: [TypeMention] Complex
|
||||
# 29| 1: [Parameter] right
|
||||
# 29| -1: [TypeMention] Complex
|
||||
# 30| 4: [ObjectCreation] object creation of type Complex
|
||||
# 30| -2: [TypeMention] Complex
|
||||
# 30| -1: [ObjectInitializer] { ..., ... }
|
||||
# 30| 0: [MemberInitializer] ... = ...
|
||||
# 30| 0: [PropertyCall] access to property Real
|
||||
# 30| 1: [AddExpr] ... + ...
|
||||
# 30| 0: [PropertyCall] access to property Real
|
||||
# 30| -1: [ParameterAccess] access to parameter left
|
||||
# 30| 1: [PropertyCall] access to property Real
|
||||
# 30| -1: [ParameterAccess] access to parameter right
|
||||
# 30| 1: [MemberInitializer] ... = ...
|
||||
# 30| 0: [PropertyCall] access to property Imaginary
|
||||
# 30| 1: [AddExpr] ... + ...
|
||||
# 30| 0: [PropertyCall] access to property Imaginary
|
||||
# 30| -1: [ParameterAccess] access to parameter left
|
||||
# 30| 1: [PropertyCall] access to property Imaginary
|
||||
# 30| -1: [ParameterAccess] access to parameter right
|
||||
# 32| 11: [Method] Subtract
|
||||
# 32| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 32| 0: [Parameter] left
|
||||
# 32| -1: [TypeMention] Complex
|
||||
# 32| 1: [Parameter] right
|
||||
# 32| -1: [TypeMention] Complex
|
||||
# 29| 0: [Parameter] value
|
||||
# 31| 6: [InstanceConstructor] Complex
|
||||
# 31| 4: [BlockStmt] {...}
|
||||
# 33| 7: [Method] Zero
|
||||
# 33| -1: [TypeMention] Complex
|
||||
# 33| 4: [ObjectCreation] object creation of type Complex
|
||||
# 33| -2: [TypeMention] Complex
|
||||
# 33| -1: [ObjectInitializer] { ..., ... }
|
||||
# 33| 0: [MemberInitializer] ... = ...
|
||||
# 33| 0: [PropertyCall] access to property Real
|
||||
# 33| 1: [SubExpr] ... - ...
|
||||
# 33| 0: [PropertyCall] access to property Real
|
||||
# 33| -1: [ParameterAccess] access to parameter left
|
||||
# 33| 1: [PropertyCall] access to property Real
|
||||
# 33| -1: [ParameterAccess] access to parameter right
|
||||
# 33| 1: [MemberInitializer] ... = ...
|
||||
# 33| 0: [PropertyCall] access to property Imaginary
|
||||
# 33| 1: [SubExpr] ... - ...
|
||||
# 33| 0: [PropertyCall] access to property Imaginary
|
||||
# 33| -1: [ParameterAccess] access to parameter left
|
||||
# 33| 1: [PropertyCall] access to property Imaginary
|
||||
# 33| -1: [ParameterAccess] access to parameter right
|
||||
# 33| 0: [TypeMention] Complex
|
||||
# 35| 8: [IncrementOperator] ++
|
||||
# 35| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 35| 0: [Parameter] other
|
||||
# 35| -1: [TypeMention] Complex
|
||||
# 36| 4: [ObjectCreation] object creation of type Complex
|
||||
# 36| -2: [TypeMention] Complex
|
||||
# 36| -1: [ObjectInitializer] { ..., ... }
|
||||
# 36| 0: [MemberInitializer] ... = ...
|
||||
# 36| 0: [PropertyCall] access to property Real
|
||||
# 36| 1: [AddExpr] ... + ...
|
||||
# 36| 0: [PropertyCall] access to property Real
|
||||
# 36| -1: [ParameterAccess] access to parameter other
|
||||
# 36| 1: [DoubleLiteral] 1
|
||||
# 36| 1: [MemberInitializer] ... = ...
|
||||
# 36| 0: [PropertyCall] access to property Imaginary
|
||||
# 36| 1: [PropertyCall] access to property Imaginary
|
||||
# 36| -1: [ParameterAccess] access to parameter other
|
||||
# 38| 9: [DecrementOperator] --
|
||||
# 38| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 38| 0: [Parameter] other
|
||||
# 38| -1: [TypeMention] Complex
|
||||
# 39| 4: [ObjectCreation] object creation of type Complex
|
||||
# 39| -2: [TypeMention] Complex
|
||||
# 39| -1: [ObjectInitializer] { ..., ... }
|
||||
# 39| 0: [MemberInitializer] ... = ...
|
||||
# 39| 0: [PropertyCall] access to property Real
|
||||
# 39| 1: [SubExpr] ... - ...
|
||||
# 39| 0: [PropertyCall] access to property Real
|
||||
# 39| -1: [ParameterAccess] access to parameter other
|
||||
# 39| 1: [DoubleLiteral] 1
|
||||
# 39| 1: [MemberInitializer] ... = ...
|
||||
# 39| 0: [PropertyCall] access to property Imaginary
|
||||
# 39| 1: [PropertyCall] access to property Imaginary
|
||||
# 39| -1: [ParameterAccess] access to parameter other
|
||||
# 41| 10: [AddOperator] +
|
||||
# 41| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 41| 0: [Parameter] left
|
||||
# 41| -1: [TypeMention] Complex
|
||||
# 41| 1: [Parameter] right
|
||||
# 41| -1: [TypeMention] Complex
|
||||
# 42| 4: [ObjectCreation] object creation of type Complex
|
||||
# 42| -2: [TypeMention] Complex
|
||||
# 42| -1: [ObjectInitializer] { ..., ... }
|
||||
# 42| 0: [MemberInitializer] ... = ...
|
||||
# 42| 0: [PropertyCall] access to property Real
|
||||
# 42| 1: [AddExpr] ... + ...
|
||||
# 42| 0: [PropertyCall] access to property Real
|
||||
# 42| -1: [ParameterAccess] access to parameter left
|
||||
# 42| 1: [PropertyCall] access to property Real
|
||||
# 42| -1: [ParameterAccess] access to parameter right
|
||||
# 42| 1: [MemberInitializer] ... = ...
|
||||
# 42| 0: [PropertyCall] access to property Imaginary
|
||||
# 42| 1: [AddExpr] ... + ...
|
||||
# 42| 0: [PropertyCall] access to property Imaginary
|
||||
# 42| -1: [ParameterAccess] access to parameter left
|
||||
# 42| 1: [PropertyCall] access to property Imaginary
|
||||
# 42| -1: [ParameterAccess] access to parameter right
|
||||
# 44| 11: [SubOperator] -
|
||||
# 44| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 44| 0: [Parameter] left
|
||||
# 44| -1: [TypeMention] Complex
|
||||
# 44| 1: [Parameter] right
|
||||
# 44| -1: [TypeMention] Complex
|
||||
# 45| 4: [ObjectCreation] object creation of type Complex
|
||||
# 45| -2: [TypeMention] Complex
|
||||
# 45| -1: [ObjectInitializer] { ..., ... }
|
||||
# 45| 0: [MemberInitializer] ... = ...
|
||||
# 45| 0: [PropertyCall] access to property Real
|
||||
# 45| 1: [SubExpr] ... - ...
|
||||
# 45| 0: [PropertyCall] access to property Real
|
||||
# 45| -1: [ParameterAccess] access to parameter left
|
||||
# 45| 1: [PropertyCall] access to property Real
|
||||
# 45| -1: [ParameterAccess] access to parameter right
|
||||
# 45| 1: [MemberInitializer] ... = ...
|
||||
# 45| 0: [PropertyCall] access to property Imaginary
|
||||
# 45| 1: [SubExpr] ... - ...
|
||||
# 45| 0: [PropertyCall] access to property Imaginary
|
||||
# 45| -1: [ParameterAccess] access to parameter left
|
||||
# 45| 1: [PropertyCall] access to property Imaginary
|
||||
# 45| -1: [ParameterAccess] access to parameter right
|
||||
# 47| 12: [ExplicitConversionOperator] explicit conversion
|
||||
# 47| -1: [TypeMention] int
|
||||
#-----| 2: (Parameters)
|
||||
# 47| 0: [Parameter] n
|
||||
# 47| -1: [TypeMention] Complex
|
||||
# 47| 4: [CastExpr] (...) ...
|
||||
# 47| 0: [TypeAccess] access to type Int32
|
||||
# 47| 0: [TypeMention] int
|
||||
# 47| 1: [PropertyCall] access to property Real
|
||||
# 47| -1: [ParameterAccess] access to parameter n
|
||||
# 49| 13: [ExplicitConversionOperator] explicit conversion
|
||||
# 49| -1: [TypeMention] short
|
||||
#-----| 2: (Parameters)
|
||||
# 49| 0: [Parameter] n
|
||||
# 49| -1: [TypeMention] Complex
|
||||
# 49| 4: [CastExpr] (...) ...
|
||||
# 49| 0: [TypeAccess] access to type Int16
|
||||
# 49| 0: [TypeMention] short
|
||||
# 49| 1: [PropertyCall] access to property Real
|
||||
# 49| -1: [ParameterAccess] access to parameter n
|
||||
# 51| 14: [Method] Inc
|
||||
# 51| -1: [TypeMention] Complex
|
||||
# 51| -1: [TypeMention] INumber<Complex>
|
||||
# 51| 1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 51| 0: [Parameter] other
|
||||
# 51| -1: [TypeMention] Complex
|
||||
# 52| 4: [ObjectCreation] object creation of type Complex
|
||||
# 52| -2: [TypeMention] Complex
|
||||
# 52| -1: [ObjectInitializer] { ..., ... }
|
||||
# 52| 0: [MemberInitializer] ... = ...
|
||||
# 52| 0: [PropertyCall] access to property Real
|
||||
# 52| 1: [AddExpr] ... + ...
|
||||
# 52| 0: [PropertyCall] access to property Real
|
||||
# 52| -1: [ParameterAccess] access to parameter other
|
||||
# 52| 1: [DoubleLiteral] 1
|
||||
# 52| 1: [MemberInitializer] ... = ...
|
||||
# 52| 0: [PropertyCall] access to property Imaginary
|
||||
# 52| 1: [PropertyCall] access to property Imaginary
|
||||
# 52| -1: [ParameterAccess] access to parameter other
|
||||
# 54| 15: [Method] Dec
|
||||
# 54| -1: [TypeMention] Complex
|
||||
# 54| -1: [TypeMention] INumber<Complex>
|
||||
# 54| 1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 54| 0: [Parameter] other
|
||||
# 54| -1: [TypeMention] Complex
|
||||
# 55| 4: [ObjectCreation] object creation of type Complex
|
||||
# 55| -2: [TypeMention] Complex
|
||||
# 55| -1: [ObjectInitializer] { ..., ... }
|
||||
# 55| 0: [MemberInitializer] ... = ...
|
||||
# 55| 0: [PropertyCall] access to property Real
|
||||
# 55| 1: [SubExpr] ... - ...
|
||||
# 55| 0: [PropertyCall] access to property Real
|
||||
# 55| -1: [ParameterAccess] access to parameter other
|
||||
# 55| 1: [DoubleLiteral] 1
|
||||
# 55| 1: [MemberInitializer] ... = ...
|
||||
# 55| 0: [PropertyCall] access to property Imaginary
|
||||
# 55| 1: [PropertyCall] access to property Imaginary
|
||||
# 55| -1: [ParameterAccess] access to parameter other
|
||||
# 57| 16: [Method] Add
|
||||
# 57| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 57| 0: [Parameter] left
|
||||
# 57| -1: [TypeMention] Complex
|
||||
# 57| 1: [Parameter] right
|
||||
# 57| -1: [TypeMention] Complex
|
||||
# 58| 4: [ObjectCreation] object creation of type Complex
|
||||
# 58| -2: [TypeMention] Complex
|
||||
# 58| -1: [ObjectInitializer] { ..., ... }
|
||||
# 58| 0: [MemberInitializer] ... = ...
|
||||
# 58| 0: [PropertyCall] access to property Real
|
||||
# 58| 1: [AddExpr] ... + ...
|
||||
# 58| 0: [PropertyCall] access to property Real
|
||||
# 58| -1: [ParameterAccess] access to parameter left
|
||||
# 58| 1: [PropertyCall] access to property Real
|
||||
# 58| -1: [ParameterAccess] access to parameter right
|
||||
# 58| 1: [MemberInitializer] ... = ...
|
||||
# 58| 0: [PropertyCall] access to property Imaginary
|
||||
# 58| 1: [AddExpr] ... + ...
|
||||
# 58| 0: [PropertyCall] access to property Imaginary
|
||||
# 58| -1: [ParameterAccess] access to parameter left
|
||||
# 58| 1: [PropertyCall] access to property Imaginary
|
||||
# 58| -1: [ParameterAccess] access to parameter right
|
||||
# 60| 17: [Method] Subtract
|
||||
# 60| -1: [TypeMention] Complex
|
||||
#-----| 2: (Parameters)
|
||||
# 60| 0: [Parameter] left
|
||||
# 60| -1: [TypeMention] Complex
|
||||
# 60| 1: [Parameter] right
|
||||
# 60| -1: [TypeMention] Complex
|
||||
# 61| 4: [ObjectCreation] object creation of type Complex
|
||||
# 61| -2: [TypeMention] Complex
|
||||
# 61| -1: [ObjectInitializer] { ..., ... }
|
||||
# 61| 0: [MemberInitializer] ... = ...
|
||||
# 61| 0: [PropertyCall] access to property Real
|
||||
# 61| 1: [SubExpr] ... - ...
|
||||
# 61| 0: [PropertyCall] access to property Real
|
||||
# 61| -1: [ParameterAccess] access to parameter left
|
||||
# 61| 1: [PropertyCall] access to property Real
|
||||
# 61| -1: [ParameterAccess] access to parameter right
|
||||
# 61| 1: [MemberInitializer] ... = ...
|
||||
# 61| 0: [PropertyCall] access to property Imaginary
|
||||
# 61| 1: [SubExpr] ... - ...
|
||||
# 61| 0: [PropertyCall] access to property Imaginary
|
||||
# 61| -1: [ParameterAccess] access to parameter left
|
||||
# 61| 1: [PropertyCall] access to property Imaginary
|
||||
# 61| -1: [ParameterAccess] access to parameter right
|
||||
Strings.cs:
|
||||
# 3| [Class] MyTestClass
|
||||
# 5| 5: [Method] M1
|
||||
|
||||
@@ -4,6 +4,18 @@ public interface INumber<T> where T : INumber<T>
|
||||
|
||||
static virtual T operator --(T other) => other;
|
||||
|
||||
static abstract T operator +(T left, T right);
|
||||
|
||||
static virtual T operator -(T left, T right) => left;
|
||||
|
||||
static abstract explicit operator int(T n);
|
||||
|
||||
static abstract explicit operator short(T n);
|
||||
|
||||
static abstract T Inc(T other);
|
||||
|
||||
static virtual T Dec(T other) => other;
|
||||
|
||||
static abstract T Add(T left, T right);
|
||||
|
||||
static virtual T Subtract(T left, T right) => left;
|
||||
@@ -26,6 +38,22 @@ public class Complex : INumber<Complex>
|
||||
public static Complex operator --(Complex other) =>
|
||||
new Complex { Real = other.Real - 1.0, Imaginary = other.Imaginary };
|
||||
|
||||
static Complex INumber<Complex>.operator +(Complex left, Complex right) =>
|
||||
new Complex { Real = left.Real + right.Real, Imaginary = left.Imaginary + right.Imaginary };
|
||||
|
||||
static Complex INumber<Complex>.operator -(Complex left, Complex right) =>
|
||||
new Complex { Real = left.Real - right.Real, Imaginary = left.Imaginary - right.Imaginary };
|
||||
|
||||
public static explicit operator int(Complex n) => (int)n.Real;
|
||||
|
||||
static explicit INumber<Complex>.operator short(Complex n) => (short)n.Real;
|
||||
|
||||
static Complex INumber<Complex>.Inc(Complex other) =>
|
||||
new Complex { Real = other.Real + 1.0, Imaginary = other.Imaginary };
|
||||
|
||||
static Complex INumber<Complex>.Dec(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 };
|
||||
|
||||
|
||||
116
csharp/ql/test/library-tests/csharp11/fileScoped.expected
Normal file
@@ -0,0 +1,116 @@
|
||||
typemodifiers
|
||||
| FileScoped1.cs:1:16:1:17 | I1 | file |
|
||||
| FileScoped1.cs:3:16:3:17 | I2 | file |
|
||||
| FileScoped1.cs:5:12:5:13 | C1 | file |
|
||||
| FileScoped1.cs:7:14:7:15 | C2 | public |
|
||||
| FileScoped1.cs:9:14:9:15 | C3 | public |
|
||||
| FileScoped1.cs:11:16:11:17 | IC | file |
|
||||
| FileScoped1.cs:13:12:13:16 | C4<> | file |
|
||||
| FileScoped1.cs:13:12:13:16 | C4<S> | file |
|
||||
| FileScoped1.cs:15:12:15:16 | C5<> | file |
|
||||
| FileScoped1.cs:17:13:17:14 | S1 | file |
|
||||
| FileScoped1.cs:17:13:17:14 | S1 | sealed |
|
||||
| FileScoped1.cs:19:11:19:12 | E1 | file |
|
||||
| FileScoped1.cs:19:11:19:12 | E1 | sealed |
|
||||
| FileScoped1.cs:21:20:21:21 | D1 | file |
|
||||
| FileScoped1.cs:21:20:21:21 | D1 | sealed |
|
||||
| FileScoped1.cs:23:1:23:18 | R1 | file |
|
||||
| FileScoped1.cs:23:1:23:18 | R1 | record |
|
||||
| FileScoped1.cs:25:1:25:26 | RS1 | file |
|
||||
| FileScoped1.cs:25:1:25:26 | RS1 | record |
|
||||
| FileScoped1.cs:25:1:25:26 | RS1 | sealed |
|
||||
| FileScoped2.cs:1:16:1:17 | I1 | file |
|
||||
| FileScoped2.cs:3:18:3:19 | I2 | public |
|
||||
| FileScoped2.cs:5:12:5:13 | C1 | file |
|
||||
| FileScoped2.cs:7:12:7:13 | C2 | file |
|
||||
| FileScoped2.cs:9:12:9:13 | IC | file |
|
||||
| FileScoped2.cs:11:12:11:16 | C4<> | file |
|
||||
| FileScoped2.cs:11:12:11:16 | C4<S> | file |
|
||||
| FileScoped2.cs:13:12:13:16 | C5<> | file |
|
||||
| FileScoped2.cs:15:13:15:14 | S1 | file |
|
||||
| FileScoped2.cs:15:13:15:14 | S1 | sealed |
|
||||
| FileScoped2.cs:17:11:17:12 | E1 | file |
|
||||
| FileScoped2.cs:17:11:17:12 | E1 | sealed |
|
||||
| FileScoped2.cs:19:20:19:21 | D1 | file |
|
||||
| FileScoped2.cs:19:20:19:21 | D1 | sealed |
|
||||
| FileScoped2.cs:21:1:21:18 | R1 | file |
|
||||
| FileScoped2.cs:21:1:21:18 | R1 | record |
|
||||
| FileScoped2.cs:23:1:23:26 | RS1 | file |
|
||||
| FileScoped2.cs:23:1:23:26 | RS1 | record |
|
||||
| FileScoped2.cs:23:1:23:26 | RS1 | sealed |
|
||||
| FileScoped3.cs:3:16:3:18 | I10 | file |
|
||||
| FileScoped3.cs:5:12:5:14 | C10 | file |
|
||||
| FileScoped3.cs:7:14:7:16 | C11 | public |
|
||||
| FileScoped4.cs:3:18:3:20 | I10 | public |
|
||||
| FileScoped4.cs:5:12:5:14 | C10 | file |
|
||||
| FileScoped4.cs:7:12:7:14 | C11 | file |
|
||||
qualifiedtypes
|
||||
| FileScoped1.cs:1:16:1:17 | I1 | I1 |
|
||||
| FileScoped1.cs:3:16:3:17 | I2 | I2 |
|
||||
| FileScoped1.cs:5:12:5:13 | C1 | C1 |
|
||||
| FileScoped1.cs:7:14:7:15 | C2 | C2 |
|
||||
| FileScoped1.cs:9:14:9:15 | C3 | C3 |
|
||||
| FileScoped1.cs:11:16:11:17 | IC | IC |
|
||||
| FileScoped1.cs:13:12:13:16 | C4<> | C4<> |
|
||||
| FileScoped1.cs:13:12:13:16 | C4<S> | C4<S> |
|
||||
| FileScoped1.cs:15:12:15:16 | C5<> | C5<> |
|
||||
| FileScoped1.cs:17:13:17:14 | S1 | S1 |
|
||||
| FileScoped1.cs:19:11:19:12 | E1 | E1 |
|
||||
| FileScoped1.cs:21:20:21:21 | D1 | D1 |
|
||||
| FileScoped1.cs:23:1:23:18 | R1 | R1 |
|
||||
| FileScoped1.cs:25:1:25:26 | RS1 | RS1 |
|
||||
| FileScoped2.cs:1:16:1:17 | I1 | I1 |
|
||||
| FileScoped2.cs:3:18:3:19 | I2 | I2 |
|
||||
| FileScoped2.cs:5:12:5:13 | C1 | C1 |
|
||||
| FileScoped2.cs:7:12:7:13 | C2 | C2 |
|
||||
| FileScoped2.cs:9:12:9:13 | IC | IC |
|
||||
| FileScoped2.cs:11:12:11:16 | C4<> | C4<> |
|
||||
| FileScoped2.cs:11:12:11:16 | C4<S> | C4<S> |
|
||||
| FileScoped2.cs:13:12:13:16 | C5<> | C5<> |
|
||||
| FileScoped2.cs:15:13:15:14 | S1 | S1 |
|
||||
| FileScoped2.cs:17:11:17:12 | E1 | E1 |
|
||||
| FileScoped2.cs:19:20:19:21 | D1 | D1 |
|
||||
| FileScoped2.cs:21:1:21:18 | R1 | R1 |
|
||||
| FileScoped2.cs:23:1:23:26 | RS1 | RS1 |
|
||||
| FileScoped3.cs:3:16:3:18 | I10 | TestFileScoped.I10 |
|
||||
| FileScoped3.cs:5:12:5:14 | C10 | TestFileScoped.C10 |
|
||||
| FileScoped3.cs:7:14:7:16 | C11 | TestFileScoped.C11 |
|
||||
| FileScoped4.cs:3:18:3:20 | I10 | TestFileScoped.I10 |
|
||||
| FileScoped4.cs:5:12:5:14 | C10 | TestFileScoped.C10 |
|
||||
| FileScoped4.cs:7:12:7:14 | C11 | TestFileScoped.C11 |
|
||||
filetypes
|
||||
| FileScoped1.cs:1:16:1:17 | I1 |
|
||||
| FileScoped1.cs:3:16:3:17 | I2 |
|
||||
| FileScoped1.cs:5:12:5:13 | C1 |
|
||||
| FileScoped1.cs:11:16:11:17 | IC |
|
||||
| FileScoped1.cs:13:12:13:16 | C4<> |
|
||||
| FileScoped1.cs:13:12:13:16 | C4<S> |
|
||||
| FileScoped1.cs:15:12:15:16 | C5<> |
|
||||
| FileScoped1.cs:17:13:17:14 | S1 |
|
||||
| FileScoped1.cs:19:11:19:12 | E1 |
|
||||
| FileScoped1.cs:21:20:21:21 | D1 |
|
||||
| FileScoped1.cs:23:1:23:18 | R1 |
|
||||
| FileScoped1.cs:25:1:25:26 | RS1 |
|
||||
| FileScoped2.cs:1:16:1:17 | I1 |
|
||||
| FileScoped2.cs:5:12:5:13 | C1 |
|
||||
| FileScoped2.cs:7:12:7:13 | C2 |
|
||||
| FileScoped2.cs:9:12:9:13 | IC |
|
||||
| FileScoped2.cs:11:12:11:16 | C4<> |
|
||||
| FileScoped2.cs:11:12:11:16 | C4<S> |
|
||||
| FileScoped2.cs:13:12:13:16 | C5<> |
|
||||
| FileScoped2.cs:15:13:15:14 | S1 |
|
||||
| FileScoped2.cs:17:11:17:12 | E1 |
|
||||
| FileScoped2.cs:19:20:19:21 | D1 |
|
||||
| FileScoped2.cs:21:1:21:18 | R1 |
|
||||
| FileScoped2.cs:23:1:23:26 | RS1 |
|
||||
| FileScoped3.cs:3:16:3:18 | I10 |
|
||||
| FileScoped3.cs:5:12:5:14 | C10 |
|
||||
| FileScoped4.cs:5:12:5:14 | C10 |
|
||||
| FileScoped4.cs:7:12:7:14 | C11 |
|
||||
internaltypes
|
||||
publictypes
|
||||
| FileScoped1.cs:7:14:7:15 | C2 |
|
||||
| FileScoped1.cs:9:14:9:15 | C3 |
|
||||
| FileScoped2.cs:3:18:3:19 | I2 |
|
||||
| FileScoped3.cs:7:14:7:16 | C11 |
|
||||
| FileScoped4.cs:3:18:3:20 | I10 |
|
||||
42
csharp/ql/test/library-tests/csharp11/fileScoped.ql
Normal file
@@ -0,0 +1,42 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
private predicate isInteresting(Type t) {
|
||||
(
|
||||
t instanceof Class or
|
||||
t instanceof Interface or
|
||||
t instanceof Struct or
|
||||
t instanceof Enum or
|
||||
t instanceof DelegateType or
|
||||
t instanceof RecordType
|
||||
) and
|
||||
t.getFile().getStem().matches("FileScoped%")
|
||||
}
|
||||
|
||||
query predicate typemodifiers(Type t, string modifier) {
|
||||
isInteresting(t) and
|
||||
t.(Modifiable).hasModifier(modifier)
|
||||
}
|
||||
|
||||
query predicate qualifiedtypes(Type t, string qualifiedName) {
|
||||
isInteresting(t) and
|
||||
exists(string qualifier, string name |
|
||||
t.hasQualifiedName(qualifier, name) and
|
||||
qualifiedName = getQualifiedName(qualifier, name)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate filetypes(Type t) {
|
||||
isInteresting(t) and
|
||||
t.isFile()
|
||||
}
|
||||
|
||||
query predicate internaltypes(Type t) {
|
||||
isInteresting(t) and
|
||||
t.isInternal()
|
||||
}
|
||||
|
||||
query predicate publictypes(Type t) {
|
||||
isInteresting(t) and
|
||||
t.isPublic()
|
||||
}
|
||||
@@ -5,16 +5,55 @@ interfacemembers
|
||||
| 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 |
|
||||
| INumber<> | StaticInterfaceMembers.cs:7:32:7:32 | + | abstract |
|
||||
| INumber<> | StaticInterfaceMembers.cs:7:32:7:32 | + | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:7:32:7:32 | + | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:9:31:9:31 | - | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:9:31:9:31 | - | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:9:31:9:31 | - | virtual |
|
||||
| INumber<> | StaticInterfaceMembers.cs:11:30:11:37 | explicit conversion | abstract |
|
||||
| INumber<> | StaticInterfaceMembers.cs:11:30:11:37 | explicit conversion | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:11:30:11:37 | explicit conversion | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:13:30:13:37 | explicit conversion | abstract |
|
||||
| INumber<> | StaticInterfaceMembers.cs:13:30:13:37 | explicit conversion | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:13:30:13:37 | explicit conversion | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:15:23:15:25 | Inc | abstract |
|
||||
| INumber<> | StaticInterfaceMembers.cs:15:23:15:25 | Inc | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:15:23:15:25 | Inc | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:17:22:17:24 | Dec | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:17:22:17:24 | Dec | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:17:22:17:24 | Dec | virtual |
|
||||
| INumber<> | StaticInterfaceMembers.cs:19:23:19:25 | Add | abstract |
|
||||
| INumber<> | StaticInterfaceMembers.cs:19:23:19:25 | Add | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:19:23:19:25 | Add | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:21:22:21:29 | Subtract | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:21:22:21:29 | Subtract | static |
|
||||
| INumber<> | StaticInterfaceMembers.cs:21:22:21:29 | Subtract | virtual |
|
||||
| INumber<> | StaticInterfaceMembers.cs:23:14:23:17 | Zero | public |
|
||||
| INumber<> | StaticInterfaceMembers.cs:23:14:23: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 |
|
||||
| StaticInterfaceMembers.cs:35:36:35:37 | ++ | StaticInterfaceMembers.cs:3:32:3:33 | ++ |
|
||||
| StaticInterfaceMembers.cs:38:36:38:37 | -- | StaticInterfaceMembers.cs:5:31:5:32 | -- |
|
||||
| StaticInterfaceMembers.cs:41:46:41:46 | + | StaticInterfaceMembers.cs:7:32:7:32 | + |
|
||||
| StaticInterfaceMembers.cs:44:46:44:46 | - | StaticInterfaceMembers.cs:9:31:9:31 | - |
|
||||
| StaticInterfaceMembers.cs:47:28:47:35 | explicit conversion | StaticInterfaceMembers.cs:11:30:11:37 | explicit conversion |
|
||||
| StaticInterfaceMembers.cs:49:38:49:45 | explicit conversion | StaticInterfaceMembers.cs:13:30:13:37 | explicit conversion |
|
||||
| StaticInterfaceMembers.cs:51:37:51:39 | Inc | StaticInterfaceMembers.cs:15:23:15:25 | Inc |
|
||||
| StaticInterfaceMembers.cs:54:37:54:39 | Dec | StaticInterfaceMembers.cs:17:22:17:24 | Dec |
|
||||
| StaticInterfaceMembers.cs:57:27:57:29 | Add | StaticInterfaceMembers.cs:19:23:19:25 | Add |
|
||||
| StaticInterfaceMembers.cs:60:27:60:34 | Subtract | StaticInterfaceMembers.cs:21:22:21:29 | Subtract |
|
||||
publicmembers
|
||||
| StaticInterfaceMembers.cs:28:19:28:22 | Real |
|
||||
| StaticInterfaceMembers.cs:29:19:29:27 | Imaginary |
|
||||
| StaticInterfaceMembers.cs:31:12:31:18 | Complex |
|
||||
| StaticInterfaceMembers.cs:33:27:33:30 | Zero |
|
||||
| StaticInterfaceMembers.cs:35:36:35:37 | ++ |
|
||||
| StaticInterfaceMembers.cs:38:36:38:37 | -- |
|
||||
| StaticInterfaceMembers.cs:41:46:41:46 | + |
|
||||
| StaticInterfaceMembers.cs:44:46:44:46 | - |
|
||||
| StaticInterfaceMembers.cs:47:28:47:35 | explicit conversion |
|
||||
| StaticInterfaceMembers.cs:49:38:49:45 | explicit conversion |
|
||||
| StaticInterfaceMembers.cs:51:37:51:39 | Inc |
|
||||
| StaticInterfaceMembers.cs:54:37:54:39 | Dec |
|
||||
| StaticInterfaceMembers.cs:57:27:57:29 | Add |
|
||||
| StaticInterfaceMembers.cs:60:27:60:34 | Subtract |
|
||||
|
||||
@@ -16,3 +16,9 @@ query predicate implements(Overridable o, Virtualizable v) {
|
||||
v.isStatic() and
|
||||
v.getAnImplementor() = o
|
||||
}
|
||||
|
||||
query predicate publicmembers(Member m) {
|
||||
m.getFile().getStem() = "StaticInterfaceMembers" and
|
||||
m.getDeclaringType().getName() = "Complex" and
|
||||
m.isPublic()
|
||||
}
|
||||
|
||||
@@ -26,4 +26,21 @@ class StaticFields
|
||||
staticField = 0; // BAD
|
||||
instanceField = 0; // OK
|
||||
}
|
||||
|
||||
static object backingField;
|
||||
static object StaticProp
|
||||
{
|
||||
get
|
||||
{
|
||||
return backingField ?? (backingField = new object()); // OK
|
||||
}
|
||||
}
|
||||
|
||||
object Prop
|
||||
{
|
||||
get
|
||||
{
|
||||
return backingField ?? (backingField = new object()); // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
| StaticFieldWrittenByInstance.cs:15:9:15:19 | access to field staticField | Write to static field from instance method or constructor. |
|
||||
| StaticFieldWrittenByInstance.cs:26:9:26:19 | access to field staticField | Write to static field from instance method or constructor. |
|
||||
| StaticFieldWrittenByInstance.cs:15:9:15:19 | access to field staticField | Write to static field from instance method, property, or constructor. |
|
||||
| StaticFieldWrittenByInstance.cs:26:9:26:19 | access to field staticField | Write to static field from instance method, property, or constructor. |
|
||||
| StaticFieldWrittenByInstance.cs:43:37:43:48 | access to field backingField | Write to static field from instance method, property, or constructor. |
|
||||
|
||||
@@ -14,7 +14,7 @@ CodeQL for Visual Studio Code provides an easy way to run queries from the large
|
||||
With these queries, or your own custom queries, you can analyze databases generated from source code to find errors and security vulnerabilities.
|
||||
The Results view shows the flow of data through the results of path queries, which is essential for triaging security results.
|
||||
|
||||
The CodeQL extension also adds a **CodeQL** sidebar view to VS Code. This contains a list of databases, and an overview of the queries that you have run in the current session.
|
||||
The CodeQL extension also adds a **CodeQL** sidebar view to VS Code. This contains a list of local CodeQL databases, an overview of the queries that you have run in the current session, and a variant analysis view for large scale analysis.
|
||||
|
||||
The extension provides standard `IntelliSense <https://code.visualstudio.com/docs/editor/intellisense>`__
|
||||
features for query files (extension ``.ql``) and library files (extension ``.qll``) that you open in the Visual Studio Code editor.
|
||||
@@ -36,4 +36,5 @@ Further reading
|
||||
-------------------
|
||||
|
||||
- ":doc:`Setting up CodeQL in Visual Studio Code <setting-up-codeql-in-visual-studio-code>`"
|
||||
- ":doc:`Analyzing your projects <analyzing-your-projects>`"
|
||||
- ":doc:`Analyzing your projects <analyzing-your-projects>`"
|
||||
- ":doc:`Running CodeQL queries at scale with multi-repository variant analysis <running-codeql-queries-at-scale-with-mrva>`"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Analyzing your projects
|
||||
=================================================
|
||||
|
||||
You can run queries on CodeQL databases and view the results in Visual Studio Code.
|
||||
You can run queries on CodeQL databases and view the results in Visual Studio Code. This article explains how to get a CodeQL database and analyze it on your local machine. For information on running analysis at scale across many CodeQL databases, see ":ref:`Running CodeQL queries at scale with multi-repository variant analysis <running-codeql-queries-at-scale-with-mrva>`."
|
||||
|
||||
Choosing a database
|
||||
------------------------
|
||||
@@ -24,8 +24,8 @@ To analyze a project, you need to add a :ref:`CodeQL database <codeql-database>`
|
||||
|
||||
#. Once you've chosen a database, it is displayed in the Databases view. To see the menu options for interacting with a database, right-click an entry in the list. You can select multiple databases using **Ctrl/Cmd+click**.
|
||||
|
||||
Obtaining a local database
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Importing a local database
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you have a CodeQL database saved locally, as an unarchived folder or as a ZIP file, you can add it to Visual Studio Code. There are several ways to obtain a local CodeQL database.
|
||||
|
||||
@@ -37,6 +37,9 @@ If you have a CodeQL database saved locally, as an unarchived folder or as a ZIP
|
||||
|
||||
For more information about running query tests, see "`Testing custom queries <https://docs.github.com/en/code-security/codeql-cli/using-the-codeql-cli/testing-custom-queries>`__" in the CodeQL CLI help.
|
||||
|
||||
Downloading a database from GitHub
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. include:: ../reusables/download-github-database.rst
|
||||
|
||||
Running a query
|
||||
|
||||
@@ -25,6 +25,8 @@ Editing settings
|
||||
|
||||
3. Edit a setting. The new settings are saved automatically.
|
||||
|
||||
Alternatively, you can edit the settings in JSON format by opening the command palette and selecting **Preferences: Open User Settings (JSON)**.
|
||||
|
||||
Choosing a version of the CodeQL CLI
|
||||
--------------------------------------
|
||||
|
||||
@@ -55,8 +57,8 @@ By default, items in the query history view are retained for 30 days. You can se
|
||||
|
||||
.. _configuring-settings-for-running-queries:
|
||||
|
||||
Configuring settings for running queries
|
||||
-----------------------------------------
|
||||
Configuring settings for running queries locally
|
||||
------------------------------------------------
|
||||
|
||||
There are a number of settings for **Running Queries**. If your queries run too slowly and time out frequently, you may want to increase the memory.
|
||||
|
||||
@@ -64,8 +66,49 @@ There are a number of settings for **Running Queries**. If your queries run too
|
||||
|
||||
To save query server logs in a custom location, edit the **Running Queries: Custom Log Directory** setting. If you use a custom log directory, the extension saves the logs permanently, instead of deleting them automatically after each workspace session. This is useful if you want to investigate these logs to improve the performance of your queries.
|
||||
|
||||
Configuring settings for testing queries
|
||||
-----------------------------------------
|
||||
Configuring settings for variant analysis
|
||||
------------------------------------------
|
||||
|
||||
You can define or edit lists of GitHub repositories for variant analysis, and change to a different controller repository using the **Variant analysis** settings.
|
||||
|
||||
For information on the purpose and requirements for a controller repository, see ":ref:`Setting up a controller repository for variant analysis <controller-repository>`."
|
||||
|
||||
You can also edit the items shown in the Variant Analysis Repositories panel by editing a file in your Visual Studio Code workspace called ``databases.json``. This file contains a JSON representation of all the items displayed in the panel. To open your ``databases.json`` file in an editor window, click the **{ }** icon in the top right of the Variant Analysis Repositories panel. You can then see a structured representation of the repos, orgs and lists in your panel. For example:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"version": 1,
|
||||
"databases": {
|
||||
"variantAnalysis": {
|
||||
"repositoryLists": [
|
||||
{
|
||||
"name": "My favorite JavaScript repos",
|
||||
"repositories": [
|
||||
"facebook/react",
|
||||
"babel/babel",
|
||||
"angular/angular"
|
||||
]
|
||||
}
|
||||
],
|
||||
"owners": [
|
||||
"microsoft"
|
||||
],
|
||||
"repositories": [
|
||||
"apache/hadoop"
|
||||
]
|
||||
}
|
||||
},
|
||||
"selected": {
|
||||
"kind": "variantAnalysisSystemDefinedList",
|
||||
"listName": "top_10"
|
||||
}
|
||||
}
|
||||
|
||||
You can change the items shown in the panel or add new items by directly editing this file.
|
||||
|
||||
Configuring settings for testing queries locally
|
||||
------------------------------------------------
|
||||
|
||||
To increase the number of threads used for testing queries, you can update the **Running Tests > Number Of Threads** setting.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.. _exploring-data-flow-with-path-queries:
|
||||
|
||||
Exploring data flow with path queries
|
||||
=================================================
|
||||
=====================================
|
||||
|
||||
You can run CodeQL queries in VS Code to help you track the flow of data through a program, highlighting areas that are potential security vulnerabilities.
|
||||
|
||||
@@ -20,8 +20,8 @@ You can also modify the existing queries to model data flow more precisely for t
|
||||
To ensure that your path query uses the correct format and metadata, follow the instructions in ":ref:`Creating path queries <creating-path-queries>`."
|
||||
This topic also contains detailed information about how to define new sources and sinks, as well as templates and examples of how to extend the CodeQL libraries to suit your analysis.
|
||||
|
||||
Running path queries in VS Code
|
||||
-----------------------------------
|
||||
Running path queries in VS Code locally
|
||||
---------------------------------------
|
||||
|
||||
#. Open a path query in the editor.
|
||||
#. Right-click in the query window and select **CodeQL: Run Query on Selected Database**. (Alternatively, run the command from the Command Palette.)
|
||||
@@ -30,6 +30,8 @@ Running path queries in VS Code
|
||||
#. Click each step to jump to it in the source code and investigate the problem further.
|
||||
#. To navigate the results from your keyboard, you can bind shortcuts to the **CodeQL: Navigate Up/Down/Left/Right in Result Viewer** commands.
|
||||
|
||||
When you are ready to run a path query at scale, you can use the Variant Analysis Repositories panel to run the query against up to 1,000 repositories on GitHub.com. For information on running analysis at scale across many CodeQL databases, see ":ref:`Running CodeQL queries at scale with multi-repository variant analysis <running-codeql-queries-at-scale-with-mrva>`."
|
||||
|
||||
Further reading
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@ The CodeQL extension for Visual Studio Code adds rich language support for CodeQ
|
||||
VS Code to help you track the flow of data through a program, highlighting
|
||||
areas that are potential security vulnerabilities.
|
||||
|
||||
- :doc:`Running CodeQL queries at scale with multi-repository variant analysis
|
||||
<running-codeql-queries-at-scale-with-mrva>`: You can run queries against groups
|
||||
of repositories on GitHub.com and view results in Visual Studio Code as each analysis
|
||||
finishes.
|
||||
|
||||
- :doc:`Testing CodeQL queries in Visual Studio Code
|
||||
<testing-codeql-queries-in-visual-studio-code>`: You can run unit tests for
|
||||
CodeQL queries using the Visual Studio Code extension.
|
||||
@@ -40,7 +45,13 @@ The CodeQL extension for Visual Studio Code adds rich language support for CodeQ
|
||||
|
||||
- :doc:`Troubleshooting CodeQL for Visual Studio Code
|
||||
<troubleshooting-codeql-for-visual-studio-code>`: You can use the detailed
|
||||
information written to the extension's log files if you need to troubleshoot problems.
|
||||
information written to the extension's log files if you need to troubleshoot problems with
|
||||
analysis of local CodeQL databases.
|
||||
|
||||
- :doc:`Troubleshooting variant analysis
|
||||
<troubleshooting-variant-analysis>`: You can use the detailed
|
||||
information written to workflow log files in your controller repository if you need to
|
||||
troubleshoot problems with analysis of CodeQL databases stored on GitHub.com.
|
||||
|
||||
- :doc:`About telemetry in CodeQL for Visual Studio Code <about-telemetry-in-codeql-for-visual-studio-code>`: If you specifically opt in to permit GitHub to do so, GitHub will collect usage data and metrics for the purposes of helping the core developers to improve the CodeQL extension for VS Code.
|
||||
|
||||
@@ -53,8 +64,10 @@ The CodeQL extension for Visual Studio Code adds rich language support for CodeQ
|
||||
analyzing-your-projects
|
||||
exploring-the-structure-of-your-source-code
|
||||
exploring-data-flow-with-path-queries
|
||||
running-codeql-queries-at-scale-with-mrva
|
||||
testing-codeql-queries-in-visual-studio-code
|
||||
working-with-codeql-packs-in-visual-studio-code
|
||||
customizing-settings
|
||||
troubleshooting-codeql-for-visual-studio-code
|
||||
troubleshooting-variant-analysis
|
||||
about-telemetry-in-codeql-for-visual-studio-code
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
:tocdepth: 1
|
||||
|
||||
.. _running-codeql-queries-at-scale-with-mrva:
|
||||
|
||||
Running CodeQL queries at scale with multi-repository variant analysis
|
||||
======================================================================
|
||||
|
||||
.. include:: ../reusables/beta-note-mrva.rst
|
||||
|
||||
About multi-repository variant analysis
|
||||
---------------------------------------
|
||||
|
||||
When you write a query to find variants of a security vulnerability and finish testing it locally, the next step is to run it on a large group of repositories. Multi-repository variant analysis (variant analysis) makes it easy run a query on up to 1000 repositories without leaving Visual Studio Code.
|
||||
|
||||
The core functionality of the CodeQL extension helps you write queries and run them locally against a CodeQL database. In contrast, variant analysis allows you to send your CodeQL query to GitHub.com to be tested against a list of repositories.
|
||||
|
||||
When you run variant analysis against a list of repositories, your query is run against each repository that has a CodeQL database available to analyze. GitHub creates and stores the latest CodeQL database for the default branch of thousands of public repositories, including every repository that runs code scanning using CodeQL.
|
||||
|
||||
If you want to run variant analysis on your repositories, you need to enable code scanning using CodeQL on GitHub.com before adding your repository to a list for analysis (either default setup, or advanced setup using the CodeQL action). For information about enabling code scanning using CodeQL, see "`Configuring code scanning automatically <https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning-for-a-repository#configuring-code-scanning-automatically>`__."
|
||||
|
||||
.. _controller-repository:
|
||||
|
||||
Setting a controller repository for variant analysis
|
||||
----------------------------------------------------
|
||||
|
||||
When you run variant analysis, the analysis is run entirely using GitHub Actions. You don't need to create any workflows, but you must specify which GitHub repository the CodeQL extension should use as the "controller repository." Controller repositories can be empty, but they must have at least one commit. The ``GITHUB_TOKEN`` must also have "Read and write permissions" to run workflows in that repository. For more information, see "`Managing GitHub Actions settings for a repository <https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#setting-the-permissions-of-the-github_token-for-your-repository>`__."
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
- The controller repository visibility can be "public" if you plan to analyze public repositories. The variant analysis will be free.
|
||||
- The controller repository visibility must be "private" if you need to analyze any private or internal repositories. Any actions minutes used by variant analysis, above the free limit, will be charged to the repository owner. For more information about free minutes and billing, see "`About billing for GitHub Actions <https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions>`__."
|
||||
|
||||
You must define a controller repository before you can run your first variant analysis.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/controller-repository.png
|
||||
:width: 350
|
||||
:alt: Screenshot of the CodeQL extension in Visual Studio Code. The "Variant Analysis Repositories" section is expanded and the "Set up controller repository" button is highlighted with a dark orange outline.
|
||||
|
||||
#. In Visual Studio Code, click **QL** in the left sidebar to display the CodeQL extension.
|
||||
|
||||
#. Expand **Variant Analysis Repositories** and click **Set up controller repository** to display a field for the controller repository.
|
||||
|
||||
#. Type the owner and name of the repository on GitHub.com that you want to use as your controller repository and press the **Enter** key.
|
||||
|
||||
#. If you are prompted to authenticate with GitHub, follow the instructions and sign into your personal or organization account. When you have finished following the process, a prompt from GitHub Authentication may ask for permission to open a URI in Visual Studio Code, click **Open**.
|
||||
|
||||
The name of the controller repository is saved in your settings for the CodeQL extension. For information on how to edit the controller repository, see ":ref:`Customizing settings <customizing-settings>`."
|
||||
|
||||
Running a query at scale using variant analysis
|
||||
-----------------------------------------------
|
||||
|
||||
#. Expand the **Variant Analysis Repositories** section, to show the default lists which include a selection of 10, 100, and 1,000 public repositories on GitHub.com for the language that you are analyzing.
|
||||
|
||||
#. Select which GitHub repository or repositories you want to run your query against. Click a row to highlight it, and then click **Select** to select that repository, organization, or list of repositories. If you want to add a new repository, organization, or list, use the options in the header panel. For information, see ":ref:`Creating custom lists of repositories <custom-lists>`", later in this article.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/variant-analysis-repo-lists.png
|
||||
:width: 350
|
||||
:alt: Screenshot of the CodeQL extension in Visual Studio Code. The "Variant Analysis Repositories" section is expanded. The "Top 10 repositories" item has a checkmark to show that it is currently selected for analysis. The user has clicked on the row for a single repository "octo-org/octo-repo" and it is highlighted blue. The "Select" button for that row is highlighted with a dark orange highlight.
|
||||
|
||||
#. Open the query you want to run, right-click in the query file, and select **CodeQL: Run Variant Analysis** to start variant analysis.
|
||||
|
||||
The CodeQL extension builds a CodeQL pack with your library and any library dependencies. The CodeQL pack and your selected repository list are posted to an API endpoint on GitHub.com which triggers a GitHub Actions dynamic workflow in your controller repository. The workflow spins up multiple parallel jobs to execute the CodeQL query against the repositories in the list, optimizing query execution. As each repository is analyzed, the results are processed and displayed in a Variant Analysis Results view in Visual Studio Code.
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
If you need to cancel the variant analysis run for any reason, click **Stop query** in the Variant Analysis Results view.
|
||||
|
||||
Exploring your results
|
||||
----------------------
|
||||
|
||||
When you run variant analysis, as soon as a workflow to run your analysis on GitHub is running, a Variant Analysis Results view opens to display the results as they are ready. You can use this view to monitor progress, see any errors, and access the workflow logs in your controller repository.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/variant-analysis-results-view.png
|
||||
:alt: Screenshot of the "Variant Analysis Results" view showing a partially complete run. Analysis of ``angular/angular`` is still running but all other results are displayed. ``facebook/create-react-app`` has three results for this query.
|
||||
|
||||
When your variant analysis run is scheduled, the results view automatically opens. Initially the view shows a list of every repository that was scheduled for analysis. As each repository is analyzed, the view is updated to show a summary of the number of results. To view the detailed results for a repository (including results paths), click the repository name.
|
||||
|
||||
For each repository, you can see:
|
||||
|
||||
- Number of results found by the query
|
||||
- Visibility of the repository
|
||||
- Whether analysis is still running (black, moving circle) or finished (green checkmark)
|
||||
- Number of stars the repository has on GitHub
|
||||
- When the repository was last updated
|
||||
|
||||
To see the results for a repository:
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/variant-analysis-result.png
|
||||
:alt: Screenshot of an example result in the "Variant Analysis Results" view. The result has blue links to the source files in GitHub so you can go straight to the repository to fix the problem. There is also a "Show paths" link because this is a data flow query.
|
||||
|
||||
#. Click the repository name to show a summary of each result.
|
||||
|
||||
#. Explore the information available for each result using links to the source files in GitHub.com and, for data flow queries, the **Show paths** link. For more information, see ":ref:`Exploring data flow with path queries <exploring-data-flow-with-path-queries>`."
|
||||
|
||||
Exporting your results
|
||||
----------------------
|
||||
|
||||
You can export your results for further analysis or to discuss them with collaborators. In the results view, click **Export results** to export the results to a secret gist on GitHub.com or to a markdown file in your workspace.
|
||||
|
||||
.. _custom-lists:
|
||||
|
||||
Creating custom lists of repositories
|
||||
-------------------------------------
|
||||
|
||||
After you have defined a controller repository, the Variant Analysis Repositories panel shows the lists of repositories that you can select for variant analysis. You can use the options in the panel header to add a specific repository or organization to the panel, and to create and manage custom lists of repositories for variant analysis.
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
CodeQL analysis always requires a CodeQL database to run queries against. When you run variant analysis against a list of repositories, your query will only be executed against the repositories that currently have a CodeQL database available to download. The best way to make a repository available for variant analysis is to enable code scanning with CodeQL. For information about enabling code scanning using CodeQL, see "`Configuring code scanning automatically <https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning-for-a-repository#configuring-code-scanning-automatically>`__."
|
||||
|
||||
Selecting a single GitHub repository or organization for analysis
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#. In the Variant Analysis Repositories panel, click the **+**, add new database, icon.
|
||||
|
||||
#. From the dropdown menu, click **From a GitHub repository** or **All repositories of GitHub org or owner**.
|
||||
|
||||
#. Type the identifier of the repository or organization that you want to use into the field.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/variant-analysis-repo-and-org.png
|
||||
:width: 350
|
||||
:alt: Screenshot of the CodeQL extension in Visual Studio Code. The "Variant Analysis Repositories" section is expanded to show a repository (octo-org/octo-repo) and an organization (octo-org). These items are highlighted with a dark orange outline.
|
||||
|
||||
Creating a custom list of repositories
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#. In the Variant Analysis Repositories panel, click the |add-list| icon.
|
||||
|
||||
#. Type a name for the new list and press **Enter**.
|
||||
|
||||
#. Select your list in the panel and then click **+**, to add a repository to your list.
|
||||
|
||||
You can manage and edit your custom lists by right-clicking on either the list name, or a repository name within the list, and selecting an option from the context menu.
|
||||
|
||||
The custom lists are stored in your workspace in a ``databases.json`` file. If you want to edit this file directly, you can open it by clicking **{ }** in the panel header.
|
||||
|
||||
For example, if you want to continue analyzing a set of repositories that had results for your query, click **Copy repository list** in the Variant Analysis Results view to add a list of only the repositories that have results to the clipboard as JSON. For example:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"name": "new-repo-list",
|
||||
"repositories": [
|
||||
"facebook/create-react-app"
|
||||
]
|
||||
}
|
||||
|
||||
You can then insert the ``new-repo-list`` of repositories into your list of custom repository lists for easy access in the Variant Analysis Repositories panel.
|
||||
|
||||
Troubleshooting variant analysis
|
||||
--------------------------------
|
||||
|
||||
For information on troubleshooting variant analysis, see
|
||||
":ref:`Troubleshooting variant analysis <troubleshooting-variant-analysis>`."
|
||||
|
||||
.. |add-list| image:: ../images/codeql-for-visual-studio-code/variant-analysis-add-list.png
|
||||
:height: 2ex
|
||||
@@ -5,7 +5,7 @@
|
||||
Testing CodeQL queries in Visual Studio Code
|
||||
============================================
|
||||
|
||||
You can run unit tests for CodeQL queries using the Visual Studio Code extension.
|
||||
You can run unit tests for CodeQL queries using the Visual Studio Code extension. When you are sure that your query finds the results you want to identify, you can use variant analysis to run it at scale. For information on running analysis at scale across many CodeQL databases, see ":ref:`Running CodeQL queries at scale with multi-repository variant analysis <running-codeql-queries-at-scale-with-mrva>`."
|
||||
|
||||
About testing queries in VS Code
|
||||
---------------------------------
|
||||
|
||||
@@ -5,7 +5,12 @@
|
||||
Troubleshooting CodeQL for Visual Studio Code
|
||||
=============================================
|
||||
|
||||
You can use the detailed information written to the extension's log files if you need to troubleshoot problems.
|
||||
This article explains how to debug problems with the analysis of CodeQL databases that are stored on your local
|
||||
machine. For information on troubleshooting variant analysis, which runs on GitHub.com, see
|
||||
":ref:`Troubleshooting variant analysis <troubleshooting-variant-analysis>`."
|
||||
|
||||
You can use the detailed information written to the extension's log files if you need to troubleshoot problems
|
||||
analyzing CodeQL databases that are stored locally.
|
||||
|
||||
About the log files
|
||||
--------------------
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
:tocdepth: 1
|
||||
|
||||
.. _troubleshooting-variant-analysis:
|
||||
|
||||
Troubleshooting variant analysis
|
||||
================================
|
||||
|
||||
.. include:: ../reusables/beta-note-mrva.rst
|
||||
|
||||
This article explains how to debug problems with variant analysis, that is, analysis run using GitHub Actions
|
||||
and not locally on your machine.
|
||||
For information on troubleshooting local analysis, see
|
||||
":ref:`Troubleshooting CodeQL for Visual Studio Code <troubleshooting-codeql-for-visual-studio-code>`."
|
||||
|
||||
When you run variant analysis, there are two key places where errors and warnings are displayed:
|
||||
|
||||
#. **Visual Studio Code errors** - any problems with creating a CodeQL pack and sending the analysis to GitHub.com are reported as Visual Studio Code errors in the bottom right corner of the application. The problem information is also available in the **Problems** view.
|
||||
#. **Variant Analysis Results** - any problems with the variant analysis run are reported in this view.
|
||||
|
||||
Variant analysis warning: Problem with controller repository
|
||||
------------------------------------------------------------
|
||||
|
||||
If there are problems with the variant analysis run, you will see a warning banner at the top of the Variant Analysis Results tab. For example:
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/variant-analysis-results-warning.png
|
||||
:width: 600
|
||||
:alt: Screenshot of the "Variant Analysis Results" view showing a warning banner with the text "warning: Problem with controller repository" and "Publicly visible controller repository can't be used to analyze private repositories. 1 private repository was not analyzed." The "Show logs" button is highlighted with a dark orange outline.
|
||||
|
||||
In this example, the user ran variant analysis on a custom list of two repositories. One of the repositories was a private repository and could not be analyzed because they had a public controller repository. Only the public repository was analyzed. To analyze both repositories, this user needs to edit their settings and update the controller repository to a private repository. For information on how to edit the controller repository, see ":ref:`Customizing settings <customizing-settings>`."
|
||||
|
||||
@@ -31,16 +31,16 @@ following snippet demonstrates.
|
||||
|
||||
This query selects the API graph node corresponding to the ``re`` module. This node represents the fact that the ``re`` module has been imported rather than a specific location in the program where the import happens. Therefore, there will be at most one result per project, and it will not have a useful location, so you'll have to click `Show 1 non-source result` in order to see it.
|
||||
|
||||
To find where the ``re`` module is referenced in the program, you can use the ``getAUse`` method. The following query selects all references to the ``re`` module in the current database.
|
||||
To find where the ``re`` module is referenced in the program, you can use the ``getAValueReachableFromSource`` method. The following query selects all references to the ``re`` module in the current database.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import python
|
||||
import semmle.python.ApiGraphs
|
||||
|
||||
select API::moduleImport("re").getAUse()
|
||||
select API::moduleImport("re").getAValueReachableFromSource()
|
||||
|
||||
Note that the ``getAUse`` method accounts for local flow, so that ``my_re_compile``
|
||||
Note that the ``getAValueReachableFromSource`` method accounts for local flow, so that ``my_re_compile``
|
||||
in the following snippet is
|
||||
correctly recognized as a reference to the ``re.compile`` function.
|
||||
|
||||
@@ -53,7 +53,7 @@ correctly recognized as a reference to the ``re.compile`` function.
|
||||
r = my_re_compile(".*")
|
||||
|
||||
If you only require immediate uses, without taking local flow into account, then you can use
|
||||
the ``getAnImmediateUse`` method instead.
|
||||
the ``asSource`` method instead.
|
||||
|
||||
Note that the given module name *must not* contain any dots. Thus, something like
|
||||
``API::moduleImport("flask.views")`` will not do what you expect. Instead, this should be decomposed
|
||||
@@ -71,7 +71,7 @@ the above ``re.compile`` example, you can now find references to ``re.compile``.
|
||||
import python
|
||||
import semmle.python.ApiGraphs
|
||||
|
||||
select API::moduleImport("re").getMember("compile").getAUse()
|
||||
select API::moduleImport("re").getMember("compile").getAValueReachableFromSource()
|
||||
|
||||
In addition to ``getMember``, you can use the ``getUnknownMember`` method to find references to API
|
||||
components where the name is not known statically. You can use the ``getAMember`` method to
|
||||
@@ -89,12 +89,36 @@ where the return value of ``re.compile`` is used:
|
||||
import python
|
||||
import semmle.python.ApiGraphs
|
||||
|
||||
select API::moduleImport("re").getMember("compile").getReturn().getAUse()
|
||||
select API::moduleImport("re").getMember("compile").getReturn().getAValueReachableFromSource()
|
||||
|
||||
Note that this includes all uses of the result of ``re.compile``, including those reachable via
|
||||
local flow. To get just the *calls* to ``re.compile``, you can use ``getAnImmediateUse`` instead of
|
||||
``getAUse``. As this is a common occurrence, you can use ``getACall`` instead of
|
||||
``getReturn`` followed by ``getAnImmediateUse``.
|
||||
local flow. To get just the *calls* to ``re.compile``, you can use ``asSource`` instead of
|
||||
``getAValueReachableFromSource``. As this is a common occurrence, you can, instead of
|
||||
``getReturn`` followed by ``asSource``, simply use ``getACall``. This will result in an
|
||||
``API::CallNode``, which deserves a small description of its own.
|
||||
|
||||
``API::CallNode``s are not ``API::Node``s. Instead they are ``DataFlow::Node``s with some convenience
|
||||
predicates that allows you to recover ``API::Node``s for the return value as well as for arguments
|
||||
to the call. This enables you to constrain the call in various ways using the API graph. The following
|
||||
snippet finds all calls to ``re.compile`` where the ``pattern`` argument comes from parsing a command
|
||||
line argument using the ``argparse`` library.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import python
|
||||
import semmle.python.ApiGraphs
|
||||
|
||||
from API::CallNode call
|
||||
where
|
||||
call = API::moduleImport("re").getMember("compile").getACall() and
|
||||
call.getParameter(0, "pattern") =
|
||||
API::moduleImport("argparse")
|
||||
.getMember("ArgumentParser")
|
||||
.getReturn()
|
||||
.getMember("parse_args")
|
||||
.getMember(_)
|
||||
select call
|
||||
|
||||
|
||||
Note that the API graph does not distinguish between class instantiations and function calls. As far
|
||||
as it's concerned, both are simply places where an API graph node is called.
|
||||
@@ -122,7 +146,7 @@ all subclasses of ``View``, you must explicitly include the subclasses of ``Meth
|
||||
API::moduleImport("flask").getMember("views").getMember(["View", "MethodView"]).getASubclass*()
|
||||
}
|
||||
|
||||
select viewClass().getAUse()
|
||||
select viewClass().getAValueReachableFromSource()
|
||||
|
||||
Note the use of the set literal ``["View", "MethodView"]`` to match both classes simultaneously.
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 111 KiB |
7
docs/codeql/reusables/beta-note-mrva.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Multi-repository variant analysis is currently available as a beta release and is subject to change. To use this feature, you must upgrade the CodeQL extension for Visual Studio Code to a minimum of version 1.8.0.
|
||||
|
||||
You can report your feedback in the community discussion for the beta release: https://gh.io/mrva-public-beta-discussion.
|
||||
@@ -248,7 +248,9 @@ module Public {
|
||||
/**
|
||||
* Holds if all the summaries that apply to `this` are auto generated and not manually created.
|
||||
*/
|
||||
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
|
||||
final predicate isAutoGenerated() {
|
||||
this.hasProvenance(["generated", "ai-generated"]) and not this.isManual()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a manual summary that applies to `this`.
|
||||
@@ -268,7 +270,7 @@ module Public {
|
||||
/**
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { neutralElement(this, "generated") }
|
||||
predicate isAutoGenerated() { neutralElement(this, ["generated", "ai-generated"]) }
|
||||
|
||||
/**
|
||||
* Holds if there exists a manual neutral that applies to `this`.
|
||||
@@ -1202,11 +1204,11 @@ module Private {
|
||||
}
|
||||
|
||||
private string renderProvenance(SummarizedCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
if c.isManual() then result = "manual" else c.hasProvenance(result)
|
||||
}
|
||||
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
if c.isManual() then result = "manual" else c.hasProvenance(result)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,8 +39,8 @@ jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,,
|
||||
jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,94,55
|
||||
java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
java.io,37,,42,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,22,,,,,,,,41,1
|
||||
java.lang,13,,76,,,,,,,,,,,,8,,,,,,,4,,,1,,,,,,,,,,,,,,,,53,23
|
||||
java.net,10,3,7,,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,,,,,3,7,
|
||||
java.lang,14,,76,,,,,,,,,,,,8,,,,,1,,4,,,1,,,,,,,,,,,,,,,,53,23
|
||||
java.net,10,3,9,,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,,,,,3,9,
|
||||
java.nio,16,,16,,13,,,,,,,,,,,,,,,1,,,,,,,,,,,,,2,,,,,,,,16,
|
||||
java.sql,11,,2,,,,,,,,4,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,,1,1
|
||||
java.util,44,,465,,,,,,,,,,,,34,,,,,,,,5,2,,1,2,,,,,,,,,,,,,,38,427
|
||||
@@ -74,10 +74,12 @@ org.apache.commons.logging,6,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
org.apache.commons.ognl,6,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,220,52
|
||||
org.apache.directory.ldap.client.api,1,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
org.apache.hadoop.hive.metastore,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,
|
||||
org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
org.apache.hc.core5.http,1,2,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,2,39,
|
||||
org.apache.hc.core5.net,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,
|
||||
org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6
|
||||
org.apache.hive.hcatalog.templeton,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,
|
||||
org.apache.http,27,3,70,,,,,,,,,,,,,,,25,,,,,,,,,,,,,,,,,,2,,,,3,62,8
|
||||
org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,57,
|
||||
org.apache.log4j,11,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
|
||||
|
@@ -18,10 +18,10 @@ Java framework & library support
|
||||
`Google Guava <https://guava.dev/>`_,``com.google.common.*``,,728,39,,6,,,,,
|
||||
JBoss Logging,``org.jboss.logging``,,,324,,,,,,,
|
||||
`JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,,,
|
||||
Java Standard Library,``java.*``,3,609,131,28,,,7,,,10
|
||||
Java Standard Library,``java.*``,3,611,132,28,,,7,,,10
|
||||
Java extensions,"``javax.*``, ``jakarta.*``",63,609,32,,,4,,1,1,2
|
||||
Kotlin Standard Library,``kotlin*``,,1835,12,10,,,,,,2
|
||||
`Spring <https://spring.io/>`_,``org.springframework.*``,29,477,101,,,,19,14,,29
|
||||
Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",60,300,269,,,,14,18,,3
|
||||
Totals,,217,8456,1564,129,6,10,107,33,1,86
|
||||
Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",60,300,273,,,,18,18,,3
|
||||
Totals,,217,8458,1569,129,6,10,111,33,1,86
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle). Suspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in <test-root-directory>/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`",
|
||||
"markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle).\n\nSuspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in <test-root-directory>/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle). Suspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in <test-root-directory>/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`",
|
||||
"markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle).\n\nSuspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in <test-root-directory>/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies. Suspicious output line: `[ERROR] COMPILATION ERROR : `",
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies.\n\nSuspicious output line: `[ERROR] COMPILATION ERROR : `",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies. Suspicious output line: `[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`",
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies.\n\nSuspicious output line: `[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -27,7 +27,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies. Suspicious output line: `org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`",
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies.\n\nSuspicious output line: `org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [supply credentials for any private dependencies](https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`",
|
||||
"markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [supply credentials for any private dependencies](https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows).\n\nSuspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin). Suspicious output line: `> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`",
|
||||
"markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin).\n\nSuspicious output line: `> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin). Suspicious output line: `Caused by: java.lang.IllegalArgumentException: Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`",
|
||||
"markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin).\n\nSuspicious output line: `Caused by: java.lang.IllegalArgumentException: Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked).\n\nSuspicious output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked).\n\nSuspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -27,7 +27,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked).\n\nSuspicious output line: `Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -41,7 +41,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `[ERROR] Failed to execute goal on project maven-sample: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11: Failed to read artifact descriptor for junit-nonesuch:junit-nonesuch:jar:4.11: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)] -> [Help 1]`",
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked).\n\nSuspicious output line: `[ERROR] Failed to execute goal on project maven-sample: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11: Failed to read artifact descriptor for junit-nonesuch:junit-nonesuch:jar:4.11: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)] -> [Help 1]`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "Building using Maven was skipped because there were multiple sibling build directories containing build files: [./maven-project-1,./maven-project-2]. If you want to use one of these, please [manually supply a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language)",
|
||||
"markdownMessage": "Building using Maven was skipped because there were multiple sibling build directories containing build files: [./maven-project-1,./maven-project-2]. If you want to use one of these, please [manually supply a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language).",
|
||||
"severity": "warning",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "If you want to use one of the candidate build systems and directories (see previous warnings), please [supply a manual a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language)",
|
||||
"markdownMessage": "If you want to use one of the candidate build systems and directories (see previous warnings), please [supply a manual a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "Could not find a Gradle, Maven or Ant top-level project to build. Please [supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language)",
|
||||
"markdownMessage": "Could not find a Gradle, Maven or Ant top-level project to build. Please [supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Gradle project does not define a `testClasses` goal. [Supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language) that builds the code that should be analyzed. Suspicious output line: `org.gradle.execution.TaskSelectionException: Task 'testClasses' not found in root project 'no-gradle-test-classes'.`",
|
||||
"markdownMessage": "Gradle project does not define a `testClasses` goal. [Supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language) that builds the code that should be analyzed.\n\nSuspicious output line: `org.gradle.execution.TaskSelectionException: Task 'testClasses' not found in root project 'no-gradle-test-classes'.`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 1.8.30",
|
||||
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 1.8.30.",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
"id": "java/extractor-agent/kotlin-version-too-new",
|
||||
"name": "Android build failure"
|
||||
"name": "Kotlin version too new"
|
||||
},
|
||||
"visibility": {
|
||||
"cliSummaryTable": true,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added new sinks for `java/hardcoded-credential-api-call` to identify the use of hardcoded secrets in the creation and verification of JWT tokens using `com.auth0.jwt`. These sinks are from [an experimental query submitted by @luchua](https://github.com/github/codeql/pull/9036).
|
||||
@@ -3,6 +3,8 @@ extensions:
|
||||
pack: codeql/java-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["java.lang", "Module", True, "getResourceAsStream", "(String)", "", "Argument[0]", "read-file", "ai-generated"]
|
||||
# suggested label is not supported: - ["java.lang", "ProcessBuilder", True, "ProcessBuilder", "(String[])", "", "Argument[0]", "command-injection", "ai-generated"]
|
||||
- ["java.lang", "String", False, "matches", "(String)", "", "Argument[0]", "regex-use[f-1]", "manual"]
|
||||
- ["java.lang", "String", False, "replaceAll", "(String,String)", "", "Argument[0]", "regex-use[-1]", "manual"]
|
||||
- ["java.lang", "String", False, "replaceFirst", "(String,String)", "", "Argument[0]", "regex-use[-1]", "manual"]
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["org.apache.hadoop.hive.metastore.api", "DefaultConstraintsRequest", True, "DefaultConstraintsRequest", "(String,String,String)", "", "Argument[1]", "sql", "ai-generated"]
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["org.apache.hadoop.hive.metastore", "ObjectStore", True, "updatePartitionColumnStatistics", "(ColumnStatistics,List,String,long)", "", "Argument[0]", "sql", "ai-generated"]
|
||||
- ["org.apache.hadoop.hive.metastore", "ObjectStore", True, "updatePartitionColumnStatistics", "(ColumnStatistics,List)", "", "Argument[0]", "sql", "ai-generated"]
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["org.apache.hive.hcatalog.templeton", "HcatDelegator", True, "addOneColumn", "(String,String,String,ColumnDesc)", "", "Argument[3]", "sql", "ai-generated"]
|
||||
|
||||
@@ -67,9 +67,10 @@
|
||||
* "taint" indicates a default additional taint step and "value" indicates a
|
||||
* globally applicable value-preserving step.
|
||||
* 9. The `provenance` column is a tag to indicate the origin of the summary.
|
||||
* There are two supported values: "generated" and "manual". "generated" means that
|
||||
* the model has been emitted by the model generator tool and "manual" means
|
||||
* that the model has been written by hand.
|
||||
* The supported values are: "manual", "generated" and "ai-generated". "manual"
|
||||
* means that the model has been written by hand, "generated" means that
|
||||
* the model has been emitted by the model generator tool and
|
||||
* "ai-generated" means that the model has been AI generated (ATM project).
|
||||
*/
|
||||
|
||||
import java
|
||||
@@ -308,7 +309,7 @@ module ModelValidation {
|
||||
not ext.regexpMatch("|Annotated") and
|
||||
result = "Unrecognized extra API graph element \"" + ext + "\" in " + pred + " model."
|
||||
or
|
||||
not provenance = ["manual", "generated"] and
|
||||
not provenance = ["manual", "generated", "ai-generated"] and
|
||||
result = "Unrecognized provenance description \"" + provenance + "\" in " + pred + " model."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -248,7 +248,9 @@ module Public {
|
||||
/**
|
||||
* Holds if all the summaries that apply to `this` are auto generated and not manually created.
|
||||
*/
|
||||
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
|
||||
final predicate isAutoGenerated() {
|
||||
this.hasProvenance(["generated", "ai-generated"]) and not this.isManual()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a manual summary that applies to `this`.
|
||||
@@ -268,7 +270,7 @@ module Public {
|
||||
/**
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { neutralElement(this, "generated") }
|
||||
predicate isAutoGenerated() { neutralElement(this, ["generated", "ai-generated"]) }
|
||||
|
||||
/**
|
||||
* Holds if there exists a manual neutral that applies to `this`.
|
||||
@@ -1202,11 +1204,11 @@ module Private {
|
||||
}
|
||||
|
||||
private string renderProvenance(SummarizedCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
if c.isManual() then result = "manual" else c.hasProvenance(result)
|
||||
}
|
||||
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
if c.isManual() then result = "manual" else c.hasProvenance(result)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -490,5 +490,11 @@ private predicate otherApiCallableCredentialParam(string s) {
|
||||
"com.microsoft.sqlserver.jdbc.SQLServerDataSource;setPassword(String);0",
|
||||
"com.microsoft.sqlserver.jdbc.SQLServerDataSource;getConnection(String, String);0",
|
||||
"com.microsoft.sqlserver.jdbc.SQLServerDataSource;getConnection(String, String);1",
|
||||
"com.auth0.jwt.algorithms.Algorithm;HMAC256(String);0",
|
||||
"com.auth0.jwt.algorithms.Algorithm;HMAC256(byte[]);0",
|
||||
"com.auth0.jwt.algorithms.Algorithm;HMAC384(String);0",
|
||||
"com.auth0.jwt.algorithms.Algorithm;HMAC384(byte[]);0",
|
||||
"com.auth0.jwt.algorithms.Algorithm;HMAC512(String);0",
|
||||
"com.auth0.jwt.algorithms.Algorithm;HMAC512(byte[]);0"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ private int getNumMadModeledApis(string package, string provenance) {
|
||||
or
|
||||
sc.isManual() and
|
||||
(
|
||||
if sc.hasProvenance("generated")
|
||||
if sc.hasProvenance(["generated", "ai-generated"])
|
||||
then
|
||||
// "both"
|
||||
provenance = "both"
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// BAD: Get secret from hardcoded string then sign a JWT token
|
||||
Algorithm algorithm = Algorithm.HMAC256("hardcoded_secret");
|
||||
JWT.create()
|
||||
.withClaim("username", username)
|
||||
.sign(algorithm);
|
||||
}
|
||||
|
||||
// BAD: Get secret from hardcoded string then verify a JWT token
|
||||
JWTVerifier verifier = JWT.require(Algorithm.HMAC256("hardcoded_secret"))
|
||||
.withIssuer(ISSUER)
|
||||
.build();
|
||||
verifier.verify(token);
|
||||
|
||||
// GOOD: Get secret from system configuration then sign a token
|
||||
String tokenSecret = System.getenv("SECRET_KEY");
|
||||
Algorithm algorithm = Algorithm.HMAC256(tokenSecret);
|
||||
JWT.create()
|
||||
.withClaim("username", username)
|
||||
.sign(algorithm);
|
||||
}
|
||||
|
||||
// GOOD: Get secret from environment variable then verify a JWT token
|
||||
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(System.getenv("SECRET_KEY")))
|
||||
.withIssuer(ISSUER)
|
||||
.build();
|
||||
verifier.verify(token);
|
||||
@@ -1,46 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
JWT (JSON Web Token) is an open standard (RFC 7519) that defines a way to provide information
|
||||
within a JSON object between two parties. JWT is widely used for sharing security information
|
||||
between two parties in web applications. Each JWT contains encoded JSON objects, including a
|
||||
set of claims. JWTs are signed using a cryptographic algorithm to ensure that the claims cannot
|
||||
be altered after the token is issued.
|
||||
</p>
|
||||
<p>
|
||||
The most basic mistake is using hardcoded secrets for JWT generation/verification. This allows
|
||||
an attacker to forge the token if the source code (and JWT secret in it) is publicly exposed or
|
||||
leaked, which leads to authentication bypass or privilege escalation.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Generating a cryptographically secure secret key during application initialization and using this
|
||||
generated key for JWT signing/verification requests can prevent this vulnerability. Or safely store
|
||||
the secret key in a key vault that cannot be leaked in source code.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following examples show the bad case and the good case respectively. The <code>bad</code>
|
||||
methods show a hardcoded secret key is used to sign and verify JWT tokens. In the <code>good</code>
|
||||
method, the secret key is loaded from a system environment during application initialization.
|
||||
</p>
|
||||
<sample src="HardcodedJwtKey.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Semgrep Blog:
|
||||
<a href="https://r2c.dev/blog/2020/hardcoded-secrets-unverified-tokens-and-other-common-jwt-mistakes/">Hardcoded secrets, unverified tokens, and other common JWT mistakes</a>
|
||||
</li>
|
||||
<li>
|
||||
CVE-2022-24860:
|
||||
<a href="https://nvd.nist.gov/vuln/detail/CVE-2022-24860">Databasir 1.01 has Use of Hard-coded Cryptographic Key vulnerability.</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* @name Use of a hardcoded key for signing JWT
|
||||
* @description Using a hardcoded key for signing JWT can allow an attacker to compromise security.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @id java/hardcoded-jwt-key
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-321
|
||||
*/
|
||||
|
||||
import java
|
||||
import HardcodedJwtKey
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, HardcodedJwtKeyConfiguration cfg
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ is used to sign a JWT token.", source.getNode(),
|
||||
"Hardcoded String"
|
||||
@@ -1,131 +0,0 @@
|
||||
/**
|
||||
* Provides sources and sinks for detecting JWT token signing vulnerabilities.
|
||||
*/
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
private class ActivateModels extends ActiveExperimentalModels {
|
||||
ActivateModels() { this = "hardcoded-jwt-key" }
|
||||
}
|
||||
|
||||
/** The class `com.auth0.jwt.JWT`. */
|
||||
class Jwt extends RefType {
|
||||
Jwt() { this.hasQualifiedName("com.auth0.jwt", "JWT") }
|
||||
}
|
||||
|
||||
/** The class `com.auth0.jwt.JWTCreator.Builder`. */
|
||||
class JwtBuilder extends RefType {
|
||||
JwtBuilder() { this.hasQualifiedName("com.auth0.jwt", "JWTCreator$Builder") }
|
||||
}
|
||||
|
||||
/** The class `com.auth0.jwt.algorithms.Algorithm`. */
|
||||
class JwtAlgorithm extends RefType {
|
||||
JwtAlgorithm() { this.hasQualifiedName("com.auth0.jwt.algorithms", "Algorithm") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface `com.auth0.jwt.interfaces.JWTVerifier` or its implementation
|
||||
* `com.auth0.jwt.JWTVerifier`.
|
||||
*/
|
||||
class JwtVerifier extends RefType {
|
||||
JwtVerifier() {
|
||||
this.hasQualifiedName(["com.auth0.jwt", "com.auth0.jwt.interfaces"], "JWTVerifier")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method that creates an instance of `com.auth0.jwt.algorithms.Algorithm`. */
|
||||
class GetAlgorithmMethod extends Method {
|
||||
GetAlgorithmMethod() {
|
||||
this.getDeclaringType() instanceof JwtAlgorithm and
|
||||
this.getName().matches(["HMAC%", "ECDSA%", "RSA%"])
|
||||
}
|
||||
}
|
||||
|
||||
/** The `require` method of `com.auth0.jwt.JWT`. */
|
||||
class RequireMethod extends Method {
|
||||
RequireMethod() {
|
||||
this.getDeclaringType() instanceof Jwt and
|
||||
this.hasName("require")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `sign` method of `com.auth0.jwt.JWTCreator.Builder`. */
|
||||
class SignTokenMethod extends Method {
|
||||
SignTokenMethod() {
|
||||
this.getDeclaringType() instanceof JwtBuilder and
|
||||
this.hasName("sign")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `verify` method of `com.auth0.jwt.interfaces.JWTVerifier`. */
|
||||
class VerifyTokenMethod extends Method {
|
||||
VerifyTokenMethod() {
|
||||
this.getDeclaringType() instanceof JwtVerifier and
|
||||
this.hasName("verify")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow source for JWT token signing vulnerabilities.
|
||||
*/
|
||||
abstract class JwtKeySource extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for JWT token signing vulnerabilities.
|
||||
*/
|
||||
abstract class JwtTokenSink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A hardcoded string literal as a source for JWT token signing vulnerabilities.
|
||||
*/
|
||||
class HardcodedKeyStringSource extends JwtKeySource {
|
||||
HardcodedKeyStringSource() { exists(this.asExpr().(CompileTimeConstantExpr).getStringValue()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression used to sign JWT tokens as a sink of JWT token signing vulnerabilities.
|
||||
*/
|
||||
private class SignTokenSink extends JwtTokenSink {
|
||||
SignTokenSink() {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof SignTokenMethod and
|
||||
this.asExpr() = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression used to verify JWT tokens as a sink of JWT token signing vulnerabilities.
|
||||
*/
|
||||
private class VerifyTokenSink extends JwtTokenSink {
|
||||
VerifyTokenSink() {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof VerifyTokenMethod and
|
||||
this.asExpr() = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration depicting taint flow for checking JWT token signing vulnerabilities.
|
||||
*/
|
||||
class HardcodedJwtKeyConfiguration extends TaintTracking::Configuration {
|
||||
HardcodedJwtKeyConfiguration() { this = "Hard-coded JWT Signing Key" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof JwtKeySource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof JwtTokenSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ) {
|
||||
exists(MethodAccess ma |
|
||||
(
|
||||
ma.getMethod() instanceof GetAlgorithmMethod or
|
||||
ma.getMethod() instanceof RequireMethod
|
||||
) and
|
||||
prev.asExpr() = ma.getArgument(0) and
|
||||
succ.asExpr() = ma
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -10,5 +10,5 @@ import semmle.code.java.dataflow.ExternalFlow
|
||||
from string package, string type, string name, string signature, string provenance
|
||||
where
|
||||
neutralModel(package, type, name, signature, provenance) and
|
||||
provenance != "generated"
|
||||
provenance != ["generated", "ai-generated"]
|
||||
select package, type, name, signature, provenance order by package, type, name, signature
|
||||
|
||||
@@ -12,6 +12,6 @@ from
|
||||
string input, string kind, string provenance
|
||||
where
|
||||
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
|
||||
provenance != "generated"
|
||||
provenance != ["generated", "ai-generated"]
|
||||
select package, type, subtypes, name, signature, ext, input, kind, provenance order by
|
||||
package, type, name, signature, input, kind
|
||||
|
||||
@@ -12,6 +12,6 @@ from
|
||||
string output, string kind, string provenance
|
||||
where
|
||||
sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance) and
|
||||
provenance != "generated"
|
||||
provenance != ["generated", "ai-generated"]
|
||||
select package, type, subtypes, name, signature, ext, output, kind, provenance order by
|
||||
package, type, name, signature, output, kind
|
||||
|
||||
@@ -12,6 +12,6 @@ from
|
||||
string input, string output, string kind, string provenance
|
||||
where
|
||||
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance) and
|
||||
provenance != "generated"
|
||||
provenance != ["generated", "ai-generated"]
|
||||
select package, type, subtypes, name, signature, ext, input, output, kind, provenance order by
|
||||
package, type, name, signature, input, output, kind
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
edges
|
||||
| HardcodedJwtKey.java:15:33:15:38 | SECRET : String | HardcodedJwtKey.java:19:49:19:54 | SECRET : String |
|
||||
| HardcodedJwtKey.java:15:33:15:38 | SECRET : String | HardcodedJwtKey.java:42:62:42:67 | SECRET : String |
|
||||
| HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" : String | HardcodedJwtKey.java:15:33:15:38 | SECRET : String |
|
||||
| HardcodedJwtKey.java:19:49:19:54 | SECRET : String | HardcodedJwtKey.java:25:23:25:31 | algorithm |
|
||||
| HardcodedJwtKey.java:42:32:42:69 | require(...) : Verification | HardcodedJwtKey.java:42:32:43:35 | withIssuer(...) : Verification |
|
||||
| HardcodedJwtKey.java:42:32:43:35 | withIssuer(...) : Verification | HardcodedJwtKey.java:42:32:44:24 | build(...) : JWTVerifier |
|
||||
| HardcodedJwtKey.java:42:32:44:24 | build(...) : JWTVerifier | HardcodedJwtKey.java:46:13:46:20 | verifier |
|
||||
| HardcodedJwtKey.java:42:62:42:67 | SECRET : String | HardcodedJwtKey.java:42:32:42:69 | require(...) : Verification |
|
||||
nodes
|
||||
| HardcodedJwtKey.java:15:33:15:38 | SECRET : String | semmle.label | SECRET : String |
|
||||
| HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" : String | semmle.label | "hardcoded_secret" : String |
|
||||
| HardcodedJwtKey.java:19:49:19:54 | SECRET : String | semmle.label | SECRET : String |
|
||||
| HardcodedJwtKey.java:25:23:25:31 | algorithm | semmle.label | algorithm |
|
||||
| HardcodedJwtKey.java:42:32:42:69 | require(...) : Verification | semmle.label | require(...) : Verification |
|
||||
| HardcodedJwtKey.java:42:32:43:35 | withIssuer(...) : Verification | semmle.label | withIssuer(...) : Verification |
|
||||
| HardcodedJwtKey.java:42:32:44:24 | build(...) : JWTVerifier | semmle.label | build(...) : JWTVerifier |
|
||||
| HardcodedJwtKey.java:42:62:42:67 | SECRET : String | semmle.label | SECRET : String |
|
||||
| HardcodedJwtKey.java:46:13:46:20 | verifier | semmle.label | verifier |
|
||||
subpaths
|
||||
#select
|
||||
| HardcodedJwtKey.java:25:23:25:31 | algorithm | HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" : String | HardcodedJwtKey.java:25:23:25:31 | algorithm | $@ is used to sign a JWT token. | HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" | Hardcoded String |
|
||||
| HardcodedJwtKey.java:25:23:25:31 | algorithm | HardcodedJwtKey.java:19:49:19:54 | SECRET : String | HardcodedJwtKey.java:25:23:25:31 | algorithm | $@ is used to sign a JWT token. | HardcodedJwtKey.java:19:49:19:54 | SECRET | Hardcoded String |
|
||||
| HardcodedJwtKey.java:46:13:46:20 | verifier | HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" : String | HardcodedJwtKey.java:46:13:46:20 | verifier | $@ is used to sign a JWT token. | HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" | Hardcoded String |
|
||||
| HardcodedJwtKey.java:46:13:46:20 | verifier | HardcodedJwtKey.java:42:62:42:67 | SECRET : String | HardcodedJwtKey.java:46:13:46:20 | verifier | $@ is used to sign a JWT token. | HardcodedJwtKey.java:42:62:42:67 | SECRET | Hardcoded String |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-321/HardcodedJwtKey.ql
|
||||
@@ -1 +0,0 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/auth0-jwt-2.3
|
||||
@@ -14,6 +14,7 @@ edges
|
||||
| Test.java:95:14:95:34 | getHostName(...) : String | Test.java:99:12:99:33 | new URI(...) |
|
||||
| Test.java:95:14:95:34 | getHostName(...) : String | Test.java:100:12:100:45 | new URI(...) |
|
||||
| Test.java:95:14:95:34 | getHostName(...) : String | Test.java:101:12:101:54 | new URI(...) |
|
||||
| Test.java:105:14:105:34 | getHostName(...) : String | Test.java:107:46:107:46 | t |
|
||||
nodes
|
||||
| Test.java:19:18:19:38 | getHostName(...) : String | semmle.label | getHostName(...) : String |
|
||||
| Test.java:24:20:24:23 | temp | semmle.label | temp |
|
||||
@@ -34,6 +35,8 @@ nodes
|
||||
| Test.java:99:12:99:33 | new URI(...) | semmle.label | new URI(...) |
|
||||
| Test.java:100:12:100:45 | new URI(...) | semmle.label | new URI(...) |
|
||||
| Test.java:101:12:101:54 | new URI(...) | semmle.label | new URI(...) |
|
||||
| Test.java:105:14:105:34 | getHostName(...) : String | semmle.label | getHostName(...) : String |
|
||||
| Test.java:107:46:107:46 | t | semmle.label | t |
|
||||
subpaths
|
||||
#select
|
||||
| Test.java:24:11:24:24 | new File(...) | Test.java:19:18:19:38 | getHostName(...) : String | Test.java:24:20:24:23 | temp | This path depends on a $@. | Test.java:19:18:19:38 | getHostName(...) | user-provided value |
|
||||
@@ -47,3 +50,4 @@ subpaths
|
||||
| Test.java:99:3:99:34 | new File(...) | Test.java:95:14:95:34 | getHostName(...) : String | Test.java:99:12:99:33 | new URI(...) | This path depends on a $@. | Test.java:95:14:95:34 | getHostName(...) | user-provided value |
|
||||
| Test.java:100:3:100:46 | new File(...) | Test.java:95:14:95:34 | getHostName(...) : String | Test.java:100:12:100:45 | new URI(...) | This path depends on a $@. | Test.java:95:14:95:34 | getHostName(...) | user-provided value |
|
||||
| Test.java:101:3:101:55 | new File(...) | Test.java:95:14:95:34 | getHostName(...) : String | Test.java:101:12:101:54 | new URI(...) | This path depends on a $@. | Test.java:95:14:95:34 | getHostName(...) | user-provided value |
|
||||
| Test.java:107:46:107:46 | t | Test.java:105:14:105:34 | getHostName(...) : String | Test.java:107:46:107:46 | t | This path depends on a $@. | Test.java:105:14:105:34 | getHostName(...) | user-provided value |
|
||||
|
||||
@@ -100,4 +100,10 @@ class Test {
|
||||
new File(new URI(null, null, t, null, null));
|
||||
new File(new URI(null, null, null, 0, t, null, null));
|
||||
}
|
||||
|
||||
void doGet6(InetAddress address) throws IOException {
|
||||
String t = address.getHostName();
|
||||
// BAD: accessing local resource with user input
|
||||
getClass().getModule().getResourceAsStream(t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import org.apache.hadoop.hive.metastore.api.ColumnStatistics;
|
||||
import org.apache.hadoop.hive.metastore.api.DefaultConstraintsRequest;
|
||||
import org.apache.hadoop.hive.metastore.ObjectStore;
|
||||
import org.apache.hive.hcatalog.templeton.ColumnDesc;
|
||||
import org.apache.hive.hcatalog.templeton.HcatDelegator;
|
||||
import java.util.List;
|
||||
|
||||
public class Hive {
|
||||
|
||||
public static Object source() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void test(ObjectStore objStore, HcatDelegator hcatDel) throws Exception {
|
||||
{
|
||||
String taint = (String) source();
|
||||
new DefaultConstraintsRequest("", taint, ""); // $ sqlInjection
|
||||
}
|
||||
{
|
||||
ColumnStatistics taint = (ColumnStatistics) source();
|
||||
//objStore.updatePartitionColumnStatistics(taint, (List<String>) null, (String) null, 0L); // $ sqlInjection
|
||||
objStore.updatePartitionColumnStatistics(taint, (List<String>) null); // $ sqlInjection
|
||||
}
|
||||
{
|
||||
ColumnDesc taint = (ColumnDesc) source();
|
||||
hcatDel.addOneColumn(null, null, null, taint); // $ sqlInjection
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient:${testdir}/../../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient:${testdir}/../../../../../stubs/springframework-5.3.8:${testdir}/../../../../../stubs/apache-hive
|
||||
|
||||
@@ -16,7 +16,7 @@ public class HardcodedJwtKey {
|
||||
|
||||
// BAD: Get secret from hardcoded string then sign a JWT token
|
||||
public String accessTokenBad(String username) {
|
||||
Algorithm algorithm = Algorithm.HMAC256(SECRET);
|
||||
Algorithm algorithm = Algorithm.HMAC256(SECRET); // $ HardcodedCredentialsApiCall
|
||||
|
||||
return JWT.create()
|
||||
.withExpiresAt(new Date(new Date().getTime() + ACCESS_EXPIRE_TIME))
|
||||
@@ -39,7 +39,7 @@ public class HardcodedJwtKey {
|
||||
|
||||
// BAD: Get secret from hardcoded string then verify a JWT token
|
||||
public boolean verifyTokenBad(String token) {
|
||||
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET))
|
||||
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)) // $ HardcodedCredentialsApiCall
|
||||
.withIssuer(ISSUER)
|
||||
.build();
|
||||
try {
|
||||
@@ -62,4 +62,49 @@ public class HardcodedJwtKey {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String accessTokenBad384(String username) {
|
||||
Algorithm algorithm = Algorithm.HMAC384(SECRET); // $ HardcodedCredentialsApiCall
|
||||
|
||||
return JWT.create()
|
||||
.withExpiresAt(new Date(new Date().getTime() + ACCESS_EXPIRE_TIME))
|
||||
.withIssuer(ISSUER)
|
||||
.withClaim("username", username)
|
||||
.sign(algorithm);
|
||||
}
|
||||
|
||||
// GOOD: Get secret from system configuration then sign a token
|
||||
public String accessTokenGood384(String username) {
|
||||
String tokenSecret = System.getenv("SECRET_KEY");
|
||||
Algorithm algorithm = Algorithm.HMAC384(tokenSecret);
|
||||
|
||||
return JWT.create()
|
||||
.withExpiresAt(new Date(new Date().getTime() + ACCESS_EXPIRE_TIME))
|
||||
.withIssuer(ISSUER)
|
||||
.withClaim("username", username)
|
||||
.sign(algorithm);
|
||||
}
|
||||
|
||||
public String accessTokenBad512(String username) {
|
||||
Algorithm algorithm = Algorithm.HMAC512(SECRET); // $ HardcodedCredentialsApiCall
|
||||
|
||||
return JWT.create()
|
||||
.withExpiresAt(new Date(new Date().getTime() + ACCESS_EXPIRE_TIME))
|
||||
.withIssuer(ISSUER)
|
||||
.withClaim("username", username)
|
||||
.sign(algorithm);
|
||||
}
|
||||
|
||||
// GOOD: Get secret from system configuration then sign a token
|
||||
public String accessTokenGood512(String username) {
|
||||
String tokenSecret = System.getenv("SECRET_KEY");
|
||||
Algorithm algorithm = Algorithm.HMAC512(tokenSecret);
|
||||
|
||||
return JWT.create()
|
||||
.withExpiresAt(new Date(new Date().getTime() + ACCESS_EXPIRE_TIME))
|
||||
.withIssuer(ISSUER)
|
||||
.withClaim("username", username)
|
||||
.sign(algorithm);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700:${testdir}/../../../../../stubs/azure-sdk-for-java:${testdir}/../../../../../stubs/shiro-core-1.4.0:${testdir}/../../../../../stubs/jsch-0.1.55:${testdir}/../../../../../stubs/ganymed-ssh-2-260:${testdir}/../../../../../stubs/apache-mina-sshd-2.8.0:${testdir}/../../../../../stubs/sshj-0.33.0:${testdir}/../../../../../stubs/j2ssh-1.5.5:${testdir}/../../../../../stubs/trilead-ssh2-212:${testdir}/../../../../../stubs/apache-commons-net-3.8.0:${testdir}/../../../../../stubs/mongodbClient:${testdir}/../../../../../stubs/mssql-jdbc-12.2.0
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700:${testdir}/../../../../../stubs/azure-sdk-for-java:${testdir}/../../../../../stubs/shiro-core-1.4.0:${testdir}/../../../../../stubs/jsch-0.1.55:${testdir}/../../../../../stubs/ganymed-ssh-2-260:${testdir}/../../../../../stubs/apache-mina-sshd-2.8.0:${testdir}/../../../../../stubs/sshj-0.33.0:${testdir}/../../../../../stubs/j2ssh-1.5.5:${testdir}/../../../../../stubs/trilead-ssh2-212:${testdir}/../../../../../stubs/apache-commons-net-3.8.0:${testdir}/../../../../../stubs/mongodbClient:${testdir}/../../../../../stubs/mssql-jdbc-12.2.0:${testdir}/../../../../../stubs/auth0-jwt-2.3
|
||||
|
||||
59
java/ql/test/stubs/apache-hive/com/google/protobuf/AbstractMessage.java
generated
Normal file
@@ -0,0 +1,59 @@
|
||||
// Generated automatically from com.google.protobuf.AbstractMessage for testing purposes
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.AbstractMessageLite;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.CodedInputStream;
|
||||
import com.google.protobuf.CodedOutputStream;
|
||||
import com.google.protobuf.Descriptors;
|
||||
import com.google.protobuf.ExtensionRegistryLite;
|
||||
import com.google.protobuf.Internal;
|
||||
import com.google.protobuf.Message;
|
||||
import com.google.protobuf.UninitializedMessageException;
|
||||
import com.google.protobuf.UnknownFieldSet;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
abstract public class AbstractMessage extends AbstractMessageLite implements Message
|
||||
{
|
||||
abstract static public class Builder<BuilderType extends AbstractMessage.Builder> extends AbstractMessageLite.Builder<BuilderType> implements Message.Builder
|
||||
{
|
||||
protected static UninitializedMessageException newUninitializedMessageException(Message p0){ return null; }
|
||||
public Builder(){}
|
||||
public BuilderType clear(){ return null; }
|
||||
public BuilderType mergeFrom(ByteString p0){ return null; }
|
||||
public BuilderType mergeFrom(ByteString p0, ExtensionRegistryLite p1){ return null; }
|
||||
public BuilderType mergeFrom(CodedInputStream p0){ return null; }
|
||||
public BuilderType mergeFrom(CodedInputStream p0, ExtensionRegistryLite p1){ return null; }
|
||||
public BuilderType mergeFrom(InputStream p0){ return null; }
|
||||
public BuilderType mergeFrom(InputStream p0, ExtensionRegistryLite p1){ return null; }
|
||||
public BuilderType mergeFrom(Message p0){ return null; }
|
||||
public BuilderType mergeFrom(byte[] p0){ return null; }
|
||||
public BuilderType mergeFrom(byte[] p0, ExtensionRegistryLite p1){ return null; }
|
||||
public BuilderType mergeFrom(byte[] p0, int p1, int p2){ return null; }
|
||||
public BuilderType mergeFrom(byte[] p0, int p1, int p2, ExtensionRegistryLite p3){ return null; }
|
||||
public BuilderType mergeUnknownFields(UnknownFieldSet p0){ return null; }
|
||||
public List<String> findInitializationErrors(){ return null; }
|
||||
public Message.Builder getFieldBuilder(Descriptors.FieldDescriptor p0){ return null; }
|
||||
public String getInitializationErrorString(){ return null; }
|
||||
public abstract BuilderType clone();
|
||||
public boolean mergeDelimitedFrom(InputStream p0){ return false; }
|
||||
public boolean mergeDelimitedFrom(InputStream p0, ExtensionRegistryLite p1){ return false; }
|
||||
}
|
||||
protected int hashFields(int p0, Map<Descriptors.FieldDescriptor, Object> p1){ return 0; }
|
||||
protected static int hashBoolean(boolean p0){ return 0; }
|
||||
protected static int hashEnum(Internal.EnumLite p0){ return 0; }
|
||||
protected static int hashEnumList(List<? extends Internal.EnumLite> p0){ return 0; }
|
||||
protected static int hashLong(long p0){ return 0; }
|
||||
public AbstractMessage(){}
|
||||
public List<String> findInitializationErrors(){ return null; }
|
||||
public String getInitializationErrorString(){ return null; }
|
||||
public boolean equals(Object p0){ return false; }
|
||||
public boolean isInitialized(){ return false; }
|
||||
public final String toString(){ return null; }
|
||||
public int getSerializedSize(){ return 0; }
|
||||
public int hashCode(){ return 0; }
|
||||
public void writeTo(CodedOutputStream p0){}
|
||||
}
|
||||
40
java/ql/test/stubs/apache-hive/com/google/protobuf/AbstractMessageLite.java
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
// Generated automatically from com.google.protobuf.AbstractMessageLite for testing purposes
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.CodedInputStream;
|
||||
import com.google.protobuf.ExtensionRegistryLite;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import com.google.protobuf.UninitializedMessageException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
|
||||
abstract public class AbstractMessageLite implements MessageLite
|
||||
{
|
||||
abstract static public class Builder<BuilderType extends AbstractMessageLite.Builder> implements MessageLite.Builder
|
||||
{
|
||||
protected static <T> void addAll(java.lang.Iterable<T> p0, Collection<? super T> p1){}
|
||||
protected static UninitializedMessageException newUninitializedMessageException(MessageLite p0){ return null; }
|
||||
public Builder(){}
|
||||
public BuilderType mergeFrom(ByteString p0){ return null; }
|
||||
public BuilderType mergeFrom(ByteString p0, ExtensionRegistryLite p1){ return null; }
|
||||
public BuilderType mergeFrom(CodedInputStream p0){ return null; }
|
||||
public BuilderType mergeFrom(InputStream p0){ return null; }
|
||||
public BuilderType mergeFrom(InputStream p0, ExtensionRegistryLite p1){ return null; }
|
||||
public BuilderType mergeFrom(byte[] p0){ return null; }
|
||||
public BuilderType mergeFrom(byte[] p0, ExtensionRegistryLite p1){ return null; }
|
||||
public BuilderType mergeFrom(byte[] p0, int p1, int p2){ return null; }
|
||||
public BuilderType mergeFrom(byte[] p0, int p1, int p2, ExtensionRegistryLite p3){ return null; }
|
||||
public abstract BuilderType clone();
|
||||
public abstract BuilderType mergeFrom(CodedInputStream p0, ExtensionRegistryLite p1);
|
||||
public boolean mergeDelimitedFrom(InputStream p0){ return false; }
|
||||
public boolean mergeDelimitedFrom(InputStream p0, ExtensionRegistryLite p1){ return false; }
|
||||
}
|
||||
public AbstractMessageLite(){}
|
||||
public ByteString toByteString(){ return null; }
|
||||
public byte[] toByteArray(){ return null; }
|
||||
public void writeDelimitedTo(OutputStream p0){}
|
||||
public void writeTo(OutputStream p0){}
|
||||
}
|
||||
38
java/ql/test/stubs/apache-hive/com/google/protobuf/AbstractParser.java
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
// Generated automatically from com.google.protobuf.AbstractParser for testing purposes
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.CodedInputStream;
|
||||
import com.google.protobuf.ExtensionRegistryLite;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import com.google.protobuf.Parser;
|
||||
import java.io.InputStream;
|
||||
|
||||
abstract public class AbstractParser<MessageType extends MessageLite> implements Parser<MessageType>
|
||||
{
|
||||
public AbstractParser(){}
|
||||
public MessageType parseDelimitedFrom(InputStream p0){ return null; }
|
||||
public MessageType parseDelimitedFrom(InputStream p0, ExtensionRegistryLite p1){ return null; }
|
||||
public MessageType parseFrom(ByteString p0){ return null; }
|
||||
public MessageType parseFrom(ByteString p0, ExtensionRegistryLite p1){ return null; }
|
||||
public MessageType parseFrom(CodedInputStream p0){ return null; }
|
||||
public MessageType parseFrom(CodedInputStream p0, ExtensionRegistryLite p1){ return null; }
|
||||
public MessageType parseFrom(InputStream p0){ return null; }
|
||||
public MessageType parseFrom(InputStream p0, ExtensionRegistryLite p1){ return null; }
|
||||
public MessageType parseFrom(byte[] p0){ return null; }
|
||||
public MessageType parseFrom(byte[] p0, ExtensionRegistryLite p1){ return null; }
|
||||
public MessageType parseFrom(byte[] p0, int p1, int p2){ return null; }
|
||||
public MessageType parseFrom(byte[] p0, int p1, int p2, ExtensionRegistryLite p3){ return null; }
|
||||
public MessageType parsePartialDelimitedFrom(InputStream p0){ return null; }
|
||||
public MessageType parsePartialDelimitedFrom(InputStream p0, ExtensionRegistryLite p1){ return null; }
|
||||
public MessageType parsePartialFrom(ByteString p0){ return null; }
|
||||
public MessageType parsePartialFrom(ByteString p0, ExtensionRegistryLite p1){ return null; }
|
||||
public MessageType parsePartialFrom(CodedInputStream p0){ return null; }
|
||||
public MessageType parsePartialFrom(InputStream p0){ return null; }
|
||||
public MessageType parsePartialFrom(InputStream p0, ExtensionRegistryLite p1){ return null; }
|
||||
public MessageType parsePartialFrom(byte[] p0){ return null; }
|
||||
public MessageType parsePartialFrom(byte[] p0, ExtensionRegistryLite p1){ return null; }
|
||||
public MessageType parsePartialFrom(byte[] p0, int p1, int p2){ return null; }
|
||||
public MessageType parsePartialFrom(byte[] p0, int p1, int p2, ExtensionRegistryLite p3){ return null; }
|
||||
}
|
||||
72
java/ql/test/stubs/apache-hive/com/google/protobuf/ByteString.java
generated
Normal file
@@ -0,0 +1,72 @@
|
||||
// Generated automatically from com.google.protobuf.ByteString for testing purposes
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.CodedInputStream;
|
||||
import com.google.protobuf.CodedOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
abstract public class ByteString implements Iterable<Byte>
|
||||
{
|
||||
protected abstract boolean isBalanced();
|
||||
protected abstract int getTreeDepth();
|
||||
protected abstract int partialHash(int p0, int p1, int p2);
|
||||
protected abstract int partialIsValidUtf8(int p0, int p1, int p2);
|
||||
protected abstract int peekCachedHashCode();
|
||||
protected abstract void copyToInternal(byte[] p0, int p1, int p2, int p3);
|
||||
public ByteString concat(ByteString p0){ return null; }
|
||||
public ByteString substring(int p0){ return null; }
|
||||
public String toString(){ return null; }
|
||||
public String toStringUtf8(){ return null; }
|
||||
public abstract ByteBuffer asReadOnlyByteBuffer();
|
||||
public abstract ByteString substring(int p0, int p1);
|
||||
public abstract ByteString.ByteIterator iterator();
|
||||
public abstract CodedInputStream newCodedInput();
|
||||
public abstract InputStream newInput();
|
||||
public abstract List<ByteBuffer> asReadOnlyByteBufferList();
|
||||
public abstract String toString(String p0);
|
||||
public abstract boolean equals(Object p0);
|
||||
public abstract boolean isValidUtf8();
|
||||
public abstract byte byteAt(int p0);
|
||||
public abstract int hashCode();
|
||||
public abstract int size();
|
||||
public abstract void copyTo(ByteBuffer p0);
|
||||
public abstract void writeTo(OutputStream p0);
|
||||
public boolean isEmpty(){ return false; }
|
||||
public boolean startsWith(ByteString p0){ return false; }
|
||||
public byte[] toByteArray(){ return null; }
|
||||
public static ByteString EMPTY = null;
|
||||
public static ByteString copyFrom(ByteBuffer p0){ return null; }
|
||||
public static ByteString copyFrom(ByteBuffer p0, int p1){ return null; }
|
||||
public static ByteString copyFrom(Iterable<ByteString> p0){ return null; }
|
||||
public static ByteString copyFrom(String p0, String p1){ return null; }
|
||||
public static ByteString copyFrom(byte[] p0){ return null; }
|
||||
public static ByteString copyFrom(byte[] p0, int p1, int p2){ return null; }
|
||||
public static ByteString copyFromUtf8(String p0){ return null; }
|
||||
public static ByteString readFrom(InputStream p0){ return null; }
|
||||
public static ByteString readFrom(InputStream p0, int p1){ return null; }
|
||||
public static ByteString readFrom(InputStream p0, int p1, int p2){ return null; }
|
||||
public static ByteString.Output newOutput(){ return null; }
|
||||
public static ByteString.Output newOutput(int p0){ return null; }
|
||||
public void copyTo(byte[] p0, int p1){}
|
||||
public void copyTo(byte[] p0, int p1, int p2, int p3){}
|
||||
static public class Output extends OutputStream
|
||||
{
|
||||
protected Output() {}
|
||||
public ByteString toByteString(){ return null; }
|
||||
public String toString(){ return null; }
|
||||
public int size(){ return 0; }
|
||||
public void reset(){}
|
||||
public void write(byte[] p0, int p1, int p2){}
|
||||
public void write(int p0){}
|
||||
public void writeTo(OutputStream p0){}
|
||||
}
|
||||
static public interface ByteIterator extends Iterator<Byte>
|
||||
{
|
||||
byte nextByte();
|
||||
}
|
||||
}
|
||||
60
java/ql/test/stubs/apache-hive/com/google/protobuf/CodedInputStream.java
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
// Generated automatically from com.google.protobuf.CodedInputStream for testing purposes
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.ExtensionRegistryLite;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import com.google.protobuf.Parser;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class CodedInputStream
|
||||
{
|
||||
protected CodedInputStream() {}
|
||||
public <T extends MessageLite> T readGroup(int p0, com.google.protobuf.Parser<T> p1, ExtensionRegistryLite p2){ return null; }
|
||||
public <T extends MessageLite> T readMessage(com.google.protobuf.Parser<T> p0, ExtensionRegistryLite p1){ return null; }
|
||||
public ByteString readBytes(){ return null; }
|
||||
public String readString(){ return null; }
|
||||
public boolean isAtEnd(){ return false; }
|
||||
public boolean readBool(){ return false; }
|
||||
public boolean skipField(int p0){ return false; }
|
||||
public byte readRawByte(){ return 0; }
|
||||
public byte[] readRawBytes(int p0){ return null; }
|
||||
public double readDouble(){ return 0; }
|
||||
public float readFloat(){ return 0; }
|
||||
public int getBytesUntilLimit(){ return 0; }
|
||||
public int getTotalBytesRead(){ return 0; }
|
||||
public int pushLimit(int p0){ return 0; }
|
||||
public int readEnum(){ return 0; }
|
||||
public int readFixed32(){ return 0; }
|
||||
public int readInt32(){ return 0; }
|
||||
public int readRawLittleEndian32(){ return 0; }
|
||||
public int readRawVarint32(){ return 0; }
|
||||
public int readSFixed32(){ return 0; }
|
||||
public int readSInt32(){ return 0; }
|
||||
public int readTag(){ return 0; }
|
||||
public int readUInt32(){ return 0; }
|
||||
public int setRecursionLimit(int p0){ return 0; }
|
||||
public int setSizeLimit(int p0){ return 0; }
|
||||
public long readFixed64(){ return 0; }
|
||||
public long readInt64(){ return 0; }
|
||||
public long readRawLittleEndian64(){ return 0; }
|
||||
public long readRawVarint64(){ return 0; }
|
||||
public long readSFixed64(){ return 0; }
|
||||
public long readSInt64(){ return 0; }
|
||||
public long readUInt64(){ return 0; }
|
||||
public static CodedInputStream newInstance(InputStream p0){ return null; }
|
||||
public static CodedInputStream newInstance(byte[] p0){ return null; }
|
||||
public static CodedInputStream newInstance(byte[] p0, int p1, int p2){ return null; }
|
||||
public static int decodeZigZag32(int p0){ return 0; }
|
||||
public static int readRawVarint32(int p0, InputStream p1){ return 0; }
|
||||
public static long decodeZigZag64(long p0){ return 0; }
|
||||
public void checkLastTagWas(int p0){}
|
||||
public void popLimit(int p0){}
|
||||
public void readGroup(int p0, MessageLite.Builder p1, ExtensionRegistryLite p2){}
|
||||
public void readMessage(MessageLite.Builder p0, ExtensionRegistryLite p1){}
|
||||
public void readUnknownGroup(int p0, MessageLite.Builder p1){}
|
||||
public void resetSizeCounter(){}
|
||||
public void skipMessage(){}
|
||||
public void skipRawBytes(int p0){}
|
||||
}
|
||||
122
java/ql/test/stubs/apache-hive/com/google/protobuf/CodedOutputStream.java
generated
Normal file
@@ -0,0 +1,122 @@
|
||||
// Generated automatically from com.google.protobuf.CodedOutputStream for testing purposes
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.LazyField;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class CodedOutputStream
|
||||
{
|
||||
protected CodedOutputStream() {}
|
||||
public int spaceLeft(){ return 0; }
|
||||
public static CodedOutputStream newInstance(OutputStream p0){ return null; }
|
||||
public static CodedOutputStream newInstance(OutputStream p0, int p1){ return null; }
|
||||
public static CodedOutputStream newInstance(byte[] p0){ return null; }
|
||||
public static CodedOutputStream newInstance(byte[] p0, int p1, int p2){ return null; }
|
||||
public static int DEFAULT_BUFFER_SIZE = 0;
|
||||
public static int LITTLE_ENDIAN_32_SIZE = 0;
|
||||
public static int LITTLE_ENDIAN_64_SIZE = 0;
|
||||
public static int computeBoolSize(int p0, boolean p1){ return 0; }
|
||||
public static int computeBoolSizeNoTag(boolean p0){ return 0; }
|
||||
public static int computeBytesSize(int p0, ByteString p1){ return 0; }
|
||||
public static int computeBytesSizeNoTag(ByteString p0){ return 0; }
|
||||
public static int computeDoubleSize(int p0, double p1){ return 0; }
|
||||
public static int computeDoubleSizeNoTag(double p0){ return 0; }
|
||||
public static int computeEnumSize(int p0, int p1){ return 0; }
|
||||
public static int computeEnumSizeNoTag(int p0){ return 0; }
|
||||
public static int computeFixed32Size(int p0, int p1){ return 0; }
|
||||
public static int computeFixed32SizeNoTag(int p0){ return 0; }
|
||||
public static int computeFixed64Size(int p0, long p1){ return 0; }
|
||||
public static int computeFixed64SizeNoTag(long p0){ return 0; }
|
||||
public static int computeFloatSize(int p0, float p1){ return 0; }
|
||||
public static int computeFloatSizeNoTag(float p0){ return 0; }
|
||||
public static int computeGroupSize(int p0, MessageLite p1){ return 0; }
|
||||
public static int computeGroupSizeNoTag(MessageLite p0){ return 0; }
|
||||
public static int computeInt32Size(int p0, int p1){ return 0; }
|
||||
public static int computeInt32SizeNoTag(int p0){ return 0; }
|
||||
public static int computeInt64Size(int p0, long p1){ return 0; }
|
||||
public static int computeInt64SizeNoTag(long p0){ return 0; }
|
||||
public static int computeLazyFieldMessageSetExtensionSize(int p0, LazyField p1){ return 0; }
|
||||
public static int computeLazyFieldSize(int p0, LazyField p1){ return 0; }
|
||||
public static int computeLazyFieldSizeNoTag(LazyField p0){ return 0; }
|
||||
public static int computeMessageSetExtensionSize(int p0, MessageLite p1){ return 0; }
|
||||
public static int computeMessageSize(int p0, MessageLite p1){ return 0; }
|
||||
public static int computeMessageSizeNoTag(MessageLite p0){ return 0; }
|
||||
public static int computeRawMessageSetExtensionSize(int p0, ByteString p1){ return 0; }
|
||||
public static int computeRawVarint32Size(int p0){ return 0; }
|
||||
public static int computeRawVarint64Size(long p0){ return 0; }
|
||||
public static int computeSFixed32Size(int p0, int p1){ return 0; }
|
||||
public static int computeSFixed32SizeNoTag(int p0){ return 0; }
|
||||
public static int computeSFixed64Size(int p0, long p1){ return 0; }
|
||||
public static int computeSFixed64SizeNoTag(long p0){ return 0; }
|
||||
public static int computeSInt32Size(int p0, int p1){ return 0; }
|
||||
public static int computeSInt32SizeNoTag(int p0){ return 0; }
|
||||
public static int computeSInt64Size(int p0, long p1){ return 0; }
|
||||
public static int computeSInt64SizeNoTag(long p0){ return 0; }
|
||||
public static int computeStringSize(int p0, String p1){ return 0; }
|
||||
public static int computeStringSizeNoTag(String p0){ return 0; }
|
||||
public static int computeTagSize(int p0){ return 0; }
|
||||
public static int computeUInt32Size(int p0, int p1){ return 0; }
|
||||
public static int computeUInt32SizeNoTag(int p0){ return 0; }
|
||||
public static int computeUInt64Size(int p0, long p1){ return 0; }
|
||||
public static int computeUInt64SizeNoTag(long p0){ return 0; }
|
||||
public static int computeUnknownGroupSize(int p0, MessageLite p1){ return 0; }
|
||||
public static int computeUnknownGroupSizeNoTag(MessageLite p0){ return 0; }
|
||||
public static int encodeZigZag32(int p0){ return 0; }
|
||||
public static long encodeZigZag64(long p0){ return 0; }
|
||||
public void checkNoSpaceLeft(){}
|
||||
public void flush(){}
|
||||
public void writeBool(int p0, boolean p1){}
|
||||
public void writeBoolNoTag(boolean p0){}
|
||||
public void writeBytes(int p0, ByteString p1){}
|
||||
public void writeBytesNoTag(ByteString p0){}
|
||||
public void writeDouble(int p0, double p1){}
|
||||
public void writeDoubleNoTag(double p0){}
|
||||
public void writeEnum(int p0, int p1){}
|
||||
public void writeEnumNoTag(int p0){}
|
||||
public void writeFixed32(int p0, int p1){}
|
||||
public void writeFixed32NoTag(int p0){}
|
||||
public void writeFixed64(int p0, long p1){}
|
||||
public void writeFixed64NoTag(long p0){}
|
||||
public void writeFloat(int p0, float p1){}
|
||||
public void writeFloatNoTag(float p0){}
|
||||
public void writeGroup(int p0, MessageLite p1){}
|
||||
public void writeGroupNoTag(MessageLite p0){}
|
||||
public void writeInt32(int p0, int p1){}
|
||||
public void writeInt32NoTag(int p0){}
|
||||
public void writeInt64(int p0, long p1){}
|
||||
public void writeInt64NoTag(long p0){}
|
||||
public void writeMessage(int p0, MessageLite p1){}
|
||||
public void writeMessageNoTag(MessageLite p0){}
|
||||
public void writeMessageSetExtension(int p0, MessageLite p1){}
|
||||
public void writeRawByte(byte p0){}
|
||||
public void writeRawByte(int p0){}
|
||||
public void writeRawBytes(ByteString p0){}
|
||||
public void writeRawBytes(ByteString p0, int p1, int p2){}
|
||||
public void writeRawBytes(byte[] p0){}
|
||||
public void writeRawBytes(byte[] p0, int p1, int p2){}
|
||||
public void writeRawLittleEndian32(int p0){}
|
||||
public void writeRawLittleEndian64(long p0){}
|
||||
public void writeRawMessageSetExtension(int p0, ByteString p1){}
|
||||
public void writeRawVarint32(int p0){}
|
||||
public void writeRawVarint64(long p0){}
|
||||
public void writeSFixed32(int p0, int p1){}
|
||||
public void writeSFixed32NoTag(int p0){}
|
||||
public void writeSFixed64(int p0, long p1){}
|
||||
public void writeSFixed64NoTag(long p0){}
|
||||
public void writeSInt32(int p0, int p1){}
|
||||
public void writeSInt32NoTag(int p0){}
|
||||
public void writeSInt64(int p0, long p1){}
|
||||
public void writeSInt64NoTag(long p0){}
|
||||
public void writeString(int p0, String p1){}
|
||||
public void writeStringNoTag(String p0){}
|
||||
public void writeTag(int p0, int p1){}
|
||||
public void writeUInt32(int p0, int p1){}
|
||||
public void writeUInt32NoTag(int p0){}
|
||||
public void writeUInt64(int p0, long p1){}
|
||||
public void writeUInt64NoTag(long p0){}
|
||||
public void writeUnknownGroup(int p0, MessageLite p1){}
|
||||
public void writeUnknownGroupNoTag(MessageLite p0){}
|
||||
}
|
||||