circle-ir 4.9.7 → 4.9.9

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.
@@ -14862,15 +14862,25 @@ function isSafeCSharpProcessStartCall(call, pattern, language, sourceLines) {
14862
14862
  function stripCsLiterals(line) {
14863
14863
  return line.replace(/\/\/.*$/, "").replace(/@?"(?:[^"\\]|\\.)*"/g, '""').replace(/'(?:[^'\\]|\\.)'/g, "''");
14864
14864
  }
14865
+ var _csDepthLines;
14866
+ var _csDepthPrefix;
14865
14867
  function csBraceDepthBefore(lines, idx) {
14866
- let depth = 0;
14867
- for (let i2 = 0; i2 < idx && i2 < lines.length; i2++) {
14868
- for (const ch of stripCsLiterals(lines[i2])) {
14869
- if (ch === "{") depth++;
14870
- else if (ch === "}") depth--;
14868
+ if (lines !== _csDepthLines) {
14869
+ const pref = new Int32Array(lines.length + 1);
14870
+ let depth = 0;
14871
+ for (let i2 = 0; i2 < lines.length; i2++) {
14872
+ pref[i2] = depth;
14873
+ for (const ch of stripCsLiterals(lines[i2])) {
14874
+ if (ch === "{") depth++;
14875
+ else if (ch === "}") depth--;
14876
+ }
14871
14877
  }
14878
+ pref[lines.length] = depth;
14879
+ _csDepthLines = lines;
14880
+ _csDepthPrefix = pref;
14872
14881
  }
14873
- return depth;
14882
+ const clamped = idx < 0 ? 0 : idx > lines.length ? lines.length : idx;
14883
+ return _csDepthPrefix[clamped];
14874
14884
  }
14875
14885
  function netBraces(fragment) {
14876
14886
  let n = 0;
@@ -14967,6 +14977,30 @@ function csThenBlock(lines, ifIdx, rest) {
14967
14977
  }
14968
14978
  return { start: ifIdx, end: firstIdx, earlyExit: isExit(firstText.trim()) };
14969
14979
  }
14980
+ var _csGuardLines;
14981
+ var _csGuardMap;
14982
+ function csEqualityGuardIndex(lines) {
14983
+ if (lines === _csGuardLines && _csGuardMap) return _csGuardMap;
14984
+ const map = /* @__PURE__ */ new Map();
14985
+ for (let i2 = 0; i2 < lines.length; i2++) {
14986
+ const parts2 = splitCsIf(lines[i2]);
14987
+ if (!parts2) continue;
14988
+ const guard = csEqualityGuard(parts2.cond);
14989
+ if (!guard) continue;
14990
+ const entry = { i: i2, rest: parts2.rest, ifCol: parts2.ifCol, op: guard.op };
14991
+ for (const id of csIdentifiers(guard.exprSide)) {
14992
+ let arr = map.get(id);
14993
+ if (!arr) {
14994
+ arr = [];
14995
+ map.set(id, arr);
14996
+ }
14997
+ arr.push(entry);
14998
+ }
14999
+ }
15000
+ _csGuardLines = lines;
15001
+ _csGuardMap = map;
15002
+ return map;
15003
+ }
14970
15004
  function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines) {
14971
15005
  if (language !== "csharp") return false;
14972
15006
  if (pattern.type !== "ssrf") return false;
@@ -14979,20 +15013,22 @@ function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines)
14979
15013
  if (candidates.size === 0) return false;
14980
15014
  const sinkIdx = call.location.line - 1;
14981
15015
  const sinkDepth = csBraceDepthBefore(sourceLines, sinkIdx);
14982
- for (let i2 = 0; i2 < sinkIdx; i2++) {
14983
- const parts2 = splitCsIf(sourceLines[i2]);
14984
- if (!parts2) continue;
14985
- const guard = csEqualityGuard(parts2.cond);
14986
- if (!guard) continue;
14987
- const guardIds = csIdentifiers(guard.exprSide);
14988
- if (![...guardIds].some((id) => candidates.has(id))) continue;
14989
- const block = csThenBlock(sourceLines, i2, parts2.rest);
14990
- if (guard.op === "==") {
14991
- if (sinkIdx >= block.start && sinkIdx <= block.end) return true;
14992
- } else {
14993
- const guardDepth = csBraceDepthBefore(sourceLines, i2) + netBraces(stripCsLiterals(sourceLines[i2]).slice(0, parts2.ifCol));
14994
- if (block.earlyExit && sinkIdx > block.end && guardDepth === sinkDepth) {
14995
- return true;
15016
+ const guardMap = csEqualityGuardIndex(sourceLines);
15017
+ const checked = /* @__PURE__ */ new Set();
15018
+ for (const cand of candidates) {
15019
+ const guards = guardMap.get(cand);
15020
+ if (!guards) continue;
15021
+ for (const g of guards) {
15022
+ if (g.i >= sinkIdx || checked.has(g)) continue;
15023
+ checked.add(g);
15024
+ const block = csThenBlock(sourceLines, g.i, g.rest);
15025
+ if (g.op === "==") {
15026
+ if (sinkIdx >= block.start && sinkIdx <= block.end) return true;
15027
+ } else {
15028
+ const guardDepth = csBraceDepthBefore(sourceLines, g.i) + netBraces(stripCsLiterals(sourceLines[g.i]).slice(0, g.ifCol));
15029
+ if (block.earlyExit && sinkIdx > block.end && guardDepth === sinkDepth) {
15030
+ return true;
15031
+ }
14996
15032
  }
14997
15033
  }
14998
15034
  }
@@ -14796,15 +14796,25 @@ function isSafeCSharpProcessStartCall(call, pattern, language, sourceLines) {
14796
14796
  function stripCsLiterals(line) {
14797
14797
  return line.replace(/\/\/.*$/, "").replace(/@?"(?:[^"\\]|\\.)*"/g, '""').replace(/'(?:[^'\\]|\\.)'/g, "''");
14798
14798
  }
14799
+ var _csDepthLines;
14800
+ var _csDepthPrefix;
14799
14801
  function csBraceDepthBefore(lines, idx) {
14800
- let depth = 0;
14801
- for (let i2 = 0; i2 < idx && i2 < lines.length; i2++) {
14802
- for (const ch of stripCsLiterals(lines[i2])) {
14803
- if (ch === "{") depth++;
14804
- else if (ch === "}") depth--;
14802
+ if (lines !== _csDepthLines) {
14803
+ const pref = new Int32Array(lines.length + 1);
14804
+ let depth = 0;
14805
+ for (let i2 = 0; i2 < lines.length; i2++) {
14806
+ pref[i2] = depth;
14807
+ for (const ch of stripCsLiterals(lines[i2])) {
14808
+ if (ch === "{") depth++;
14809
+ else if (ch === "}") depth--;
14810
+ }
14805
14811
  }
14812
+ pref[lines.length] = depth;
14813
+ _csDepthLines = lines;
14814
+ _csDepthPrefix = pref;
14806
14815
  }
14807
- return depth;
14816
+ const clamped = idx < 0 ? 0 : idx > lines.length ? lines.length : idx;
14817
+ return _csDepthPrefix[clamped];
14808
14818
  }
14809
14819
  function netBraces(fragment) {
14810
14820
  let n = 0;
@@ -14901,6 +14911,30 @@ function csThenBlock(lines, ifIdx, rest) {
14901
14911
  }
14902
14912
  return { start: ifIdx, end: firstIdx, earlyExit: isExit(firstText.trim()) };
14903
14913
  }
14914
+ var _csGuardLines;
14915
+ var _csGuardMap;
14916
+ function csEqualityGuardIndex(lines) {
14917
+ if (lines === _csGuardLines && _csGuardMap) return _csGuardMap;
14918
+ const map = /* @__PURE__ */ new Map();
14919
+ for (let i2 = 0; i2 < lines.length; i2++) {
14920
+ const parts2 = splitCsIf(lines[i2]);
14921
+ if (!parts2) continue;
14922
+ const guard = csEqualityGuard(parts2.cond);
14923
+ if (!guard) continue;
14924
+ const entry = { i: i2, rest: parts2.rest, ifCol: parts2.ifCol, op: guard.op };
14925
+ for (const id of csIdentifiers(guard.exprSide)) {
14926
+ let arr = map.get(id);
14927
+ if (!arr) {
14928
+ arr = [];
14929
+ map.set(id, arr);
14930
+ }
14931
+ arr.push(entry);
14932
+ }
14933
+ }
14934
+ _csGuardLines = lines;
14935
+ _csGuardMap = map;
14936
+ return map;
14937
+ }
14904
14938
  function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines) {
14905
14939
  if (language !== "csharp") return false;
14906
14940
  if (pattern.type !== "ssrf") return false;
@@ -14913,20 +14947,22 @@ function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines)
14913
14947
  if (candidates.size === 0) return false;
14914
14948
  const sinkIdx = call.location.line - 1;
14915
14949
  const sinkDepth = csBraceDepthBefore(sourceLines, sinkIdx);
14916
- for (let i2 = 0; i2 < sinkIdx; i2++) {
14917
- const parts2 = splitCsIf(sourceLines[i2]);
14918
- if (!parts2) continue;
14919
- const guard = csEqualityGuard(parts2.cond);
14920
- if (!guard) continue;
14921
- const guardIds = csIdentifiers(guard.exprSide);
14922
- if (![...guardIds].some((id) => candidates.has(id))) continue;
14923
- const block = csThenBlock(sourceLines, i2, parts2.rest);
14924
- if (guard.op === "==") {
14925
- if (sinkIdx >= block.start && sinkIdx <= block.end) return true;
14926
- } else {
14927
- const guardDepth = csBraceDepthBefore(sourceLines, i2) + netBraces(stripCsLiterals(sourceLines[i2]).slice(0, parts2.ifCol));
14928
- if (block.earlyExit && sinkIdx > block.end && guardDepth === sinkDepth) {
14929
- return true;
14950
+ const guardMap = csEqualityGuardIndex(sourceLines);
14951
+ const checked = /* @__PURE__ */ new Set();
14952
+ for (const cand of candidates) {
14953
+ const guards = guardMap.get(cand);
14954
+ if (!guards) continue;
14955
+ for (const g of guards) {
14956
+ if (g.i >= sinkIdx || checked.has(g)) continue;
14957
+ checked.add(g);
14958
+ const block = csThenBlock(sourceLines, g.i, g.rest);
14959
+ if (g.op === "==") {
14960
+ if (sinkIdx >= block.start && sinkIdx <= block.end) return true;
14961
+ } else {
14962
+ const guardDepth = csBraceDepthBefore(sourceLines, g.i) + netBraces(stripCsLiterals(sourceLines[g.i]).slice(0, g.ifCol));
14963
+ if (block.earlyExit && sinkIdx > block.end && guardDepth === sinkDepth) {
14964
+ return true;
14965
+ }
14930
14966
  }
14931
14967
  }
14932
14968
  }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "circle-ir",
3
- "version": "4.9.7",
3
+ "version": "4.9.9",
4
4
  "description": "High-performance Static Application Security Testing (SAST) library for detecting security vulnerabilities through taint analysis",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",