There's a great Random ASCII blog post about an obscure FPU issue like this [1].
- The crash was in a FPU that Chrome barely uses
- The instruction that crashed Chrome was thousands of instructions away from the one that triggered the exception
- The instruction that triggered the exception was not at fault
- The crash only happened because of third-party code running inside of Chrome
- The crash was ultimately found to be caused by a code-gen bug in Visual Studio 2015
I've run into this kind of thing once myself (sharing a process with other companies is fun!). It was real confusing to get a stack trace showing our code suddenly crashing on a line of code that was doing the exact same thing with the exact same values as it had always done before.
This also happened in python ecosystem where gevent were messing with numpy because gevent was compiled with -ffast-math, which disables subnormal numbers
Cool trick, but I wouldn’t do that for the use case.
The use case they had is saving minidumps when the app crashes. Windows error reporting OS component is flexible enough to support the feature without hacks, they just need to write couple values to registry in the installer of their software. See details on per-application settings in that article: https://learn.microsoft.com/en-us/windows/win32/wer/collecti...
If they want better UX and/or compress & uploads the dump as soon as the app crashes (as opposed to the next launch of the app) – I would solve by making a simple supervisor app which launches the main binary with CreateProcess, waits for it to exit, then looks for the MainApp.exe.{ProcessID}.dmp file created by that WER OS component.
Hello, author here (16 years ago). I don't think that component existed then. In hindsight, we would have either used WER or initiated crash dumps from outside of the process via a watchdog. It is quite problematic to attempt to capture your process state from within a failed process.
That said, we did have a bunch of hand-rolled state capturing (including Python thread stacks) so maybe WER wouldn't have been as useful anyway.
WER has been in the OS for about 20 years. Vista for sure, maybe even before that.
Writing your own minidump uploader in the unhandled exception filter is/was a very common practice in games, while obviously not ideal.
I think Unreal Engine might still do that. So I think that the claim that Direct3D captures exceptions is suspect.
It may trap them and return EXCEPTION_CONTINUE_SEARCH to pass it on to the next handler, but I have a hard time coming up with a reason why it would trap them in the first place. I have personally never seen Direct3D trap an exception in my long career.
Maybe you were expecting C++ exceptions to be caught, but these APIs are only for SEH.
Now Flash, I have no experience with.
Yes, I know it's a 16year old post. But I must stop myths.
Direct3D doesn't, but the kernel can eat exceptions if 32-bit code triggers an exception from a user mode callback on a 64-bit system. Rendering code is vulnerable to this when triggered from a WM_PAINT message. The call SetProcessUserModeExceptionPolicy() is needed to override the default behavior:
It was introduced in a Windows 7 update and documented in a knowledge base article that has since been removed instead of the regular Win32 docs, so information on it is harder to find these days.
The Registry keys for WER, even the per-application ones, are all under HKEY_LOCAL_MACHINE. They cannot be set without elevation. WER is also useless if you want to capture contextual in-process data about the crash.
This problem is so rampant that even Office hooks SetUnhandledExceptionFilter.
Requiring elevation wasn't uncommon for games or most applications back then. Installing to local app data is somewhat new, though platforms like Steam smartly modified the NTFS permissions in their own app dir to prevent elevation specifically for binary deployment; other components like C runtime, etc. during game install would require elevation.
Office is a poor example of 'what to do'. The title bar is a hack. It only supports ~214 character path length even though Win32 API has been lifted to 32k, etc.
Sure, if an application uses an elevated installer -- but as you note, not all do. It does look like WER may support options being set in HKCU (per-user) as well as HKLM (machine-wide), which would be a way of handling local installs.
I wouldn't characterize Steam's world-writable folder strategy as smart, compared to a more secure model using an elevated downloader and installer.
I fail to see what Office's title bar rendering has to do with its exception handling strategy. As for path length handling, Office also hosts a large in-process plugin ecosystem, so it has to be conservative with such application-level policy changes.
Cool solution, but I'd assume/hope Windows currently has sufficient memory protections to not allow applications to rewrite their own memory - especially if the function was already in a DLL to begin with and not JIT-generated code?
Code segments are not writeble by default on Windows, like on any modern OS, but you can make any memory segment in your own process writable using VirtualProtect. That is not unique to Windows as well, on Linux you could achieve the same with mprotect.
As sibling notes, executable memory is not by default writable. If desired, you can also further disallow any executable memory to me allocated or modified by your process, even via the normal APIs, by calling SetProcessMitigationPolicy with ProcessDynamicCodePolicy.
The most insidious version of this I experienced was when a library changed the FPU settings.
Fortunately, it was sufficient to reset the FPU settings after initializing the library. But it sure took a long time to figure out what happened!
There's a great Random ASCII blog post about an obscure FPU issue like this [1].
I've run into this kind of thing once myself (sharing a process with other companies is fun!). It was real confusing to get a stack trace showing our code suddenly crashing on a line of code that was doing the exact same thing with the exact same values as it had always done before.[1]: https://randomascii.wordpress.com/2016/09/16/everything-old-...
This also happened in python ecosystem where gevent were messing with numpy because gevent was compiled with -ffast-math, which disables subnormal numbers
Blog post: https://moyix.blogspot.com/2022/09/someones-been-messing-wit... HN discussion: https://news.ycombinator.com/item?id=41212072
Cool trick, but I wouldn’t do that for the use case.
The use case they had is saving minidumps when the app crashes. Windows error reporting OS component is flexible enough to support the feature without hacks, they just need to write couple values to registry in the installer of their software. See details on per-application settings in that article: https://learn.microsoft.com/en-us/windows/win32/wer/collecti...
If they want better UX and/or compress & uploads the dump as soon as the app crashes (as opposed to the next launch of the app) – I would solve by making a simple supervisor app which launches the main binary with CreateProcess, waits for it to exit, then looks for the MainApp.exe.{ProcessID}.dmp file created by that WER OS component.
Hello, author here (16 years ago). I don't think that component existed then. In hindsight, we would have either used WER or initiated crash dumps from outside of the process via a watchdog. It is quite problematic to attempt to capture your process state from within a failed process.
That said, we did have a bunch of hand-rolled state capturing (including Python thread stacks) so maybe WER wouldn't have been as useful anyway.
WER has been in the OS for about 20 years. Vista for sure, maybe even before that.
Writing your own minidump uploader in the unhandled exception filter is/was a very common practice in games, while obviously not ideal.
I think Unreal Engine might still do that. So I think that the claim that Direct3D captures exceptions is suspect.
It may trap them and return EXCEPTION_CONTINUE_SEARCH to pass it on to the next handler, but I have a hard time coming up with a reason why it would trap them in the first place. I have personally never seen Direct3D trap an exception in my long career.
Maybe you were expecting C++ exceptions to be caught, but these APIs are only for SEH.
Now Flash, I have no experience with.
Yes, I know it's a 16year old post. But I must stop myths.
Direct3D doesn't, but the kernel can eat exceptions if 32-bit code triggers an exception from a user mode callback on a 64-bit system. Rendering code is vulnerable to this when triggered from a WM_PAINT message. The call SetProcessUserModeExceptionPolicy() is needed to override the default behavior:
https://code.google.com/archive/p/crashrpt/issues/104
It was introduced in a Windows 7 update and documented in a knowledge base article that has since been removed instead of the regular Win32 docs, so information on it is harder to find these days.
The Registry keys for WER, even the per-application ones, are all under HKEY_LOCAL_MACHINE. They cannot be set without elevation. WER is also useless if you want to capture contextual in-process data about the crash.
This problem is so rampant that even Office hooks SetUnhandledExceptionFilter.
Requiring elevation wasn't uncommon for games or most applications back then. Installing to local app data is somewhat new, though platforms like Steam smartly modified the NTFS permissions in their own app dir to prevent elevation specifically for binary deployment; other components like C runtime, etc. during game install would require elevation.
Office is a poor example of 'what to do'. The title bar is a hack. It only supports ~214 character path length even though Win32 API has been lifted to 32k, etc.
Sure, if an application uses an elevated installer -- but as you note, not all do. It does look like WER may support options being set in HKCU (per-user) as well as HKLM (machine-wide), which would be a way of handling local installs.
I wouldn't characterize Steam's world-writable folder strategy as smart, compared to a more secure model using an elevated downloader and installer.
I fail to see what Office's title bar rendering has to do with its exception handling strategy. As for path length handling, Office also hosts a large in-process plugin ecosystem, so it has to be conservative with such application-level policy changes.
Cool solution, but I'd assume/hope Windows currently has sufficient memory protections to not allow applications to rewrite their own memory - especially if the function was already in a DLL to begin with and not JIT-generated code?
Code segments are not writeble by default on Windows, like on any modern OS, but you can make any memory segment in your own process writable using VirtualProtect. That is not unique to Windows as well, on Linux you could achieve the same with mprotect.
As sibling notes, executable memory is not by default writable. If desired, you can also further disallow any executable memory to me allocated or modified by your process, even via the normal APIs, by calling SetProcessMitigationPolicy with ProcessDynamicCodePolicy.
https://learn.microsoft.com/en-us/windows/win32/api/processt...
The exception to this is if you're leveraging large-page support. Large pages are always read/write (and nonpageable).
But that's a rare edge case.
Which is why the code in the article changes memory protections from read+execute to read+write and then back again after modifying the code.