circle-ir 4.16.0 → 4.16.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.
@@ -369,25 +369,44 @@ function resolveJavaDerivedAnchor(varName, derived, realSourceByVar, codeLines,
369
369
  * const-prop never seeds those derived names. Argument-style derivations
370
370
  * (`shown = encodeForPage(nick)`) must keep the veto so sanitizer credit holds.
371
371
  */
372
- function javaReceiverChainDerivedVar(code, localVar, seedVar) {
372
+ function javaReceiverChainDerivedVar(rhsByLocal, localVar, seedVar) {
373
373
  if (!seedVar || localVar === seedVar)
374
374
  return false;
375
+ const rhsList = rhsByLocal.get(localVar);
376
+ if (!rhsList)
377
+ return false;
375
378
  const esc = seedVar.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
376
379
  const receiverOnRhs = new RegExp(`(?:^|[^\\w.$])${esc}\\s*\\.`, 'u');
380
+ return rhsList.some(rhs => receiverOnRhs.test(rhs));
381
+ }
382
+ /**
383
+ * cognium-dev#806 — the assignment RHS texts of each Java local, indexed once
384
+ * per file. `javaReceiverChainDerivedVar` used to re-run its declaration regex
385
+ * over every line for every (source, derived local) pair, which made large
386
+ * files take seconds. Same per-line matching, done once.
387
+ */
388
+ function indexJavaLocalAssignments(code) {
377
389
  const declRe = /^\s*(?:public|private|protected|static|final|volatile|transient|\s)*\s*(?:[A-Za-z_][\w.]*(?:\s*<[^>]*>)?(?:\s*\[\s*\])*)\s+([A-Za-z_]\w*)\s*=\s*(.+?);\s*$/;
378
390
  const assignRe = /^\s*([A-Za-z_]\w*)\s*=\s*(.+?);\s*$/;
391
+ const index = new Map();
379
392
  for (const line of code.split('\n')) {
380
393
  const trimmed = line.trimStart();
381
394
  if (trimmed.startsWith('//') || trimmed.startsWith('*'))
382
395
  continue;
396
+ // Cheap pre-check: neither regex can match a line without `=` and `;`.
397
+ if (!line.includes('=') || !line.includes(';'))
398
+ continue;
383
399
  const m = declRe.exec(line) ?? assignRe.exec(line);
384
- if (!m || m[1] !== localVar)
400
+ if (!m)
385
401
  continue;
402
+ const list = index.get(m[1]);
386
403
  const rhs = stripJavaTrailingComment(m[2]);
387
- if (receiverOnRhs.test(rhs))
388
- return true;
404
+ if (list)
405
+ list.push(rhs);
406
+ else
407
+ index.set(m[1], [rhs]);
389
408
  }
390
- return false;
409
+ return index;
391
410
  }
392
411
  function makeConstPropVeto(constProp, graph, sources, code, language, sanitizers) {
393
412
  const lines = typeof code === 'string' ? code.split('\n') : [];
@@ -553,16 +572,24 @@ export class TaintPropagationPass {
553
572
  // into const-prop's tainted set so DFG + expression-scan vetoes keep them.
554
573
  // Per-source seeding + receiver filter avoids argument-style derivations
555
574
  // (`shown = encodeForPage(nick)`) that must stay vetoed for sanitizer credit.
575
+ // cognium-dev#806: index the assignments once, visit each seed name once,
576
+ // and skip the file-wide derivation when no local not already tainted has
577
+ // a `seed.` receiver on its RHS (only such locals can be added).
556
578
  if (ctx.language === 'java' && typeof ctx.code === 'string') {
579
+ const rhsByLocal = indexJavaLocalAssignments(ctx.code);
580
+ const seen = new Set();
557
581
  for (const s of sources) {
558
- if (!s.variable)
582
+ if (!s.variable || seen.has(s.variable))
559
583
  continue;
560
- for (const [v] of buildJavaTaintedVars(ctx.code, new Set([s.variable]))) {
561
- if (v === s.variable)
562
- continue;
563
- if (javaReceiverChainDerivedVar(ctx.code, v, s.variable)) {
584
+ seen.add(s.variable);
585
+ const seedVar = s.variable;
586
+ const candidates = [...rhsByLocal.keys()].filter(v => !constProp.tainted.has(v) && javaReceiverChainDerivedVar(rhsByLocal, v, seedVar));
587
+ if (candidates.length === 0)
588
+ continue;
589
+ const derived = buildJavaTaintedVars(ctx.code, new Set([seedVar]));
590
+ for (const v of candidates) {
591
+ if (derived.has(v))
564
592
  constProp.tainted.add(v);
565
- }
566
593
  }
567
594
  }
568
595
  }