|
| 1 | +# Fork Maintenance Guide |
| 2 | + |
| 3 | +This document describes how to maintain the WarpGrid wasi-libc patch series: why the patches exist, how to rebase them onto new upstream releases, how to add new patches, and how to troubleshoot common failures. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +WarpGrid runs user-supplied WebAssembly modules in a sandboxed environment. These modules are compiled against [wasi-libc](https://github.com/WebAssembly/wasi-libc), the standard C library for WASI targets. Stock wasi-libc does not include networking or advanced filesystem support, so WarpGrid maintains a **patch series** that adds shim functions for: |
| 8 | + |
| 9 | +- **DNS resolution** — `getaddrinfo`, `gethostbyname`, `getnameinfo` routed through the WarpGrid DNS shim |
| 10 | +- **Filesystem** — `fopen`/`open` routed through the WarpGrid virtual filesystem, plus timezone virtualization |
| 11 | +- **Sockets** — `connect`, `send`, `recv`, `read`, `write`, `close` routed through the WarpGrid database proxy |
| 12 | + |
| 13 | +These patches are kept as numbered `git format-patch` files in `libc-patches/` rather than maintained as a full fork. This keeps the delta small, reviewable, and straightforward to rebase when upstream releases a new version. |
| 14 | + |
| 15 | +### Repository layout |
| 16 | + |
| 17 | +``` |
| 18 | +libc-patches/ |
| 19 | + UPSTREAM_REF # Pinned upstream tag + commit hash |
| 20 | + 0001-dns-*.patch # Patch series (applied in order) |
| 21 | + 0002-fs-*.patch |
| 22 | + ... |
| 23 | + tests/ # C test programs that validate patch behavior |
| 24 | + test_dns_getaddrinfo.c |
| 25 | + test_fs_virtual_open.c |
| 26 | + ... |
| 27 | +scripts/ |
| 28 | + rebase-libc.sh # Apply, export, update, validate patches |
| 29 | + build-libc.sh # Build stock and/or patched sysroots |
| 30 | + test-libc.sh # Run test programs against sysroots |
| 31 | +``` |
| 32 | + |
| 33 | +## Upstream Pin Policy |
| 34 | + |
| 35 | +The file `libc-patches/UPSTREAM_REF` pins the exact upstream commit that the patch series applies to: |
| 36 | + |
| 37 | +``` |
| 38 | +TAG=wasi-sdk-30 |
| 39 | +COMMIT=ec0effd769df5f05b647216578bcf5d3b5449725 |
| 40 | +``` |
| 41 | + |
| 42 | +**Rules:** |
| 43 | + |
| 44 | +1. **Always pin to a tagged release** (e.g., `wasi-sdk-30`), never to an arbitrary commit. Tags are stable references that correspond to tested wasi-sdk releases. |
| 45 | +2. **Update the pin only when rebasing** — `scripts/rebase-libc.sh --update <new-tag>` updates both `TAG` and `COMMIT` automatically. |
| 46 | +3. **Version compatibility** — The patched sysroot must be built with the matching wasi-sdk version. If `TAG=wasi-sdk-30`, use wasi-sdk 30.x to compile against it. |
| 47 | +4. **Do not edit UPSTREAM_REF by hand** — The rebase script manages it. Manual edits risk pin/reality divergence. |
| 48 | + |
| 49 | +## Patch Series |
| 50 | + |
| 51 | +The current series has 8 patches, applied in order. Later patches may depend on earlier ones. |
| 52 | + |
| 53 | +| Patch | Purpose | Depends on | |
| 54 | +|-------|---------|------------| |
| 55 | +| `0001-dns-route-getaddrinfo-through-WarpGrid-DNS-shim` | Routes `getaddrinfo()` through the WarpGrid DNS shim | — | |
| 56 | +| `0002-fs-route-fopen-open-through-WarpGrid-virtual-filesys` | Routes `fopen()`/`open()` through the WarpGrid virtual filesystem | — | |
| 57 | +| `0003-socket-route-connect-through-WarpGrid-database-proxy` | Routes `connect()` through the WarpGrid database proxy | 0001 | |
| 58 | +| `0004-socket-route-send-recv-read-write-through-WarpGrid-d` | Routes `send()`/`recv()`/`read()`/`write()` through the proxy | 0003 | |
| 59 | +| `0005-warpgrid-patch-close-for-proxied-fd-cleanup-US-211` | Patches `close()` to clean up proxied file descriptors | 0004 | |
| 60 | +| `0006-dns-route-gethostbyname-through-WarpGrid-DNS-shim` | Routes `gethostbyname()` through the DNS shim | 0001 | |
| 61 | +| `0007-dns-route-getnameinfo-through-WarpGrid-DNS-reverse-r` | Routes `getnameinfo()` through the DNS shim (reverse lookups) | 0001 | |
| 62 | +| `0008-fs-timezone-virtual` | Virtualizes timezone data via the WarpGrid filesystem | — | |
| 63 | + |
| 64 | +**Dependency graph:** |
| 65 | + |
| 66 | +``` |
| 67 | +0001 (DNS getaddrinfo) |
| 68 | +├── 0003 (socket connect) → 0004 (socket send/recv) → 0005 (socket close) |
| 69 | +├── 0006 (DNS gethostbyname) |
| 70 | +└── 0007 (DNS getnameinfo) |
| 71 | +
|
| 72 | +0002 (FS fopen/open) [independent] |
| 73 | +0008 (FS timezone) [independent] |
| 74 | +``` |
| 75 | + |
| 76 | +## Rebase Workflow |
| 77 | + |
| 78 | +When a new upstream wasi-libc release is available (e.g., `wasi-sdk-31`), follow these steps: |
| 79 | + |
| 80 | +### 1. Validate current patch health |
| 81 | + |
| 82 | +```bash |
| 83 | +scripts/rebase-libc.sh --validate |
| 84 | +``` |
| 85 | + |
| 86 | +This checks patch numbering, ordering, and dependency constraints. Fix any issues before proceeding. |
| 87 | + |
| 88 | +### 2. Attempt the rebase |
| 89 | + |
| 90 | +```bash |
| 91 | +scripts/rebase-libc.sh --update wasi-sdk-31 |
| 92 | +``` |
| 93 | + |
| 94 | +This will: |
| 95 | +- Clone wasi-libc at the new tag |
| 96 | +- Apply each patch in order using `git am --3way` |
| 97 | +- Report which patches applied and which conflicted |
| 98 | +- On success: update `UPSTREAM_REF`, export rebased patches, move the source checkout into place |
| 99 | + |
| 100 | +### 3. If the rebase succeeds |
| 101 | + |
| 102 | +Build and test to confirm everything works: |
| 103 | + |
| 104 | +```bash |
| 105 | +scripts/build-libc.sh --patched |
| 106 | +scripts/test-libc.sh --all |
| 107 | +``` |
| 108 | + |
| 109 | +If all tests pass, commit the updated patches and `UPSTREAM_REF`. |
| 110 | + |
| 111 | +### 4. If the rebase has conflicts |
| 112 | + |
| 113 | +The script reports which patch failed and which files conflict. To resolve: |
| 114 | + |
| 115 | +1. Apply patches up to the conflict manually: |
| 116 | + ```bash |
| 117 | + scripts/rebase-libc.sh --apply |
| 118 | + ``` |
| 119 | +2. The script stops at the first conflicting patch. Resolve the conflict in the source checkout (`build/src-patched/`). |
| 120 | +3. After resolving, commit the fix: |
| 121 | + ```bash |
| 122 | + cd build/src-patched |
| 123 | + git add -A |
| 124 | + git am --continue |
| 125 | + ``` |
| 126 | +4. Export the updated patch series: |
| 127 | + ```bash |
| 128 | + scripts/rebase-libc.sh --export |
| 129 | + ``` |
| 130 | +5. Build and test: |
| 131 | + ```bash |
| 132 | + scripts/build-libc.sh --patched |
| 133 | + scripts/test-libc.sh --all |
| 134 | + ``` |
| 135 | + |
| 136 | +## Adding a New Patch |
| 137 | + |
| 138 | +To add a new shim or modification to the patched wasi-libc: |
| 139 | + |
| 140 | +1. **Start from a clean applied state:** |
| 141 | + ```bash |
| 142 | + scripts/rebase-libc.sh --apply |
| 143 | + ``` |
| 144 | + |
| 145 | +2. **Make your changes** in `build/src-patched/`: |
| 146 | + ```bash |
| 147 | + cd build/src-patched |
| 148 | + # Edit source files... |
| 149 | + ``` |
| 150 | + |
| 151 | +3. **Commit with a descriptive message** following the existing convention (`<subsystem>: <description>`): |
| 152 | + ```bash |
| 153 | + git add -A |
| 154 | + git commit -m "dns: route getXXX through WarpGrid DNS shim" |
| 155 | + ``` |
| 156 | + |
| 157 | +4. **Export the updated patch series:** |
| 158 | + ```bash |
| 159 | + scripts/rebase-libc.sh --export |
| 160 | + ``` |
| 161 | + This regenerates all `libc-patches/*.patch` files with correct numbering. |
| 162 | + |
| 163 | +5. **Add a test program** in `libc-patches/tests/`: |
| 164 | + - Name it `test_<subsystem>_<feature>.c` |
| 165 | + - Include the `WARPGRID_SHIM_REQUIRED` marker comment if the test needs WarpGrid shims (so it gets skipped when testing the stock sysroot) |
| 166 | + - Include the `LIBPQ_REQUIRED` marker if the test depends on libpq |
| 167 | + |
| 168 | +6. **Verify:** |
| 169 | + ```bash |
| 170 | + scripts/build-libc.sh --patched |
| 171 | + scripts/test-libc.sh --all |
| 172 | + scripts/rebase-libc.sh --validate |
| 173 | + ``` |
| 174 | + |
| 175 | +7. **Update the dependency table** in this document if the new patch depends on existing patches. Also update the dependency constraints in `rebase-libc.sh`'s `do_validate()` function. |
| 176 | + |
| 177 | +## Troubleshooting |
| 178 | + |
| 179 | +### Context conflict in header changes |
| 180 | + |
| 181 | +**Symptom:** `git am --3way` fails on a patch that modifies files in `libc-bottom-half/headers/` or `libc-top-half/musl/include/`. |
| 182 | + |
| 183 | +**Why it happens:** Upstream modifies the same header files that WarpGrid patches add declarations to. The 3-way merge cannot resolve the context difference automatically. |
| 184 | + |
| 185 | +**Resolution:** |
| 186 | +1. Open the conflicting header file in `build/src-patched/` |
| 187 | +2. Look for `<<<<<<<` conflict markers |
| 188 | +3. Keep both the upstream changes and the WarpGrid additions (WarpGrid typically adds new function declarations or `#include` directives — these rarely conflict semantically) |
| 189 | +4. `git add` the resolved file, then `git am --continue` |
| 190 | +5. Re-export patches: `scripts/rebase-libc.sh --export` |
| 191 | + |
| 192 | +### Symbol collision |
| 193 | + |
| 194 | +**Symptom:** Build fails with `multiple definition of 'some_function'` or linker errors after a successful rebase. |
| 195 | + |
| 196 | +**Why it happens:** Upstream added a function with the same name as a WarpGrid shim (e.g., upstream implements `getaddrinfo` natively). The patches still add WarpGrid's version, causing a duplicate symbol. |
| 197 | + |
| 198 | +**Resolution:** |
| 199 | +1. Check whether upstream's implementation is equivalent to the WarpGrid shim |
| 200 | +2. If yes: remove the WarpGrid shim from the patch (the upstream version replaces it). Update the test to remove the `WARPGRID_SHIM_REQUIRED` marker |
| 201 | +3. If no: rename or guard the WarpGrid shim with a preprocessor check (e.g., `#ifndef __WASI_LIBC_HAS_GETADDRINFO`) |
| 202 | +4. Re-export patches and rebuild |
| 203 | + |
| 204 | +### Build system changes |
| 205 | + |
| 206 | +**Symptom:** Patches apply cleanly but `build-libc.sh` fails because a CMakeLists.txt target or Makefile variable that WarpGrid patches reference has been renamed, moved, or restructured upstream. |
| 207 | + |
| 208 | +**Why it happens:** WarpGrid patches may modify build rules (e.g., adding source files to a target list). If upstream renames or reorganizes those targets, the patch content is syntactically correct but semantically wrong. |
| 209 | + |
| 210 | +**Resolution:** |
| 211 | +1. Compare the upstream CMakeLists.txt/Makefile changes with the patch content |
| 212 | +2. Update the patch to use the new target names or file paths |
| 213 | +3. Re-export and rebuild: |
| 214 | + ```bash |
| 215 | + cd build/src-patched |
| 216 | + # Fix the build files |
| 217 | + git add -A |
| 218 | + git commit --amend |
| 219 | + scripts/rebase-libc.sh --export |
| 220 | + scripts/build-libc.sh --patched |
| 221 | + ``` |
| 222 | + |
| 223 | +## Testing |
| 224 | + |
| 225 | +The test harness runs C test programs from `libc-patches/tests/` against built sysroots. |
| 226 | + |
| 227 | +### Modes |
| 228 | + |
| 229 | +```bash |
| 230 | +scripts/test-libc.sh # Test patched sysroot (default) |
| 231 | +scripts/test-libc.sh --stock # Test stock sysroot only |
| 232 | +scripts/test-libc.sh --patched # Test patched sysroot only |
| 233 | +scripts/test-libc.sh --all # Test both stock and patched sysroots |
| 234 | +scripts/test-libc.sh --ci # Test both + produce JUnit XML report |
| 235 | +``` |
| 236 | + |
| 237 | +### How `--stock` vs `--patched` works |
| 238 | + |
| 239 | +- Tests with the `WARPGRID_SHIM_REQUIRED` marker are **skipped** when testing the stock sysroot (because the shim functions don't exist in stock wasi-libc) |
| 240 | +- Tests with the `LIBPQ_REQUIRED` marker are **skipped** if libpq has not been built |
| 241 | +- All other tests run against both sysroots, verifying that WarpGrid patches don't break baseline functionality |
| 242 | + |
| 243 | +### CI mode (`--ci`) |
| 244 | + |
| 245 | +When `--ci` is passed, the harness: |
| 246 | +1. Runs both stock and patched test suites (same as `--all`) |
| 247 | +2. Generates a JUnit XML report at `test-results/libc-<timestamp>.xml` |
| 248 | +3. Exits non-zero if any test fails |
| 249 | + |
| 250 | +The JUnit XML contains `<testsuite>` and `<testcase>` elements with per-test timing, skip reasons, and failure output — compatible with CI systems like GitHub Actions, Jenkins, and GitLab CI. |
| 251 | + |
| 252 | +### Test harness self-tests |
| 253 | + |
| 254 | +The test harness itself is tested by `scripts/test-libc.test.sh`, which validates flag parsing, output format, and JUnit XML generation using mock toolchains (no wasi-sdk or wasmtime required): |
| 255 | + |
| 256 | +```bash |
| 257 | +scripts/test-libc.test.sh # Run all self-tests |
| 258 | +scripts/test-libc.test.sh --quick # Skip tests that require real execution |
| 259 | +``` |
0 commit comments