Prevent compiler stack overflow on long acyclic forward type-alias chains

未关闭
#1,068 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@hiyouwhatsapp 已经在做这个了。

开始于 2026年11月2日。

  • #1074 来自 @hiyouwhatsapp —— 未关闭

评估

难度
4/5
预计耗时
3-5 天
新手友好度
35/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
rust
领域
compilers

调研方向

Start with the type canonicalization code in front/parser/src/verification/program.rs and the alias graph validation paths it reaches. Run the Python reproduction from the issue against target/debug/wavec to get the SIGABRT, then find which recursive function first exhausts the stack. Done means the 16384-alias chain completes or returns a normal diagnostic, direct and indirect alias cycles still get rejected, and tests cover forward and backward declaration order.

由索引模型根据 Issue 内容生成。

描述

bug

Problem

A long acyclic chain of forward type aliases aborts wavec check with a stack overflow instead of completing or returning a normal source diagnostic. Each declaration contains only a shallow named type, so the syntactic type-depth guard does not bound semantic traversal through the alias graph.

This is a Wave compiler robustness defect. It is not evidence of a Rust standard-library or compiler vulnerability.

Starting points: type canonicalization and the alias graph validation paths. The end-to-end abort is confirmed; the exact recursive function that first exhausts the stack has not been isolated.

Reproduction

Tested on Linux amd64 with a checkout-built wavec 0.0.1-alpha-dev, Rust 1.89.0 and LLVM 21. Local revision f7ff92c54bf8b41c2877245788890935b4ca3ba1; the frontend and driver source are identical to canonical master 1d1751405e087f32c1b1f28399d1629ae1bcfbd2 for this reproduction.

Run from the checkout. This creates only a temporary source, disables core dumps in the child and bounds the compiler invocation:

from pathlib import Path
import resource
import subprocess
import tempfile

compiler = str(Path('target/debug/wavec').resolve())

def limits():
    resource.setrlimit(resource.RLIMIT_CORE, (0, 0))

with tempfile.TemporaryDirectory() as temporary:
    source = Path(temporary) / 'aliases.wave'
    count = 16384
    source.write_text(
        '\n'.join(f'type A{i} = A{i + 1};' for i in range(count - 1))
        + f'\ntype A{count - 1} = i32;\n'
        + 'fun main() { var x: A0 = 0; }\n',
        encoding='utf-8',
    )
    result = subprocess.run(
        [compiler, 'check', str(source), '--error-format=json'],
        capture_output=True, text=True, timeout=12, preexec_fn=limits,
    )
    print(result.returncode)
    print(result.stderr)

Observed exit -6 (SIGABRT):

thread 'main' has overflowed its stack
fatal runtime error: stack overflow, aborting

The host-dependent failure threshold is not a proposed language limit. Separate 4096- and 8192-alias probes exceeded the 12-second observation window; that does not establish an asymptotic complexity claim.

Scope

Make semantic alias traversal safe for long acyclic graphs while preserving supported forward aliases and existing recursive-alias rejection. Preserve normal structured and JSON diagnostics. Do not increase the OS stack size or silently replace unresolved types.

Related: #167 rejects cycles; #852 bounds syntactic block/type nesting; #1029 bounds import depth. None covers this shallow, acyclic alias graph.

Completion criteria

  • A long acyclic forward alias chain no longer aborts the compiler.
  • Direct and indirect cycles still receive normal diagnostics.
  • Tests cover forward/backward declaration order and aliases used by ordinary type checking and code generation.
  • Any newly proposed rejection limit is discussed before changing accepted-language semantics.
主要语言
Rust
星标
56
派生
21
平均合并
20 小时 49 分钟
30 天内合并 PR
45

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

wavefnd/Wave 的其他 Issue

查看 wavefnd/Wave 的全部 Issue

相似的 Issue

更多 Rust Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。