{"record":{"id":"fc23d44bbe347a91","repo":"abhigyanpatwari/GitNexus","slug":"cfg-lang-provider-language-cdgskippedunsou","errorCode":null,"errorMessage":"[cfg] lang=${provider.language}: ${cdgSkippedUnsound} function(s) had control dependence skipped (EXIT not reverse-reachable from all blocks); CFG and REACHING_DEF are unaffected","messagePattern":"\\[cfg\\] lang=(.+?): (.+?) function\\(s\\) had control dependence skipped \\(EXIT not reverse-reachable from all blocks\\); CFG and REACHING_DEF are unaffected","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gitnexus/src/core/ingestion/scope-resolution/pipeline/run.ts","lineNumber":1581,"sourceCode":"            ? `; taint: ${taintTotals.findings} TAINTED, ${taintTotals.kills} SANITIZES ` +\n              `(${taintTotals.analyzed} function(s) analyzed, ` +\n              `${taintTotals.noMatch} skipped: no source/sink match` +\n              (taintTotals.hopsTruncated > 0\n                ? `, ${taintTotals.hopsTruncated} finding(s) with truncated hop paths`\n                : '') +\n              `)`\n            : ''),\n      );\n    }\n    // R8 (#2195): CDG soundness skips surface UNCONDITIONALLY (parity with the\n    // taint/RD gap warns) — not buried in the logger.debug stats line above. A\n    // function whose EXIT is not reverse-reachable from every block gets NO\n    // control dependence (an unmodeled non-terminating / multi-terminal CFG\n    // shape the synthetic-escape pass could not bridge). Withholding CDG\n    // silently would let a language's control dependence erode unnoticed; CFG\n    // and REACHING_DEF do not depend on post-dominance and are unaffected.\n    if (cdgSkippedUnsound > 0) {\n      logger.warn(\n        `[cfg] lang=${provider.language}: ${cdgSkippedUnsound} function(s) had control ` +\n          `dependence skipped (EXIT not reverse-reachable from all blocks); ` +\n          `CFG and REACHING_DEF are unaffected`,\n      );\n    }\n    // R4: taint coverage gaps and cap drops surface UNCONDITIONALLY (never\n    // logger.debug, never input.onWarn) at the per-language aggregate, with\n    // counts and up to 5 example functions. Per-function warns above cover\n    // the rare/actionable cases (unsafe sites, cap drops); solver-status gaps\n    // were already per-function-warned by the RD layer (same solver, same\n    // fact cap), so this aggregate is their single taint-side surface.\n    if (taintSpec !== undefined) {\n      const gapCount =\n        taintTotals.unsafeSites +\n        taintTotals.gapTruncated +\n        taintTotals.gapOverflow +\n        taintTotals.gapNoFacts;\n      if (gapCount > 0 || taintTotals.dropped > 0) {","sourceCodeStart":1563,"sourceCodeEnd":1599,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/core/ingestion/scope-resolution/pipeline/run.ts#L1563-L1599","documentation":"R8 (#2195): when building control dependence (CDG), a function whose EXIT block is not reverse-reachable from every block — an unmodeled non-terminating or multi-terminal CFG shape the synthetic-escape pass could not bridge — gets NO control dependence at all. The skip is surfaced unconditionally per language aggregate; CFG and REACHING_DEF do not depend on post-dominance and remain intact.","triggerScenarios":"Running analyze with the PDG layer enabled on code containing functions with pathological terminal shapes (e.g. infinite loops with no path to EXIT, unusual multi-exit structures). cdgSkippedUnsound accumulates across those functions and the warn fires at the per-language aggregate.","commonSituations":"Embedded/event-loop style code with intentional infinite loops, generated state machines with unreachable exits, or languages whose CFG construction yields blocks that cannot reach EXIT. Users notice it when pdg_query mode 'controls' returns nothing for a function while CFG/RD queries still work.","solutions":["Confirm scope: only CDG is missing — CFG and REACHING_DEF queries for those functions still answer, so most flows keep working","Locate the functions: the count is aggregate, so correlate with per-function diagnostics or query pdg_query controls on suspects to find which lost CDG","If the shape is your own code (an intentional forever-loop), add an explicit exit path/return so EXIT becomes reverse-reachable and CDG is rebuilt","If the shape looks normal, report it upstream as a CFG-shape modeling gap with the function source"],"exampleFix":"# before\nasync function pump() {\n  while (true) {\n    await tick();   // EXIT not reverse-reachable → CDG skipped for this fn\n  }\n}\n# after\nasync function pump(stop: () => boolean) {\n  while (!stop()) {\n    await tick();   // reachable EXIT → control dependence emitted\n  }\n}","handlingStrategy":"validation","validationCode":"// Detect CDG loss before relying on 'controls' queries:\nconst res = await pdgQuery({ mode: 'controls', target: 'src/worker.ts:pump' });\nif (res.results.length === 0 && analyzeLog.includes('control dependence skipped')) {\n  // CFG/RD still valid; only control-dependence questions are unanswerable\n  console.warn('CDG unavailable for pump — do not treat as no-controls');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Give long-running loops an explicit exit path so EXIT stays reverse-reachable","When pdg_query controls is empty, check the aggregate warn first — absence of CDG is not absence of control","Track the per-function skip count across runs; growth signals new pathological CFG shapes entering the codebase"],"tags":["pdg","cdg","control-dependence","static-analysis","cfg"],"backgroundTag":"static-analysis-unsoundness","analyzedSha":"0d1aed942f0e8b5d3bac27519fff441aceea722d","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}