Exception "The data area passed to a system call is too small"
See original GitHub issueDescription
Encountered the below exception stack trace in our production WPF application.
Details are scant but I do know the PC was running Windows 10 Pro 2009, and the version of our software that was running targeted net6.0-windows runtime environment. I also have a list of processes that were currently running at the time of the exception. I’m not sure how to share that privately here; let me know if you need it and I’ll arrange a way.
It’s difficult to tell exactly what the state of our software was when this exception happened, but other than this exception all signs indicate the software was operating normally.
Here’s the stack trace:
Type: System.ComponentModel.Win32Exception
Message: The data area passed to a system call is too small.
Source: WindowsBase
Stack Trace:
at MS.Win32.UnsafeNativeMethods.GetWindowText(HandleRef hWnd, StringBuilder lpString, Int32 nMaxCount)
at System.Windows.Automation.Peers.WindowAutomationPeer.GetNameCore()
at System.Windows.Automation.Peers.AutomationPeer.UpdateSubtree()
at System.Windows.ContextLayoutManager.fireAutomationEvents()
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
Internet search results currently point to some issue with an out-of-date installation of SQL Server. I do not believe SQL Server is/was present on this machine.
Reproduction Steps
Sorry
Expected behavior
I expect no exception
Actual behavior
Above exception was thrown
Regression?
No response
Known Workarounds
No response
Configuration
Windows 10 Pro 2009 x64 WPF net6.0-windows target
Other information
No response
Issue Analytics
- State:
- Created 2 years ago
- Reactions:5
- Comments:16 (3 by maintainers)
Top GitHub Comments
Another workaround
I think the following will more reliably work around this issue.
In general, P/Invoke the
SetWindowsHookEx
function with these parameters:idHook
:WH_CALLWNDPROCRET
(12)lpfn
: the function described belowhmod
:IntPtr.Zero
, or 0dwThreadId
: current thread’s native IDThe function signature for
WH_CALLWNDPROCRET
is described here: https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nc-winuser-hookprocWhat you want to do in this function is inspect the
CWPRETSTRUCT
parameter to see if the message is aWM_GETTEXT
message. If so, then just set last system error to zero (Marshal.SetLastSystemError(0)
).Here’s some example WPF code that uses the
PInvoke.User32
andPInvoke.Kernel32
NuGet packages to make it easier to deal with the native calls and structures:This (obviously) requires your project to allow unsafe code.
With this in my WPF app I can now set system errors all I want in as many hooks for
WM_GETTEXT
message hooks as I want, and my app won’t throw this issue’s exception.However this does not hook into windows created on other threads. If you start a new
Dispatcher
in another thread and show aWindow
there then you’ll need to run the above code on that thread, too.Reproduction
Turns out it’s easy enough to trigger this exception by simply having a window with an empty
Title
and then setting the system error to 122 within a message loop hook for the WM_GETTEXT message and finally returning zero:I think it’s significant that the message doesn’t even have to be marked handled.
And it’s not necessary to conditionally set the error. It also throws the exception if
SetLastSystemError(122)
is outside the if-statement.But with the above then you get this exception stack:
The stack trace is different because the layout pass is apparently being invoked by a different code path. But you’ll notice that the same methods are being exercised at the top of the stack.
Findings
As you can see, the exception message is caused by Win32 error 122. After running all the relevant Microsoft DLLs through disassemblers and tracing through Microsoft’s source code online we can see that error 122 is not raised on any of the relevant code paths.
And I guess I should state the obvious: no we are not knowingly setting the system error to 122 in the message loops in our software.
Taking all these things into account, I’m deducing these things:
Path forward
Possible workaround
First, let me show a possible workaround I found. We’ll probably implement this in our software. All you have to do is be the first to add this band-aid hook. But this only works if the WM_GETTEXT message goes unhandled by all hooks prior to the band-aid hook. So this likely won’t fix the issue for us:
Looking long term
Let’s take a look at that WPF method at the very top of the stack:
…and the
NativeMethodsSetLastError.GetWindowText(...)
method looks like this:I ran
PresentationNative_v0400.dll -> GetWindowTextWrapper(...)
through a disassembler and can see that all it’s doing isSetLastError(0)
before calling GetWindowTextW, which states:To me it seems like a bad decision to make it impossible to distinguish between an empty title bar and an error condition. But I’m betting that nobody will be in any hurry to alter the behavior of
GetWindowTextW
.So I would like to propose:
UnsafeNativeMethodsCLR.GetWindowText(...)
should not check for errors, but should instead just return an empty string whenNativeMethodsSetLastError.GetWindowText(...)
returns zero. Would the WPF folks like a PR for this?