Felix Palmen :freebsd: :c64:<p>Revisiting <a href="https://mastodon.bsd.cafe/tags/async" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>async</span></a> / <a href="https://mastodon.bsd.cafe/tags/await" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>await</span></a> in <a href="https://mastodon.bsd.cafe/tags/POSIX" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>POSIX</span></a> C, trying to "add some <a href="https://mastodon.bsd.cafe/tags/security" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>security</span></a>" 🙈 </p><p>Recap: Consider a classic <a href="https://mastodon.bsd.cafe/tags/reactor" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>reactor</span></a>-style service in C with a <a href="https://mastodon.bsd.cafe/tags/threadpool" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>threadpool</span></a> attached to run the individual request handlers. When such a handler needs to do some I/O, it'll have to wait for its completion, and doing so is kind of straight forward by just blocking the worker thread executing the job until whatever I/O was needed completes.</p><p>Now, blocking a thread is never a great thing to do and I recently tooted about an interesting alternative I found: Make use of the (unfortunately deprecated) POSIX user context switching to enable releasing the worker thread while waiting. In a nutshell, you create a context with <a href="https://mastodon.bsd.cafe/tags/makecontext" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>makecontext</span></a> that has its own private <a href="https://mastodon.bsd.cafe/tags/stack" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>stack</span></a>, and then you can use <a href="https://mastodon.bsd.cafe/tags/swapcontext" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>swapcontext</span></a> to get off the thread, and later again to get back on the thread. A minor issue is: It must be the *same* thread ... so you might have to wait until it completes something else before you can resume your job. But then, that's probably okayish, you can make sure in your job scheduling to only use worker threads with awaited tasks attached when no other thread is available.</p><p>In my first implementation, I just used <a href="https://mastodon.bsd.cafe/tags/malloc" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>malloc</span></a> to create a 64kiB private stack for each thread job. That's perfectly fine if you can guarantee your job will never consume more stack space, AND it won't have any vulnerabilities allowing some attacker to mess with the stack. But in practice, especially for a library offering this async/await implementation, it's nothing but a wild <a href="https://mastodon.bsd.cafe/tags/CVE" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>CVE</span></a> generator.</p><p>So, I now improved on that:</p><p>* Allocate a much larger stack of now 2MiB. That alone makes issues at least less likely. And on a sane modern OS, we can still assume pages will only be mapped "on demand".<br>* Only allocate the stack directly before running the thread job, and delegate allocation to some internal "stack manager" that keeps track of all allocated stacks and reuses them, only freeing them on exit. This should avoid most of the allocation overhead.<br>* If MAP_ANON / MAP_ANONYMOUS is available, use <a href="https://mastodon.bsd.cafe/tags/mmap" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>mmap</span></a> for allocating the stack. That at least gives a chance to stay away from other allocations ....<br>* But finally, if MAP_STACK is available, use this flag! From my research, <a href="https://mastodon.bsd.cafe/tags/FreeBSD" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>FreeBSD</span></a>, <a href="https://mastodon.bsd.cafe/tags/OpenBSD" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>OpenBSD</span></a> and <a href="https://mastodon.bsd.cafe/tags/NetBSD" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>NetBSD</span></a> will for example make sure there's at least one "guard page" below a stack mapped with this flag, so a stack overflow consistently takes the SIGSEGV emergency exit 😆. <a href="https://mastodon.bsd.cafe/tags/Linux" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Linux</span></a> knows this flag as well, but doesn't seem to implement such protection at this time ... 🤔 </p><p><a href="https://mastodon.bsd.cafe/tags/C" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>C</span></a> <a href="https://mastodon.bsd.cafe/tags/coding" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>coding</span></a></p>