# Known Limitations of c-shell
`c-shell` evaluates your C code by passing complete generated C files to your system host compiler. While this design provides accurate answers matching your real toolchain's ABI and rules, it comes with several inherent design limitations and boundary conditions documented below.
## Security & Execution Model
- **Execution is not sandboxed.** Compilers and generated programs run with `c-shell`'s user permissions and working directory. Do not evaluate untrusted code.
- **Most external side effects still replay.** Supported stdin calls use the stdin tape (see [HOW_IT_WORKS.md](HOW_IT_WORKS.md)), but file and process changes still repeat on every replay. Calls to known APIs such as `fopen`, `fprintf`, `remove`, `rename` and `system` produce a one-time English warning before execution. Detection is lexical and finite: wrappers and application-defined effects can still escape it. Stream-taking APIs such as `fgets` can conservatively trigger this warning even when their stream is stdin.
## Stdin & IO Replay
- **The stdin tape wraps common direct reads, not every input API.** `scanf`, `getchar`, `getc(stdin)`, `fgetc(stdin)` and `fgets(..., stdin)` are captured, including mixed buffered reads, `ungetc` pushback and EOF. `fscanf`, `fread`, raw `read(0, ...)`, explicitly removing the wrapper macros, and calls inside a precompiled library are not captured. An active request can receive one line; calls already completed from libc's buffer do not require another line. Programs that require multiple interactive lines in a single call should put the values on one line. With piped or redirected source stdin is carrying C code, so current program reads receive EOF; use `-e` or an interactive terminal when the evaluated program needs stdin.
- **Program output is bounded.** When stdin is a real terminal, output from the newest input is streamed immediately, so a prompt before `scanf` is visible. If the program leaves a partial line, `c-shell` appends a dim `↵` marker and the protective newline it inserted; a real `\n` needs no marker. With non-terminal stdin output remains buffered for deterministic transcripts and receives no marker. Capture is limited to 8 MiB per stream; an overflow is reported and the input is not committed.
## Semantics & Scope
- **Runtime checks are optional and partial.** `%check` uses only sanitizer
backends that can compile, link, run and detect a test error with the current
toolchain. Available checks differ by target/runtime installation. Checks
cover executed paths, not all undefined behavior or logic errors; general
uninitialized-value detection is not included. Leak detection is disabled
for replayed session allocations. Checked input is never retained, but
replay and external effects still occur. Messages are currently English.
- **Rebinding is C shadowing, not assignment.** A redeclared local lives in a nested block. Its declarator is already in scope during its initializer, so `int x = x + 1;` does not read the outer `x`. File-scope replacement also makes retained earlier calls use the new function when the session replays.
- **The purity heuristic is conservative.** Any expression containing a function call or a reference to a macro defined in retained input is kept, even if it happens to be pure.
- **Indeterminate values remain undefined C.** Address-only struct-member formatting prevents `c-shell` from adding a `%s` memory dereference, but it cannot make `struct P p; p` well-defined when members were never initialized; reading an indeterminate pointer or scalar is itself not portable. Initialize structs (for example with `{0}`) when the value matters.
- **Incomplete inputs are not committed.** Besides crashes and timeouts, a successful early `exit(0)`, `_Exit` or top-level `return` is detected by a missing completion marker; committing it would terminate every later replay before the new input runs.
## Value Printing Limits
- **Not every C value is printable.** The `_Generic` runtime covers the standard boolean/integer/real-floating types, top-level `char` strings, common object pointers and session-visible structs as described in [HOW_IT_WORKS.md](HOW_IT_WORKS.md). Header-only/anonymous aggregate types that have no reusable C spelling, complex and `void` values are evaluated without `Out[n]` and receive an explanatory note. A member whose type is not in the scalar or generated aggregate table is shown as `<unprintable>` rather than being coerced.
## Platform & Process Management
- **Process cleanup follows the launched process tree.** On Unix, the process group is killed when each run ends; a child that explicitly creates a new session with `setsid` can still escape. On Windows, each run is contained in a Job Object that is closed when the run ends.
- **No session save/load.** The input history is bounded (up to 1000 lines) within the current process memory/file session, but session state cannot be saved to a file or loaded across launches.
- **Windows uses WinLibs GCC; MSVC is not supported.** c-shell drives a MinGW-w64 GNU toolchain on Windows, and release binaries are built for `x86_64-pc-windows-gnu`. Put the toolchain's `bin` directory on `PATH`. The `clang` driver bundled with WinLibs also targets MinGW-w64 and accepts the same GNU command line, so `--cc clang` works, but CI exercises only GCC there. `cl.exe` and `clang-cl` are not supported.
- **Windows verification uses native WinLibs CI.** The Windows job installs WinLibs GCC and runs the same end-to-end tests, including Web PTY input and Ctrl-C recovery, on the Windows runner. MinGW-w64 GCC ships no ASan/UBSan runtime, so `%check` tests are skipped there; Linux and macOS jobs still require working sanitizers. Other Windows compiler configurations are not verified by this CI matrix. Local Linux tests do not establish Windows behavior.