https://github.com/pmarreck/nimble-darwin-ssl-fix
nimble for Nix/macOS with working TLS — fixes the openssl dlopen/segfault on nimble refresh/install
https://github.com/pmarreck/nimble-darwin-ssl-fix
Last synced: 3 days ago
JSON representation
nimble for Nix/macOS with working TLS — fixes the openssl dlopen/segfault on nimble refresh/install
- Host: GitHub
- URL: https://github.com/pmarreck/nimble-darwin-ssl-fix
- Owner: pmarreck
- Created: 2026-06-05T02:21:34.000Z (14 days ago)
- Default Branch: yolo
- Last Pushed: 2026-06-05T02:30:00.000Z (14 days ago)
- Last Synced: 2026-06-05T04:12:21.828Z (14 days ago)
- Language: Nix
- Size: 3.91 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# nimble-darwin-ssl-fix
A Nix flake that ships a **`nimble` whose TLS actually works on Nix/macOS**.
On nixpkgs/darwin, stock `nimble refresh` (and any `nimble install` that hits the
network) dies with:
```
Downloading Official package list
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
```
This flake fixes it. `nimble refresh` works in a completely pristine environment —
no `DYLD_*`, no `SSL_CERT_FILE`, no `--noSSLCheck`.
## Use it
```bash
# one-off
nix run github:pmarreck/nimble-darwin-ssl-fix -- refresh
# in a devShell (flake)
{
inputs.nimble-fix.url = "github:pmarreck/nimble-darwin-ssl-fix";
# ...
devShells.default = pkgs.mkShell {
buildInputs = [ pkgs.nim inputs.nimble-fix.packages.${system}.nimble ];
};
}
# or as an overlay
nixpkgs.overlays = [ inputs.nimble-fix.overlays.default ]; # replaces pkgs.nimble
```
## What was actually wrong
This is **not** a missing nil-check (Nim's `std/openssl` already raises
`LibraryError` on a failed symbol load), and Nim's SSL itself is fine — a fresh
`nim c -d:ssl` HTTPS program downloads the very same `packages.json` with no env
hacks. The bug is specific to how **nimble** is built and how Nim binds OpenSSL on
nixpkgs:
`lib/wrappers/openssl.nim` binds OpenSSL two ways at once:
1. **Bulk procs** (`SSL_CTX_new`, `SSL_connect`, `SSL_read`, …) — nixpkgs patches
these (ehmry, 2023, *"Do not load openssl with dlopen"*) to **link** against
nixpkgs' OpenSSL at build time.
2. **Compat procs** (`TLS_method`, `getOpenSSLVersion`, …) — still resolved at
**runtime** via `dlopen` of a **bare** library name
(`"libssl(.3|.1.1|…).dylib"`).
Two failures compound on darwin:
- The stock nixpkgs `nimble` is built **without `--define:ssl`**, so it isn't even
link-bound to nix's OpenSSL. (`otool -L` on the shipped binary shows no libssl.)
- Even after adding `-d:ssl`, the compat procs' bare-name `dlopen` does **not**
resolve to the link-bound nix OpenSSL on macOS. The runtime probe lands on a
*different* (or no) libssl, and mixing two OpenSSL builds crashes inside
`SSL_CTX_new` — exactly the *"two different openSSL loaded version causes a
crash"* scenario `openssl.nim`'s own header comment warns about.
Crash path (from a stacktrace build):
```
packageinfo.nim(151) fetchList
tools.nim(224) newSSLContext
net.nim(670) newContext <- TLS_method()/SSL_CTX_new, mixed openssl
SIGSEGV
```
It works on Linux (and goes unnoticed by maintainers) because there the
link-bound OpenSSL is on the loader path, so the leftover runtime probe resolves
to the *same* library. macOS + Nix + Nim is the unlucky cell.
## The fix (three parts, all empirically required)
1. **`--define:ssl`** — link-bind the bulk procs to nixpkgs OpenSSL.
2. **`DYLD_FALLBACK_LIBRARY_PATH` → nix openssl `/lib`** — so the compat layer's
runtime `dlopen` probe resolves to the **same** OpenSSL. No mismatch, no crash.
3. **`SSL_CERT_FILE` → cacert bundle** — so certificate verification passes.
(2) and (3) are baked into the binary via `wrapProgram`, so users set nothing.
See `flake.nix` for the exact derivation.
## Verified
```
$ env -i HOME=/tmp/x PATH=/usr/bin:/bin result/bin/nimble refresh
Downloading Official package list
Success Package list downloaded.
```
(`env -i` = empty environment; nothing inherited.)
---
## Ready-to-file nixpkgs issue
> **Title:** `nimble` segfaults on `nimble refresh` on aarch64-darwin (no `-d:ssl`
> + bare-name openssl `dlopen` mismatch)
>
> **Description:** The shipped `nimble` (`pkgs/by-name/ni/nimble/package.nix`) is
> built without `--define:ssl`, so its openssl procs are not link-bound to
> nixpkgs openssl (`otool -L $(which nimble)` shows no libssl). `nimble refresh`
> SIGSEGVs in `net.newContext` (`tools.nim:224 newSSLContext` → `net.nim:670`).
>
> Adding `nimFlags = [ "--define:ssl" ]` makes it link libssl, but it **still**
> segfaults on darwin: Nim's `std/openssl` compat layer (`TLS_method`, etc.)
> resolves libssl at runtime via a bare-name `dlopen`, which on macOS does not
> find the link-bound nix openssl, so a *different* openssl is mixed in →
> crash in `SSL_CTX_new`. A fresh `nim c -d:ssl` HTTPS program works, confirming
> the issue is nimble's build + the leftover runtime probe, not Nim's SSL.
>
> **Fix options:** (a) add `--define:ssl` to the nimble derivation **and** make
> the openssl compat-probe resolve to the link-bound store path on darwin (patch
> `DLLSSLName`/`DLLUtilName` to absolute `${openssl}/lib/...` in `nim-unwrapped`),
> or (b) wrap `nimble` with `DYLD_FALLBACK_LIBRARY_PATH=${openssl}/lib` +
> `SSL_CERT_FILE`. Note: the `--dynlibOverride:ssl` static route is currently
> broken in the patched nim (`Error: invalid pragma: gimportc`).
## Sources
- [NixOS/nixpkgs#150982 — nimble "Illegal storage access" downloading packages.json](https://github.com/NixOS/nixpkgs/issues/150982)
- [NixOS/nixpkgs#201456 — nimble refresh invalid certificates (openssl 3.x)](https://github.com/NixOS/nixpkgs/issues/201456)
- [Nimble troubleshooting — DYLD_LIBRARY_PATH / -d:ssl](https://nim-lang.github.io/nimble/troubleshooting.html)
- nixpkgs commit *"Do not load openssl with dlopen"* (ehmry, 2023) — `pkgs/by-name/ni/nim-unwrapped-2_2/openssl.patch`
## License
MIT (or match upstream nimble's BSD-3 — it's just a build wrapper).