# 0137 — `sx run` on a program with no `main` segfaults (JIT entry lookup unguarded)

> **RESOLVED.** A pre-JIT entry-point check in `main.zig` now emits a clean
> `error: no 'main' function found …` diagnostic and exits non-zero before any
> codegen/JIT, so a no-main program never reaches the garbage-pointer call. A
> defensive `main_addr == 0` guard in `target.zig`'s `runJITFromObject` (ORC
> reports lookup success but leaves the address degenerate) remains as a
> backstop. Regression test: `examples/1188-diagnostics-run-no-main.sx`.

## Symptom

`sx run <file>` on a program that defines no `main` function **crashes**
(SIGSEGV/abort, "Segmentation fault at address 0x60") instead of emitting a clean
diagnostic like `error: no 'main' function found`.

- **Observed:** process crash, exit 134 (abort) / 139 (SIGSEGV); no diagnostic.
- **Expected:** a normal compile-style error ("no `main` entry point") and a
  clean non-zero exit, the same way any other missing-entry condition reports.

Independent of inline assembly — surfaced while writing an ASM-stream probe that
omitted `main`, but reproduces with an ordinary, asm-free program (see below).

## Reproduction

A file with only an (uncalled) function and no `main`:

```sx
foo :: (n: u64) -> u64 { return n + 1; }
```

```sh
sx run that.sx
# => "Segmentation fault at address 0x60", exit 134
# expected: "error: no 'main' function found" (or similar), clean non-zero exit
```

## Root cause (suspected)

`src/target.zig` JIT-run path, ~lines 256–273. After the ORC lookup:

```zig
var main_addr: c.LLVMOrcExecutorAddress = 0;
err = c.LLVMOrcLLJITLookup(jit, &main_addr, "main");
if (err != null) { /* prints "JIT lookup error" and returns error.CompileError */ }

// no guard for main_addr == 0 here:
const main_fn: *const fn () callconv(.c) i32 = @ptrFromInt(main_addr);
const result = main_fn();          // <- calls a null/garbage pointer when no main
```

When the module has no `main` symbol, the lookup leaves `main_addr` at `0` (or
ORC returns a degenerate success), so `@ptrFromInt(main_addr)` + `main_fn()`
calls into null → the crash. There is no `main_addr == 0` check.

## Investigation prompt (paste into a fresh session)

> `sx run` on a program with no `main` segfaults instead of diagnosing. The JIT
> run path in `src/target.zig` (~lines 256–273) looks up `"main"` via
> `LLVMOrcLLJITLookup`, then unconditionally casts `main_addr` to a function
> pointer and calls it. When the program defines no `main`, `main_addr` is `0`
> (or the lookup degenerately "succeeds"), so the call dereferences null and
> crashes.
>
> Fix: after the lookup's `err` check, add `if (main_addr == 0) { … }` that emits
> a clean user-facing error ("no `main` function found" / "program has no entry
> point") and returns `error.CompileError` (matching the existing
> `JIT lookup error` style), BEFORE the `@ptrFromInt` + call. Consider whether a
> pre-JIT check (the module/program already knows whether a `main` decl exists —
> e.g. emit_llvm.zig:631 already null-checks `LLVMGetNamedFunction(.., "main")`)
> is the better choke point so the diagnostic carries a source span rather than a
> bare message. Either is acceptable; the hard requirement is *no crash*.
>
> Verification: `printf 'foo :: (n: u64) -> u64 { return n + 1; }\n' > /tmp/x.sx
> && sx run /tmp/x.sx` — expect a clean error message + non-zero exit, NOT a
> segfault. Add a pinned repro under `issues/` (or an `examples/11xx-diagnostics-*`
> once the message is settled) asserting the diagnostic on stderr + the exit code.
