atproto relay implementation in zig zlay.waow.tech
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix use-after-free: broadcast() was destroying consumers still referenced by Handler

broadcast() removed dead consumers from the list AND called shutdown()+destroy(),
but Handler.close() still held the pointer and later called removeConsumer() on
freed memory. Now broadcast() only unlinks from the list — removeConsumer() is
the sole owner of shutdown + destroy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+2 -2
+2 -2
src/broadcaster.zig
··· 534 534 while (i < self.consumers.items.len) { 535 535 const consumer = self.consumers.items[i]; 536 536 if (!consumer.alive.load(.acquire)) { 537 + // remove from broadcast list but don't destroy — 538 + // Handler.close() → removeConsumer() owns cleanup 537 539 _ = self.consumers.swapRemove(i); 538 - consumer.shutdown(); 539 540 _ = self.stats.consumer_count.fetchSub(1, .monotonic); 540 - self.allocator.destroy(consumer); 541 541 continue; 542 542 } 543 543 if (consumer.enqueue(frame)) {