Commit 1d7c4ea
* feat: io_uring fixed-buffer send (write_fixed) (#284)
Completes the fixed recv/send primitive pair: `send_fixed` writes a reply from a
REGISTERED buffer via write_fixed_all, the write-side analog of recv_fixed. New
in ironcache-runtime::fixed_datapath.
It stages `data` into a checked-out registered buffer (copy_nonoverlapping into
the buffer's stable_mut_ptr + set_init, in one small documented unsafe block --
data.len() is guarded <= the buffer capacity, distinct allocations, exactly
data.len() bytes written then marked initialized, so write_fixed_all reads only
those bytes) and writes it without a per-write pin.
Its fall-back contract MIRRORS recv_fixed's for one clean caller branch: it
returns None -- "use the owned-buffer send" -- when the reply does NOT fit one
buffer (> ring.buf_size(), a rare large bulk value) OR the slab is drained. The
single-buffer size decision stays with this primitive; the serve-loop wiring
picks fixed-vs-owned send off the None.
Validated on a real ring (local Linux container kernel 6.8 + the CI io_uring
datapath job): a full fixed recv+send round-trip (request read via read_fixed,
reply written via write_fixed_all, client observes it byte-exact) plus the
oversized-reply -> None fall-back. 43 io_uring lib tests pass; clippy -D warnings
over --features io_uring clean (incl. the unsafe block); macOS build + fmt +
invariant lints clean; 0 dashes. No throughput claim (deferred to a pinned host).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: ELares <zeke@butlr.io>
* fix: slice fixed-buffer send to data.len() to not leak stale bytes (#284)
Adversarial review (verified against the tokio-uring 0.5 source) caught a real
correctness + information-disclosure defect in send_fixed. `write_fixed_all(buf)`
submits `buf.bytes_init()` bytes, but tokio-uring's `set_init` is GROW-ONLY and
`FixedBufPool` RETAINS init_len across buffer reuse. So a reused buffer whose
retained init_len exceeds the reply length would send the reply FOLLOWED BY the
stale trailing bytes of a prior (longer) recv/reply through that buffer -- and
because the slab is shared across all connections on the shard, those leaked bytes
can be another client's request/reply data.
Not UB / not OOB (the stale bytes are within init_len = previously-initialized
memory); a semantic bug: `set_init(data.len())` cannot SHRINK init_len, so it does
not bound the write.
Fix: write `buf.slice(0..data.len())` so the SQE length is the slice length
(`end - begin`), independent of the buffer's retained init_len. The reply is
pinned to exactly the fresh bytes.
Regression test added (fixed_send_of_a_short_reply_after_a_longer_recv_leaks_no_
stale_bytes): a pool of ONE buffer forces send_fixed to reuse the exact buffer a
prior 20-byte recv filled, then sends a 5-byte reply. VERIFIED it FAILS on the old
`write_fixed_all(buf)` (client received "+OK\r\n" + 15 stale 'q' bytes from the
prior request) and PASSES with the slice fix (exactly 5 bytes). My earlier
round-trip test masked the bug only because its 7-byte reply happened to be LONGER
than the 6-byte prior recv (set_init grew, no stale tail).
44 io_uring lib tests pass; clippy -D warnings over --features io_uring clean;
macOS build + fmt + invariant lints clean; 0 dashes.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: ELares <zeke@butlr.io>
---------
Signed-off-by: ELares <zeke@butlr.io>
Co-authored-by: ELares <zeke@butlr.io>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d933916 commit 1d7c4ea
2 files changed
Lines changed: 140 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
167 | 173 | | |
168 | 174 | | |
169 | 175 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
86 | 87 | | |
87 | 88 | | |
88 | 89 | | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
89 | 125 | | |
90 | 126 | | |
91 | | - | |
| 127 | + | |
92 | 128 | | |
93 | 129 | | |
94 | 130 | | |
| |||
141 | 177 | | |
142 | 178 | | |
143 | 179 | | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
144 | 277 | | |
145 | 278 | | |
146 | 279 | | |
| |||
0 commit comments