How can I check whether a parameter is a pointer to a stack variable?

Raymond Chen

Raymond

A customer traced a bug in their program back to the fact that somebody passed a stack buffer to a function that operates asynchronously. Something like this:

// This function sends the buffer to the destination
// asynchronously. When the send completes, the completion
// handler is invoked.
HRESULT SendDataAsync(void *buffer, size_t bufferSize,
                      ITransferCompletion* completion);

class ColorSender : public ITransferCompletion
{
...
};

// Code in italics is wrong
HRESULT ColorSender::SendColor()
{
  COLORREF color = GetColorToSend();
  return SendDataAsync(&color, sizeof(color), this);
}

This bug led to the destination sometimes receiving corrupted data because it was a race between the stack variable being reused for something else and the data transport code copying the buffer into the transport channel. In this particular case, the customer fixed the problem by making the color local variable a member of the Color­Sender class, because the Color­Sender object itself must remain valid for the lifetime of the transfer seeing as it is the completion handler. (We’re using the principle that code is mostly correct.)

The customer wanted to add some debugging code to the Send­Data­Async function so that it can assert that the buffer is not on the stack. The customer understands that this may be overly restrictive, and would not be appropriate for a function with a broad audience, but this function is used only within their application, so being extra-restrictive is probably okay.¹

On Windows 8 and higher, the customer can use the Get­Current­Thread­Stack­Limits function to get the bounds of the current thread’s stack and use that to verify that the buffer pointer is not in that range. (Since this is just for debugging purposes, they can skip the test if running on older versions of Windows, and hope that their testing on Windows 8 will catch the problem.)

¹ If it turns out that the check is too restrictive, they could create two functions. The first is called Send­Possibly­Stack­Data­Async that does no validation, and the second is Send­Data­Async which does the initial validation that the buffer is not on the stack, and then calls Send­Possibly­Stack­Data­Async. Most callers use Send­Data­Async, but if you’re in a special case where you are sending stack data and you know that you won’t return from the function until the completion occurs, then you can use Send­Possibly­Stack­Data­Async. The team could have a rule that equires all uses of Send­Possibly­Stack­Data­Async to undergo a special review.

Update: See follow-up discussion.

Raymond Chen
Raymond Chen

Follow Raymond   

0 comments

Comments are closed.