惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
Y
Y Combinator Blog
博客园 - Franky
D
Docker
B
Blog RSS Feed
M
MIT News - Artificial intelligence
雷峰网
雷峰网
博客园 - 司徒正美
人人都是产品经理
人人都是产品经理
宝玉的分享
宝玉的分享
S
SegmentFault 最新的问题
GbyAI
GbyAI
Recent Announcements
Recent Announcements
Martin Fowler
Martin Fowler
H
Hackread – Cybersecurity News, Data Breaches, AI and More
MyScale Blog
MyScale Blog
B
Blog
H
Help Net Security
Microsoft Security Blog
Microsoft Security Blog
WordPress大学
WordPress大学
Vercel News
Vercel News
The Cloudflare Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News

The Old New Thing

std::call_once vs. std::async - The Old New Thing Magic statics vs. std::call_once - The Old New Thing Why do Microsoft job levels start in the high 50's instead of starting at a sane number like 1? - The Old New Thing Why didn't Read­Directory­ChangesW provide a way to correlate the two sides of a rename operation? - The Old New Thing How can I remove the Close button from my window caption? - The Old New Thing Why is the x86 undefined instruction called ud2? Why 2? - The Old New Thing What algorithm did Windows XP use to choose your initial user picture? - The Old New Thing A sample use of the winstart.bat file in Windows 95 - The Old New Thing What happens if you change a window class's GCL_CB­WND­EXTRA? - The Old New Thing The case of the progress callback that never got called when progress happened - The Old New Thing The perils of binding to value types in XAML - The Old New Thing Microspeak: Funded / unfunded - The Old New Thing AWE does not require PAE, though PAE makes it much more useful - The Old New Thing On forcing all derived classes to implement a specific non-virtual method, part 2 - The Old New Thing On forcing all derived classes to implement a specific non-virtual method, part 1 - The Old New Thing In the product end game, every change carries significant risk, episode 2 - The Old New Thing Why didn't the Windows Entertainment Pack just run the MS-DOS version inside an emulator? - The Old New Thing Comparing the two holograms on the Windows 95 box - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function, practical exam - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function - The Old New Thing On wrapping a callable in a lambda that just calls it with the same parameters - The Old New Thing Why did the Microsoft Entertainment Pack for Windows have a special sticker announcing that it also had Tetris? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing Forcing an ARM64X executable to run as a specific architecture - The Old New Thing A little helper class for managing LPPROC_THREAD_ATTRIBUTE_LISTs - The Old New Thing The comments that go into code versus those that go into the pull request description - The Old New Thing The little-known winstart.bat batch file - The Old New Thing How can I perform a Copy­File&shy in unbuffered mode? - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 5 - The Old New Thing
Why don't we allow stacks to be sparse, instead of forcin...
Raymond Chen · 2026-09-07 · via The Old New Thing

When I discussed why we don’t just make the entire stack out of guard pages, commenter BCS wondered, “Why require that the stack use contiguously mapped pages? What would break if only touched pages got mapped in? That could actually be a good thing for example with a function that wanted to alloca 512MB on the stack but only read/writes a few pages.”

So the question is asking why the stack must be contiguous. Why not let it be sparse and fault in only the pages that are touched?

The first issue is that the stack check code would have to include an explicit check against the stack limit, instead of just walking down the stack a page at a time. This explicit check is needed to avoid security vulnerabilities if somebody manages to alloca a buffer so large that it goes past the end of the stack reservation entirely. If you go a single page at a time, you will eventually hit the no-access page that marks the end of the stack. But if you can leap over multiple pages at a time without touching them, you might leap so far past the end of the stack that you land somewhere else and start corrupting that other memory because you’re using it as a stack. In linux circles, this vulnerability is nicknamed “Stack Clash“¹ and goes more formally by “stack guard-page hopping.”²

After fixing that issue, you have another problem: How would you report a failure to commit a page in the middle of the stack?

void dosomething()
{
    void* buffer = NULL;
    __try {
        buffer = alloca(65536);
    } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW) {
        if (!_resetstkoflw()) __fastfail(FAST_FAIL_FATAL_APP_EXIT);
    }

    if (buffer != NULL) {
        ⟦ use the buffer ⟧
    }
}

If you allowed sparse stacks, then the memory for the buffer would not actually be committed until the code used it. But the point the code uses the buffer is outside the exception handler for the failed alloca(). The code assumes, not unreasonably, that if alloca succeeds, then the memory is indeed allocated.

I guess you could fix this by committing the memory without making it present. That would mean making a call to VirtualAlloc to expand the stack rather than just accessing the memory. Not only would this make the stack expansion code more complicated, particularly since you have to preserve all the registers that might possibly be used by any calling convention, but you also have to make sure that the VirtualAlloc function itself doesn’t allocate too much stack!

Now, you can still tweak the x86-32 stack prober to avoid pete.d‘s problem, where a large stack frame is made completely present, with the resulting page-ins creating noticeable performance issues. The x86-32 prober could short-circuit the stack probe (like the MIPS and other processors listed in the table on this page) so that the page-ins occur only when the stack is actually expanding.

¹ Bonus reading about Stack Clash:

² Some systems mitigate stack guard-page hopping by creating a really large no-access region beyond the end of the stack. However, this isn’t a fix; just a mitigation. It just makes people have to leap further to clear the no-access region. If you already have this vulnerability, it’s probably because an attacker can control the size of the allocation, in which case you didn’t really slow them down by much; they just have to put a bigger number in their attack payload.

Other systems address this more thoroughly by (surprise) probing each page of the stack in sequence.

Stack Clash continues to be a problem even though gcc had a solution in 2020. Here’s CVE-2026-77658 from just a few days ago.

Category

Topics

Author

Raymond Chen

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.