[GH-ISSUE #6668] [Bug] Early break or continue turns a skipped var initializer into a definite return value #4047

Closed
opened 2026-10-31 00:46:20 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 23, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6668

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

analyzeJavaScriptArtifactFiles reports literal 1 for an exported function's return after an early break or continue can skip its var value = 1 declaration initializer. Even do { break; var value = 1; } while (false); return value; produces a definite 1, although the initializer cannot execute. A labeled-block break gives the same result.

This is observed analyzer output from the source application boundary. Expected skipped-initializer behavior is language-semantics-derived; the analyzed JavaScript was never executed. Public CLI/MCP output and the installed npm entrypoint were not tested.

Reproduction

With the pinned Node runtime on PATH and locked dependencies installed, run the following from the checkout root. This exact final here-document ran once; exploratory cases also exposed skipped initialization before the final function-local reproducer was prepared.

node --import ./node_modules/tsx/dist/loader.mjs --input-type=module <<'JS'
import { createHash } from 'node:crypto';
import { resolve } from 'node:path';
import { pathToFileURL } from 'node:url';
const { analyzeJavaScriptArtifactFiles } = await import(pathToFileURL(resolve('src/application/javascript/JavaScriptArtifactAnalysis.ts')).href);

function analyze(source) {
  const sha256 = createHash('sha256').update(source).digest('hex');
  const file = {path: 'entry.cjs', sha256, container_sha256: sha256,
    bytes: Buffer.byteLength(source), inventory_artifact_id: 'fixture',
    kind: 'javascript', unpacked: false, text: {included: true, value: source}};
  const result = analyzeJavaScriptArtifactFiles({files: [file], containers: [],
    unavailable_relevant_files: [], text_bytes_read: file.bytes, invalid_utf8_files: 0});
  return result.files[0].semantic.ir;
}

for (const [name, body] of [
  ['conditional-break', 'do {if(stop) break; var value = 1;} while(false); return value;'],
  ['unconditional-break', 'do {break; var value = 1;} while(false); return value;'],
  ['conditional-continue', 'do {if(stop) continue; var value = 1;} while(false); return value;'],
  ['labeled-break', 'work: {break work; var value = 1;} return value;'],
  ['initialized-control', 'do {var value = 1;} while(false); return value;'],
  ['break-after-write-control', 'do {var value = 1; if(stop) break;} while(false); return value;'],
  ['skipped-loop-control', 'while(stop) {var value = 1; break;} return value;'],
]) {
  const source = `exports.read = function read(stop){${body}};`;
  const ir = analyze(source);
  const read = ir.callables.find(c => c.name === 'read');
  console.log(JSON.stringify({name, returns: read.returnSites.map(s => s.value)}));
}
JS

Expected behavior

The first four cases must not publish a certain 1. A var initializer assigns its value only when its declaration executes; an early break or continue skips that declaration while the hoisted binding remains undefined. Conditional early exits permit either undefined or 1, and the unconditional exits shown always skip the initializer. An unknown result is sufficient if undefined is outside REA's value lattice. The two definite-initialization controls should retain literal 1; the potentially unentered while control should remain unknown, consistent with REA's uncertainty contract.

Impact and scope

All four early-exit fixtures in the final application-boundary reproduction published an incorrect definite return literal. The failure affects ordinary do...while and labeled-block code with var declarations after a possible abrupt exit. No frequency estimate for real applications, regression range, or downstream CLI/MCP effect was established.

REA version

Package 6.7.0; source revision 19520d0008.

Runtime and platform

Node.js v24.22.1; Linux x64; dependencies from the repository lockfile. No Hopper, Ghidra, or other native provider was involved.

Target and artifact context

Authored, in-memory JavaScript source strings supplied as content-addressed artifact records. All fixtures use entry.cjs. The analyzer parses source without executing it.

Interface

Other

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The final reproduction exited successfully and printed:

{"name":"conditional-break","returns":[{"status":"literal","value":1}]}
{"name":"unconditional-break","returns":[{"status":"literal","value":1}]}
{"name":"conditional-continue","returns":[{"status":"literal","value":1}]}
{"name":"labeled-break","returns":[{"status":"literal","value":1}]}
{"name":"initialized-control","returns":[{"status":"literal","value":1}]}
{"name":"break-after-write-control","returns":[{"status":"literal","value":1}]}
{"name":"skipped-loop-control","returns":[{"status":"unknown","reason":"Binding value may remain uninitialized."}]}

The first four lines lose skipped-initializer uncertainty; the last three controls behave consistently with their source semantics.

  • Expected source: REA preserves uncertainty; the existing skipped-initializer result; the variable-statement semantics under Expected behavior.
  • Failure source: Executed analyzeJavaScriptArtifactFiles reproduction above, through the application entrypoint, returning the displayed definite return sites.
  • Evidence provenance: observed for REA output; language-semantics-derived for the expected target value.
  • Local verification: reproduced at the source application API; no analyzed target execution or public CLI/MCP verification.
  • Reproduction completeness: complete for that application-boundary failure.

Typed outcome or recovery expected

Preserve unknown or explicit undefined for unconditional skipped initialization, and uncertainty for a conditional early exit. Keep initialized-control and break-after-write-control at literal 1. The existing unknown result for skipped-loop-control must remain intact.

Analysis or suspected cause

Source-derived: writeMayBeSkipped checks ancestor/child relationships through semanticBranchMayBeSkipped. Those relationships cover a potentially unentered loop body but do not account for an earlier sibling break or continue that bypasses this initializer. The value evaluator consequently receives a sole initializer without the skipped-expression flag. This is a suspected producing-boundary gap, not a prescribed fix.

Additional context

Searched the saved open corpus and live open/closed issues for JavaScript abrupt completion, break plus uninitialized, do-while plus literal, skipped initialization, unreachable code, and break/continue initializers. Closed #2562 covers a branch or loop that is not entered; the final skipped-loop-control demonstrates that its uncertainty behavior already works here. This report enters the block or loop and exits before a later sibling initializer. Open #5302 and closed #5377 concern reads or calls before the initializer's source position; every read here follows its initializer in source order. No exact duplicate was found in the open and closed searches refreshed before submission.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The executed application-boundary probe publishes a definite return literal contradicted by the source's language semantics. This is a bounded evidence-correctness defect; no severe downstream incident or widespread workflow failure was established.
  • Workaround status: unverified
  • Workaround basis: No existing analyzer option or equivalent automatic workflow preserving the required semantic result was demonstrated. Changing the analyzed source can change its behavior and artifact identity; no result-preserving workaround was demonstrated.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6668 ## Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ## Area Evidence, artifacts, or reconstruction ## Observed behavior `analyzeJavaScriptArtifactFiles` reports literal `1` for an exported function's return after an early `break` or `continue` can skip its `var value = 1` declaration initializer. Even `do { break; var value = 1; } while (false); return value;` produces a definite `1`, although the initializer cannot execute. A labeled-block `break` gives the same result. This is observed analyzer output from the source application boundary. Expected skipped-initializer behavior is language-semantics-derived; the analyzed JavaScript was never executed. Public CLI/MCP output and the installed npm entrypoint were not tested. ## Reproduction With the pinned Node runtime on `PATH` and locked dependencies installed, run the following from the checkout root. This exact final here-document ran once; exploratory cases also exposed skipped initialization before the final function-local reproducer was prepared. ```sh node --import ./node_modules/tsx/dist/loader.mjs --input-type=module <<'JS' import { createHash } from 'node:crypto'; import { resolve } from 'node:path'; import { pathToFileURL } from 'node:url'; const { analyzeJavaScriptArtifactFiles } = await import(pathToFileURL(resolve('src/application/javascript/JavaScriptArtifactAnalysis.ts')).href); function analyze(source) { const sha256 = createHash('sha256').update(source).digest('hex'); const file = {path: 'entry.cjs', sha256, container_sha256: sha256, bytes: Buffer.byteLength(source), inventory_artifact_id: 'fixture', kind: 'javascript', unpacked: false, text: {included: true, value: source}}; const result = analyzeJavaScriptArtifactFiles({files: [file], containers: [], unavailable_relevant_files: [], text_bytes_read: file.bytes, invalid_utf8_files: 0}); return result.files[0].semantic.ir; } for (const [name, body] of [ ['conditional-break', 'do {if(stop) break; var value = 1;} while(false); return value;'], ['unconditional-break', 'do {break; var value = 1;} while(false); return value;'], ['conditional-continue', 'do {if(stop) continue; var value = 1;} while(false); return value;'], ['labeled-break', 'work: {break work; var value = 1;} return value;'], ['initialized-control', 'do {var value = 1;} while(false); return value;'], ['break-after-write-control', 'do {var value = 1; if(stop) break;} while(false); return value;'], ['skipped-loop-control', 'while(stop) {var value = 1; break;} return value;'], ]) { const source = `exports.read = function read(stop){${body}};`; const ir = analyze(source); const read = ir.callables.find(c => c.name === 'read'); console.log(JSON.stringify({name, returns: read.returnSites.map(s => s.value)})); } JS ``` ## Expected behavior The first four cases must not publish a certain `1`. A [`var` initializer assigns its value only when its declaration executes](https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-variable-statement); an early `break` or `continue` skips that declaration while the hoisted binding remains undefined. Conditional early exits permit either undefined or `1`, and the unconditional exits shown always skip the initializer. An unknown result is sufficient if undefined is outside REA's value lattice. The two definite-initialization controls should retain literal `1`; the potentially unentered `while` control should remain unknown, consistent with [REA's uncertainty contract](https://github.com/morluto/rea/blob/19520d00087bc92b5c1020918ea3b7c064768bb4/AGENTS.md#L19-L21). ## Impact and scope All four early-exit fixtures in the final application-boundary reproduction published an incorrect definite return literal. The failure affects ordinary `do...while` and labeled-block code with `var` declarations after a possible abrupt exit. No frequency estimate for real applications, regression range, or downstream CLI/MCP effect was established. ## REA version Package 6.7.0; source revision 19520d00087bc92b5c1020918ea3b7c064768bb4. ## Runtime and platform Node.js v24.22.1; Linux x64; dependencies from the repository lockfile. No Hopper, Ghidra, or other native provider was involved. ## Target and artifact context Authored, in-memory JavaScript source strings supplied as content-addressed artifact records. All fixtures use `entry.cjs`. The analyzer parses source without executing it. ## Interface Other ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence The final reproduction exited successfully and printed: ```jsonl {"name":"conditional-break","returns":[{"status":"literal","value":1}]} {"name":"unconditional-break","returns":[{"status":"literal","value":1}]} {"name":"conditional-continue","returns":[{"status":"literal","value":1}]} {"name":"labeled-break","returns":[{"status":"literal","value":1}]} {"name":"initialized-control","returns":[{"status":"literal","value":1}]} {"name":"break-after-write-control","returns":[{"status":"literal","value":1}]} {"name":"skipped-loop-control","returns":[{"status":"unknown","reason":"Binding value may remain uninitialized."}]} ``` The first four lines lose skipped-initializer uncertainty; the last three controls behave consistently with their source semantics. - Expected source: [REA preserves uncertainty](https://github.com/morluto/rea/blob/19520d00087bc92b5c1020918ea3b7c064768bb4/AGENTS.md#L19-L21); [the existing skipped-initializer result](https://github.com/morluto/rea/blob/19520d00087bc92b5c1020918ea3b7c064768bb4/src/domain/javascript/javascriptSemanticValues.ts#L494-L501); the variable-statement semantics under Expected behavior. - Failure source: Executed `analyzeJavaScriptArtifactFiles` reproduction above, through the [application entrypoint](https://github.com/morluto/rea/blob/19520d00087bc92b5c1020918ea3b7c064768bb4/src/application/javascript/JavaScriptArtifactAnalysis.ts#L87-L95), returning the displayed definite return sites. - Evidence provenance: observed for REA output; language-semantics-derived for the expected target value. - Local verification: reproduced at the source application API; no analyzed target execution or public CLI/MCP verification. - Reproduction completeness: complete for that application-boundary failure. ## Typed outcome or recovery expected Preserve unknown or explicit undefined for unconditional skipped initialization, and uncertainty for a conditional early exit. Keep `initialized-control` and `break-after-write-control` at literal `1`. The existing unknown result for `skipped-loop-control` must remain intact. ## Analysis or suspected cause Source-derived: [writeMayBeSkipped](https://github.com/morluto/rea/blob/19520d00087bc92b5c1020918ea3b7c064768bb4/src/domain/javascript/javascriptSemanticAnalysis.ts#L1353-L1371) checks ancestor/child relationships through [semanticBranchMayBeSkipped](https://github.com/morluto/rea/blob/19520d00087bc92b5c1020918ea3b7c064768bb4/src/domain/javascript/javascriptSemanticEvaluationOrder.ts#L93-L117). Those relationships cover a potentially unentered loop body but do not account for an earlier sibling `break` or `continue` that bypasses this initializer. The value evaluator consequently receives a sole initializer without the skipped-expression flag. This is a suspected producing-boundary gap, not a prescribed fix. ## Additional context Searched the saved open corpus and live open/closed issues for JavaScript abrupt completion, break plus uninitialized, do-while plus literal, skipped initialization, unreachable code, and break/continue initializers. Closed [#2562](https://github.com/morluto/rea/issues/2562) covers a branch or loop that is not entered; the final `skipped-loop-control` demonstrates that its uncertainty behavior already works here. This report enters the block or loop and exits before a later sibling initializer. Open [#5302](https://github.com/morluto/rea/issues/5302) and closed [#5377](https://github.com/morluto/rea/issues/5377) concern reads or calls before the initializer's source position; every read here follows its initializer in source order. No exact duplicate was found in the open and closed searches refreshed before submission. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The executed application-boundary probe publishes a definite return literal contradicted by the source's language semantics. This is a bounded evidence-correctness defect; no severe downstream incident or widespread workflow failure was established. - Workaround status: unverified - Workaround basis: No existing analyzer option or equivalent automatic workflow preserving the required semantic result was demonstrated. Changing the analyzed source can change its behavior and artifact identity; no result-preserving workaround was demonstrated.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4047
No description provided.