Win32 debug heap assertion after reading a cached filter filter while server is terminating

If a new (possibly just the first) TCP client connection comes into a server (any of Synchronet's TCP servers) while the server is already in the process of terminating, but waiting for child threads to terminate (i.e. at the top of its local cleanup() function), a Microsoft debug heap assertion may be thrown upon destruction of a filter/trashcan file object.

free_dbg_nolock(void * const block, const int block_use) (debug_heap.cpp:996)
_free_dbg(void * block, int block_use) (debug_heap.cpp:1030)
free(void * block) (free.cpp:35)
strListFreeStrings(char * * list) (str_list.c:634)
strListFree(char * * * list) (str_list.c:640)
filterFile::~filterFile() (/filterfile.hpp:42)
[External Code] (Unknown Source:0)
cleanup(int code) (/mailsrvr.cpp:6113)
mail_server(void * arg) (/mailsrvr.cpp:6632)
[External Code] (Unknown Source:0)
[Frames below may be incorrect and/or missing, no symbols loaded for sbbsctrl.exe] (Unknown Source:0)

The larger the configured "semaphore check frequency" and the more frequent incoming connections, the more easy it was to reproduce the issue. I could reproduce it on any/all of Synchronet's TCP servers, though I tended to use the mail server for testing experimental changes.

The issue has never been seen/reproduced in Win32-release builds or non-Windows builds.

Here's an unfruitful Gemini discussion about the issue: https://gemini.google.com/share/aac98154728e

Deuce had Claude take a look at the issue and provided a couple commits that did not resolve the issue:

  • commit 2fb010d6
  • commit 61695ba1

Although the issue looks and smells like heap corruption, running sbbs.exe or sbbsctrl.exe under Microsoft's Application Verifier didn't find any heap corruption (with heap page "full" verification enabled), even when the assertion/exception occurred.

I failed to get sbbs.exe or sbbsctrl.exe to run successfully with Address Sanitizer enabled (out of memory errors trying to realloc a 60KB buffer to load main.ini for parsing).

Edited Mar 12, 2026 by Rob Swindell
Assignee Loading
Time tracking Loading