circle-ir 4.14.0 → 4.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/passes/sink-filter-pass.d.ts.map +1 -1
- package/dist/analysis/passes/sink-filter-pass.js +47 -14
- package/dist/analysis/passes/sink-filter-pass.js.map +1 -1
- package/dist/analysis/taint-matcher.d.ts.map +1 -1
- package/dist/analysis/taint-matcher.js +9 -3
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/analysis/taint-propagation.d.ts +0 -6
- package/dist/analysis/taint-propagation.d.ts.map +1 -1
- package/dist/analysis/taint-propagation.js +12 -2
- package/dist/analysis/taint-propagation.js.map +1 -1
- package/dist/browser/circle-ir.js +75 -24
- package/dist/core/circle-ir-core.cjs +41 -11
- package/dist/core/circle-ir-core.js +41 -11
- package/dist/core/extractors/dfg.js +38 -8
- package/dist/core/extractors/dfg.js.map +1 -1
- package/package.json +1 -1
|
@@ -10196,6 +10196,36 @@ function extractFieldDefs(body2, startId) {
|
|
|
10196
10196
|
function extractJSParameterDefs(params, startId) {
|
|
10197
10197
|
const defs = [];
|
|
10198
10198
|
let id = startId;
|
|
10199
|
+
const addPatternDefs = (patternNode, line) => {
|
|
10200
|
+
if (patternNode.type === "identifier" || patternNode.type === "shorthand_property_identifier_pattern") {
|
|
10201
|
+
defs.push({
|
|
10202
|
+
id: id++,
|
|
10203
|
+
variable: getNodeText(patternNode),
|
|
10204
|
+
line,
|
|
10205
|
+
kind: "param"
|
|
10206
|
+
});
|
|
10207
|
+
return;
|
|
10208
|
+
}
|
|
10209
|
+
if (patternNode.type === "rest_pattern" || patternNode.type === "rest_element") {
|
|
10210
|
+
const nameNode = patternNode.namedChildCount > 0 ? patternNode.namedChild(0) : null;
|
|
10211
|
+
if (!nameNode) return;
|
|
10212
|
+
addPatternDefs(nameNode, line);
|
|
10213
|
+
return;
|
|
10214
|
+
}
|
|
10215
|
+
if (patternNode.type === "assignment_pattern") {
|
|
10216
|
+
const leftNode = patternNode.childForFieldName("left");
|
|
10217
|
+
if (leftNode) addPatternDefs(leftNode, line);
|
|
10218
|
+
return;
|
|
10219
|
+
}
|
|
10220
|
+
if (patternNode.type === "object_pattern" || patternNode.type === "array_pattern") {
|
|
10221
|
+
const destructDefs = extractDestructuringDefs(patternNode, id);
|
|
10222
|
+
for (const def of destructDefs) {
|
|
10223
|
+
def.kind = "param";
|
|
10224
|
+
defs.push(def);
|
|
10225
|
+
id++;
|
|
10226
|
+
}
|
|
10227
|
+
}
|
|
10228
|
+
};
|
|
10199
10229
|
for (let i2 = 0; i2 < params.childCount; i2++) {
|
|
10200
10230
|
const param = params.child(i2);
|
|
10201
10231
|
if (!param) continue;
|
|
@@ -10243,14 +10273,7 @@ function extractJSParameterDefs(params, startId) {
|
|
|
10243
10273
|
}
|
|
10244
10274
|
} else if (param.type === "required_parameter" || param.type === "optional_parameter") {
|
|
10245
10275
|
const patternNode = param.childForFieldName("pattern");
|
|
10246
|
-
if (patternNode
|
|
10247
|
-
defs.push({
|
|
10248
|
-
id: id++,
|
|
10249
|
-
variable: getNodeText(patternNode),
|
|
10250
|
-
line: param.startPosition.row + 1,
|
|
10251
|
-
kind: "param"
|
|
10252
|
-
});
|
|
10253
|
-
}
|
|
10276
|
+
if (patternNode) addPatternDefs(patternNode, param.startPosition.row + 1);
|
|
10254
10277
|
}
|
|
10255
10278
|
}
|
|
10256
10279
|
return defs;
|
|
@@ -15766,7 +15789,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
15766
15789
|
if (skipMethods.includes(method.name)) continue;
|
|
15767
15790
|
for (const param of method.parameters) {
|
|
15768
15791
|
const hasCSharpBindingAttr = language === "csharp" && param.annotations.some((a) => CSHARP_BINDING_ATTRS.has(a));
|
|
15769
|
-
const
|
|
15792
|
+
const isDestructureBinding = param.name.startsWith("{") || param.name.startsWith("[");
|
|
15793
|
+
const isTaintable = hasCSharpBindingAttr ? true : isDestructureBinding ? true : param.type ? isInterproceduralTaintableType(param.type, language) : true;
|
|
15770
15794
|
if (isTaintable) {
|
|
15771
15795
|
const paramLine = param.line ?? method.start_line;
|
|
15772
15796
|
sources.push({
|
|
@@ -19255,6 +19279,9 @@ function buildSanitizersByLine(sanitizers) {
|
|
|
19255
19279
|
}
|
|
19256
19280
|
return out2;
|
|
19257
19281
|
}
|
|
19282
|
+
function concatOutsideStrings(expression) {
|
|
19283
|
+
return expression.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, " ").includes("+");
|
|
19284
|
+
}
|
|
19258
19285
|
function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanitizers, sanitizersArg) {
|
|
19259
19286
|
let graph;
|
|
19260
19287
|
let sources;
|
|
@@ -19286,6 +19313,7 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
|
|
|
19286
19313
|
}
|
|
19287
19314
|
const taintedVars = [];
|
|
19288
19315
|
const flows = [];
|
|
19316
|
+
const javaConcat = graph.ir.meta.language === "java";
|
|
19289
19317
|
const reachableSinks = /* @__PURE__ */ new Map();
|
|
19290
19318
|
const defsByLine = graph.defsByLine;
|
|
19291
19319
|
const usesByLine = graph.usesByLine;
|
|
@@ -19322,12 +19350,14 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
|
|
|
19322
19350
|
continue;
|
|
19323
19351
|
}
|
|
19324
19352
|
}
|
|
19325
|
-
const
|
|
19353
|
+
const expr = typeof arg.expression === "string" ? arg.expression : "";
|
|
19354
|
+
const compoundConcat = javaConcat && !!arg.variable && expr !== arg.variable && concatOutsideStrings(expr);
|
|
19355
|
+
const candidateUses = arg.variable && !compoundConcat ? usesAtSink.filter((u) => u.variable === arg.variable) : usesAtSink;
|
|
19326
19356
|
{
|
|
19327
19357
|
for (const use of candidateUses) {
|
|
19328
19358
|
if (use.def_id !== null) {
|
|
19329
19359
|
if (allTaintedDefIds.has(use.def_id)) {
|
|
19330
|
-
if (!arg.variable) {
|
|
19360
|
+
if (!arg.variable || compoundConcat) {
|
|
19331
19361
|
if (typeof arg.expression !== "string" || arg.expression.length === 0) continue;
|
|
19332
19362
|
const re = new RegExp(`(?:^|[^A-Za-z0-9_$])${use.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:[^A-Za-z0-9_$]|$)`);
|
|
19333
19363
|
if (!re.test(arg.expression)) continue;
|
|
@@ -37344,6 +37374,20 @@ function evaluateSimpleExpression(expr, symbols) {
|
|
|
37344
37374
|
if (result !== null && !isNaN(result)) return String(Math.floor(result));
|
|
37345
37375
|
return expr;
|
|
37346
37376
|
}
|
|
37377
|
+
var ARGUMENT_IDENT_SKIP = /* @__PURE__ */ new Set(["new", "true", "false", "null", "this", "super"]);
|
|
37378
|
+
function isStringConcat(expression) {
|
|
37379
|
+
return expression.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, " ").includes("+");
|
|
37380
|
+
}
|
|
37381
|
+
function argumentIdentifiers(expression) {
|
|
37382
|
+
const stripped = expression.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, " ");
|
|
37383
|
+
const found = stripped.match(/[A-Za-z_$][A-Za-z0-9_$]*/g) ?? [];
|
|
37384
|
+
const out2 = [];
|
|
37385
|
+
for (const id of found) {
|
|
37386
|
+
if (ARGUMENT_IDENT_SKIP.has(id)) continue;
|
|
37387
|
+
if (!out2.includes(id)) out2.push(id);
|
|
37388
|
+
}
|
|
37389
|
+
return out2;
|
|
37390
|
+
}
|
|
37347
37391
|
function isStringLiteralExpression(expr) {
|
|
37348
37392
|
const trimmed = expr.trim();
|
|
37349
37393
|
if (trimmed.length < 2) return false;
|
|
@@ -37415,20 +37459,27 @@ function filterCleanVariableSinks(sinks, calls, taintedVars, symbols, dfg, sanit
|
|
|
37415
37459
|
dangerousArgCount++;
|
|
37416
37460
|
if (language === "bash" && arg.expression === call.method_name && !arg.variable && arg.literal == null) continue;
|
|
37417
37461
|
if (arg.variable && !arg.expression?.includes("[")) {
|
|
37418
|
-
const
|
|
37419
|
-
const
|
|
37420
|
-
|
|
37421
|
-
|
|
37422
|
-
|
|
37423
|
-
|
|
37424
|
-
|
|
37425
|
-
|
|
37426
|
-
|
|
37427
|
-
|
|
37462
|
+
const expr = arg.expression ?? "";
|
|
37463
|
+
const concatNames = language === "java" && isStringConcat(expr) ? argumentIdentifiers(expr) : [];
|
|
37464
|
+
const names = concatNames.length > 0 ? concatNames : [arg.variable];
|
|
37465
|
+
let argClean = true;
|
|
37466
|
+
for (const varName of names) {
|
|
37467
|
+
const scopedName = methodName ? `${methodName}:${varName}` : varName;
|
|
37468
|
+
if (fieldNames.has(varName) && !isInSynchronizedBlock) {
|
|
37469
|
+
argClean = false;
|
|
37470
|
+
break;
|
|
37471
|
+
}
|
|
37472
|
+
if (sanitizedVars?.has(scopedName) || sanitizedVars?.has(varName)) continue;
|
|
37473
|
+
if (taintedVars.has(scopedName) || taintedVars.has(varName)) {
|
|
37474
|
+
argClean = false;
|
|
37475
|
+
break;
|
|
37476
|
+
}
|
|
37477
|
+
const symbolValue = symbols.get(scopedName) ?? symbols.get(varName);
|
|
37478
|
+
if (symbolValue && symbolValue.type !== "unknown") continue;
|
|
37479
|
+
argClean = false;
|
|
37480
|
+
break;
|
|
37428
37481
|
}
|
|
37429
|
-
|
|
37430
|
-
if (symbolValue && symbolValue.type !== "unknown") continue;
|
|
37431
|
-
allArgsAreClean = false;
|
|
37482
|
+
if (!argClean) allArgsAreClean = false;
|
|
37432
37483
|
} else {
|
|
37433
37484
|
if (arg.literal != null) continue;
|
|
37434
37485
|
if (arg.expression && !arg.variable && isStringLiteralExpression(arg.expression)) continue;
|
|
@@ -10242,6 +10242,36 @@ function extractFieldDefs(body2, startId) {
|
|
|
10242
10242
|
function extractJSParameterDefs(params, startId) {
|
|
10243
10243
|
const defs = [];
|
|
10244
10244
|
let id = startId;
|
|
10245
|
+
const addPatternDefs = (patternNode, line) => {
|
|
10246
|
+
if (patternNode.type === "identifier" || patternNode.type === "shorthand_property_identifier_pattern") {
|
|
10247
|
+
defs.push({
|
|
10248
|
+
id: id++,
|
|
10249
|
+
variable: getNodeText(patternNode),
|
|
10250
|
+
line,
|
|
10251
|
+
kind: "param"
|
|
10252
|
+
});
|
|
10253
|
+
return;
|
|
10254
|
+
}
|
|
10255
|
+
if (patternNode.type === "rest_pattern" || patternNode.type === "rest_element") {
|
|
10256
|
+
const nameNode = patternNode.namedChildCount > 0 ? patternNode.namedChild(0) : null;
|
|
10257
|
+
if (!nameNode) return;
|
|
10258
|
+
addPatternDefs(nameNode, line);
|
|
10259
|
+
return;
|
|
10260
|
+
}
|
|
10261
|
+
if (patternNode.type === "assignment_pattern") {
|
|
10262
|
+
const leftNode = patternNode.childForFieldName("left");
|
|
10263
|
+
if (leftNode) addPatternDefs(leftNode, line);
|
|
10264
|
+
return;
|
|
10265
|
+
}
|
|
10266
|
+
if (patternNode.type === "object_pattern" || patternNode.type === "array_pattern") {
|
|
10267
|
+
const destructDefs = extractDestructuringDefs(patternNode, id);
|
|
10268
|
+
for (const def of destructDefs) {
|
|
10269
|
+
def.kind = "param";
|
|
10270
|
+
defs.push(def);
|
|
10271
|
+
id++;
|
|
10272
|
+
}
|
|
10273
|
+
}
|
|
10274
|
+
};
|
|
10245
10275
|
for (let i2 = 0; i2 < params.childCount; i2++) {
|
|
10246
10276
|
const param = params.child(i2);
|
|
10247
10277
|
if (!param) continue;
|
|
@@ -10289,14 +10319,7 @@ function extractJSParameterDefs(params, startId) {
|
|
|
10289
10319
|
}
|
|
10290
10320
|
} else if (param.type === "required_parameter" || param.type === "optional_parameter") {
|
|
10291
10321
|
const patternNode = param.childForFieldName("pattern");
|
|
10292
|
-
if (patternNode
|
|
10293
|
-
defs.push({
|
|
10294
|
-
id: id++,
|
|
10295
|
-
variable: getNodeText(patternNode),
|
|
10296
|
-
line: param.startPosition.row + 1,
|
|
10297
|
-
kind: "param"
|
|
10298
|
-
});
|
|
10299
|
-
}
|
|
10322
|
+
if (patternNode) addPatternDefs(patternNode, param.startPosition.row + 1);
|
|
10300
10323
|
}
|
|
10301
10324
|
}
|
|
10302
10325
|
return defs;
|
|
@@ -15066,7 +15089,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
15066
15089
|
if (skipMethods.includes(method.name)) continue;
|
|
15067
15090
|
for (const param of method.parameters) {
|
|
15068
15091
|
const hasCSharpBindingAttr = language === "csharp" && param.annotations.some((a) => CSHARP_BINDING_ATTRS.has(a));
|
|
15069
|
-
const
|
|
15092
|
+
const isDestructureBinding = param.name.startsWith("{") || param.name.startsWith("[");
|
|
15093
|
+
const isTaintable = hasCSharpBindingAttr ? true : isDestructureBinding ? true : param.type ? isInterproceduralTaintableType(param.type, language) : true;
|
|
15070
15094
|
if (isTaintable) {
|
|
15071
15095
|
const paramLine = param.line ?? method.start_line;
|
|
15072
15096
|
sources.push({
|
|
@@ -17220,6 +17244,9 @@ function buildSanitizersByLine(sanitizers) {
|
|
|
17220
17244
|
}
|
|
17221
17245
|
return out2;
|
|
17222
17246
|
}
|
|
17247
|
+
function concatOutsideStrings(expression) {
|
|
17248
|
+
return expression.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, " ").includes("+");
|
|
17249
|
+
}
|
|
17223
17250
|
function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanitizers, sanitizersArg) {
|
|
17224
17251
|
let graph;
|
|
17225
17252
|
let sources;
|
|
@@ -17251,6 +17278,7 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
|
|
|
17251
17278
|
}
|
|
17252
17279
|
const taintedVars = [];
|
|
17253
17280
|
const flows = [];
|
|
17281
|
+
const javaConcat = graph.ir.meta.language === "java";
|
|
17254
17282
|
const reachableSinks = /* @__PURE__ */ new Map();
|
|
17255
17283
|
const defsByLine = graph.defsByLine;
|
|
17256
17284
|
const usesByLine = graph.usesByLine;
|
|
@@ -17287,12 +17315,14 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
|
|
|
17287
17315
|
continue;
|
|
17288
17316
|
}
|
|
17289
17317
|
}
|
|
17290
|
-
const
|
|
17318
|
+
const expr = typeof arg.expression === "string" ? arg.expression : "";
|
|
17319
|
+
const compoundConcat = javaConcat && !!arg.variable && expr !== arg.variable && concatOutsideStrings(expr);
|
|
17320
|
+
const candidateUses = arg.variable && !compoundConcat ? usesAtSink.filter((u) => u.variable === arg.variable) : usesAtSink;
|
|
17291
17321
|
{
|
|
17292
17322
|
for (const use of candidateUses) {
|
|
17293
17323
|
if (use.def_id !== null) {
|
|
17294
17324
|
if (allTaintedDefIds.has(use.def_id)) {
|
|
17295
|
-
if (!arg.variable) {
|
|
17325
|
+
if (!arg.variable || compoundConcat) {
|
|
17296
17326
|
if (typeof arg.expression !== "string" || arg.expression.length === 0) continue;
|
|
17297
17327
|
const re = new RegExp(`(?:^|[^A-Za-z0-9_$])${use.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:[^A-Za-z0-9_$]|$)`);
|
|
17298
17328
|
if (!re.test(arg.expression)) continue;
|
|
@@ -10176,6 +10176,36 @@ function extractFieldDefs(body2, startId) {
|
|
|
10176
10176
|
function extractJSParameterDefs(params, startId) {
|
|
10177
10177
|
const defs = [];
|
|
10178
10178
|
let id = startId;
|
|
10179
|
+
const addPatternDefs = (patternNode, line) => {
|
|
10180
|
+
if (patternNode.type === "identifier" || patternNode.type === "shorthand_property_identifier_pattern") {
|
|
10181
|
+
defs.push({
|
|
10182
|
+
id: id++,
|
|
10183
|
+
variable: getNodeText(patternNode),
|
|
10184
|
+
line,
|
|
10185
|
+
kind: "param"
|
|
10186
|
+
});
|
|
10187
|
+
return;
|
|
10188
|
+
}
|
|
10189
|
+
if (patternNode.type === "rest_pattern" || patternNode.type === "rest_element") {
|
|
10190
|
+
const nameNode = patternNode.namedChildCount > 0 ? patternNode.namedChild(0) : null;
|
|
10191
|
+
if (!nameNode) return;
|
|
10192
|
+
addPatternDefs(nameNode, line);
|
|
10193
|
+
return;
|
|
10194
|
+
}
|
|
10195
|
+
if (patternNode.type === "assignment_pattern") {
|
|
10196
|
+
const leftNode = patternNode.childForFieldName("left");
|
|
10197
|
+
if (leftNode) addPatternDefs(leftNode, line);
|
|
10198
|
+
return;
|
|
10199
|
+
}
|
|
10200
|
+
if (patternNode.type === "object_pattern" || patternNode.type === "array_pattern") {
|
|
10201
|
+
const destructDefs = extractDestructuringDefs(patternNode, id);
|
|
10202
|
+
for (const def of destructDefs) {
|
|
10203
|
+
def.kind = "param";
|
|
10204
|
+
defs.push(def);
|
|
10205
|
+
id++;
|
|
10206
|
+
}
|
|
10207
|
+
}
|
|
10208
|
+
};
|
|
10179
10209
|
for (let i2 = 0; i2 < params.childCount; i2++) {
|
|
10180
10210
|
const param = params.child(i2);
|
|
10181
10211
|
if (!param) continue;
|
|
@@ -10223,14 +10253,7 @@ function extractJSParameterDefs(params, startId) {
|
|
|
10223
10253
|
}
|
|
10224
10254
|
} else if (param.type === "required_parameter" || param.type === "optional_parameter") {
|
|
10225
10255
|
const patternNode = param.childForFieldName("pattern");
|
|
10226
|
-
if (patternNode
|
|
10227
|
-
defs.push({
|
|
10228
|
-
id: id++,
|
|
10229
|
-
variable: getNodeText(patternNode),
|
|
10230
|
-
line: param.startPosition.row + 1,
|
|
10231
|
-
kind: "param"
|
|
10232
|
-
});
|
|
10233
|
-
}
|
|
10256
|
+
if (patternNode) addPatternDefs(patternNode, param.startPosition.row + 1);
|
|
10234
10257
|
}
|
|
10235
10258
|
}
|
|
10236
10259
|
return defs;
|
|
@@ -15000,7 +15023,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
15000
15023
|
if (skipMethods.includes(method.name)) continue;
|
|
15001
15024
|
for (const param of method.parameters) {
|
|
15002
15025
|
const hasCSharpBindingAttr = language === "csharp" && param.annotations.some((a) => CSHARP_BINDING_ATTRS.has(a));
|
|
15003
|
-
const
|
|
15026
|
+
const isDestructureBinding = param.name.startsWith("{") || param.name.startsWith("[");
|
|
15027
|
+
const isTaintable = hasCSharpBindingAttr ? true : isDestructureBinding ? true : param.type ? isInterproceduralTaintableType(param.type, language) : true;
|
|
15004
15028
|
if (isTaintable) {
|
|
15005
15029
|
const paramLine = param.line ?? method.start_line;
|
|
15006
15030
|
sources.push({
|
|
@@ -17154,6 +17178,9 @@ function buildSanitizersByLine(sanitizers) {
|
|
|
17154
17178
|
}
|
|
17155
17179
|
return out2;
|
|
17156
17180
|
}
|
|
17181
|
+
function concatOutsideStrings(expression) {
|
|
17182
|
+
return expression.replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, " ").includes("+");
|
|
17183
|
+
}
|
|
17157
17184
|
function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanitizers, sanitizersArg) {
|
|
17158
17185
|
let graph;
|
|
17159
17186
|
let sources;
|
|
@@ -17185,6 +17212,7 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
|
|
|
17185
17212
|
}
|
|
17186
17213
|
const taintedVars = [];
|
|
17187
17214
|
const flows = [];
|
|
17215
|
+
const javaConcat = graph.ir.meta.language === "java";
|
|
17188
17216
|
const reachableSinks = /* @__PURE__ */ new Map();
|
|
17189
17217
|
const defsByLine = graph.defsByLine;
|
|
17190
17218
|
const usesByLine = graph.usesByLine;
|
|
@@ -17221,12 +17249,14 @@ function propagateTaint(graphOrDfg, callsOrSources, sourcesOrSinks, sinksOrSanit
|
|
|
17221
17249
|
continue;
|
|
17222
17250
|
}
|
|
17223
17251
|
}
|
|
17224
|
-
const
|
|
17252
|
+
const expr = typeof arg.expression === "string" ? arg.expression : "";
|
|
17253
|
+
const compoundConcat = javaConcat && !!arg.variable && expr !== arg.variable && concatOutsideStrings(expr);
|
|
17254
|
+
const candidateUses = arg.variable && !compoundConcat ? usesAtSink.filter((u) => u.variable === arg.variable) : usesAtSink;
|
|
17225
17255
|
{
|
|
17226
17256
|
for (const use of candidateUses) {
|
|
17227
17257
|
if (use.def_id !== null) {
|
|
17228
17258
|
if (allTaintedDefIds.has(use.def_id)) {
|
|
17229
|
-
if (!arg.variable) {
|
|
17259
|
+
if (!arg.variable || compoundConcat) {
|
|
17230
17260
|
if (typeof arg.expression !== "string" || arg.expression.length === 0) continue;
|
|
17231
17261
|
const re = new RegExp(`(?:^|[^A-Za-z0-9_$])${use.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:[^A-Za-z0-9_$]|$)`);
|
|
17232
17262
|
if (!re.test(arg.expression)) continue;
|
|
@@ -804,6 +804,42 @@ function extractFieldDefs(body, startId) {
|
|
|
804
804
|
function extractJSParameterDefs(params, startId) {
|
|
805
805
|
const defs = [];
|
|
806
806
|
let id = startId;
|
|
807
|
+
// TypeScript wraps every parameter in required_parameter / optional_parameter.
|
|
808
|
+
// The pattern may be an identifier or a destructuring pattern (`{ id }`,
|
|
809
|
+
// `{ a: { b } }`, `{ id } = default`). Bound names are param defs, matching
|
|
810
|
+
// the JavaScript object_pattern / array_pattern branches. (cognium-dev#664)
|
|
811
|
+
const addPatternDefs = (patternNode, line) => {
|
|
812
|
+
if (patternNode.type === 'identifier' || patternNode.type === 'shorthand_property_identifier_pattern') {
|
|
813
|
+
defs.push({
|
|
814
|
+
id: id++,
|
|
815
|
+
variable: getNodeText(patternNode),
|
|
816
|
+
line,
|
|
817
|
+
kind: 'param',
|
|
818
|
+
});
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
if (patternNode.type === 'rest_pattern' || patternNode.type === 'rest_element') {
|
|
822
|
+
const nameNode = patternNode.namedChildCount > 0 ? patternNode.namedChild(0) : null;
|
|
823
|
+
if (!nameNode)
|
|
824
|
+
return;
|
|
825
|
+
addPatternDefs(nameNode, line);
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
if (patternNode.type === 'assignment_pattern') {
|
|
829
|
+
const leftNode = patternNode.childForFieldName('left');
|
|
830
|
+
if (leftNode)
|
|
831
|
+
addPatternDefs(leftNode, line);
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
if (patternNode.type === 'object_pattern' || patternNode.type === 'array_pattern') {
|
|
835
|
+
const destructDefs = extractDestructuringDefs(patternNode, id);
|
|
836
|
+
for (const def of destructDefs) {
|
|
837
|
+
def.kind = 'param';
|
|
838
|
+
defs.push(def);
|
|
839
|
+
id++;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
};
|
|
807
843
|
for (let i = 0; i < params.childCount; i++) {
|
|
808
844
|
const param = params.child(i);
|
|
809
845
|
if (!param)
|
|
@@ -865,14 +901,8 @@ function extractJSParameterDefs(params, startId) {
|
|
|
865
901
|
// TypeScript formal parameters
|
|
866
902
|
else if (param.type === 'required_parameter' || param.type === 'optional_parameter') {
|
|
867
903
|
const patternNode = param.childForFieldName('pattern');
|
|
868
|
-
if (patternNode
|
|
869
|
-
|
|
870
|
-
id: id++,
|
|
871
|
-
variable: getNodeText(patternNode),
|
|
872
|
-
line: param.startPosition.row + 1,
|
|
873
|
-
kind: 'param',
|
|
874
|
-
});
|
|
875
|
-
}
|
|
904
|
+
if (patternNode)
|
|
905
|
+
addPatternDefs(patternNode, param.startPosition.row + 1);
|
|
876
906
|
}
|
|
877
907
|
}
|
|
878
908
|
return defs;
|