# EOF Exception 修复报告

## 问题描述

用户在使用 CLI 交互模式时遇到异常退出：

```
Exception: Read bytes 4294967295 != Expected bytes 1
at cli.io.Readline::readline(std.core::String)(/Users/louloulin/Documents/linchong/cjproject/codelin/src/io/readline.cj:621)
```

## 根本原因分析

### 1. 异常触发链路

```
用户按 Ctrl+D (或其他 EOF 信号)
  ↓
read() 系统调用返回 -1 (错误) 或 0 (EOF)
  ↓
ffi/raw_input_linux.c::getRawUtf8() 返回 -1
  ↓
src/io/raw_input_utils_unix.cj::rawGetRune() 接收到 len = -1
  ↓
第 52 行将 len 与 size 比较时，-1 被解释为无符号数 4294967295
  ↓
抛出异常导致程序崩溃
```

### 2. 为什么是 4294967295？

- `4294967295` = `0xFFFFFFFF` = `2^32 - 1`
- 这是 `-1` 的无符号 32 位表示
- 当 `IntNative` (有符号) 的 `-1` 在字符串插值中被显示时，被解释为无符号数

### 3. 常见触发场景

- 用户按 `Ctrl+D` (EOF 信号)
- 终端被意外关闭或中断
- stdin 被重定向且已读取到文件末尾
- 系统 I/O 错误

## 修复方案

### Unix/macOS 版本 (`raw_input_utils_unix.cj`)

**修复前：**
```cangjie
static func rawGetRune(): Option<Rune> {
    var buffer: VArray<Byte, $4> = [0, 0, 0, 0]
    let len: IntNative = unsafe { getRawUtf8(inout buffer) }

    let bytes = [buffer[0], buffer[1], buffer[2], buffer[3]]
    let (r, size) = Rune.fromUtf8(bytes, 0)
    if (size != Int64(len)) {
        throw Exception("Read bytes ${len} != Expected bytes ${size}")
    }
    return r
}
```

**修复后：**
```cangjie
static func rawGetRune(): Option<Rune> {
    var buffer: VArray<Byte, $4> = [0, 0, 0, 0]
    let len: IntNative = unsafe { getRawUtf8(inout buffer) }

    // Handle EOF or read error
    // len = 0: EOF
    // len = -1: Read error
    if (len <= 0) {
        return None
    }

    let bytes = [buffer[0], buffer[1], buffer[2], buffer[3]]
    let (r, size) = Rune.fromUtf8(bytes, 0)
    if (size != Int64(len)) {
        throw Exception("Read bytes ${len} != Expected bytes ${size}")
    }
    return r
}
```

### Windows 版本 (`raw_input_utils_win.cj`)

**修复前：**
```cangjie
static func rawGetRune(): Option<Rune> {
    var buffer: VArray<Byte, $4> = [0, 0, 0, 0]
    let len = unsafe { getRawUtf8(inout buffer) }
    if (len == 0) { // WHEN UNKNOWN ASCII
        return rawGetRune()
    }
    let bytes = [buffer[0], buffer[1], buffer[2], buffer[3]]
    let (r, size) = Rune.fromUtf8(bytes, 0)
    if (size != Int64(len)) {
        throw Exception("Read bytes(${len}) != Expected bytes(${size})")
    }
    return r
}
```

**修复后：**
```cangjie
static func rawGetRune(): Option<Rune> {
    var buffer: VArray<Byte, $4> = [0, 0, 0, 0]
    let len = unsafe { getRawUtf8(inout buffer) }
    if (len == 0) { // WHEN UNKNOWN ASCII
        return rawGetRune()
    }
    // Handle EOF or read error
    if (len < 0) {
        return None
    }
    let bytes = [buffer[0], buffer[1], buffer[2], buffer[3]]
    let (r, size) = Rune.fromUtf8(bytes, 0)
    if (size != Int64(len)) {
        throw Exception("Read bytes(${len}) != Expected bytes(${size})")
    }
    return r
}
```

## 修复效果

### 修复前行为
- 当用户按 `Ctrl+D` 时，程序会抛出异常并崩溃
- 用户看到难以理解的错误信息（4294967295 字节）
- 会话状态可能丢失

### 修复后行为
- `rawGetRune()` 返回 `None`
- `readline()` 在第 621-624 行正确处理 `None` 并返回 `None`
- CLI 应用可以优雅地处理退出，保存会话状态
- 用户体验：正常退出（就像输入了退出命令）

## 相关代码调用链

```
cli_app.cj::startInteractive()
  ↓
input_utils.cj::getUserInput()
  ↓
readline.cj::readline(prompt, withBox: true)
  ↓
readline.cj::readline(prompt) [第 621 行]
  ↓
raw_input_utils_unix.cj::rawGetRune() [修复点]
  ↓
getRawUtf8() [FFI C 函数]
```

## 测试验证

### 手动测试
1. 启动 CLI: `./target/release/codelin`
2. 在提示符下按 `Ctrl+D`
3. **期望结果：** 程序优雅退出，不抛出异常

### 自动化测试场景
```bash
# 模拟 EOF 输入
echo "" | ./target/release/codelin

# 预期：程序正常启动和退出，无异常
```

## 编译状态

✅ **编译成功** (2025-01-06)

```
cjpm build success
```

## 相关文件

- **修复文件：**
  - `src/io/raw_input_utils_unix.cj` (Unix/macOS)
  - `src/io/raw_input_utils_win.cj` (Windows)

- **FFI 实现：**
  - `ffi/raw_input_linux.c::getRawUtf8()`
  - `ffi/raw_input_win.c::getRawUtf8()`

- **调用链：**
  - `src/io/readline.cj::readline()`
  - `src/io/input_utils.cj::getUserInput()`
  - `src/app/cli_app.cj::startInteractive()`

## 总结

这是一个**关键的健壮性修复**，解决了 CLI 在接收到 EOF 或 I/O 错误时的崩溃问题。修复通过正确处理 `read()` 系统调用的错误返回值，确保程序能够优雅地处理用户中断（如 `Ctrl+D`）。

**关键改进：**
1. ✅ 防止异常崩溃
2. ✅ 优雅处理 EOF 和 I/O 错误
3. ✅ 改善用户体验
4. ✅ 保护会话状态

**影响范围：**
- 所有使用交互模式的 CLI 场景
- 跨平台支持（Unix/macOS 和 Windows）

