c0ab9cb5b5
Until there's a "Wait", there's usually only one API message inflight at a time. In our quest for performance, we put that single API message in charge of its own buffer management: instead of allocating buffers on the heap and deleting them later (storing pointers to them at the far corners of the earth), it would instead allocate them from small internal pools (if possible) and only heap allocate (transparently) if necessary. The pointers flung to the corners of the earth would be pointers (1) back into the API_MSG or (2) to a heap block owned by boost::small_vector. It took us months to realize that those bare pointers were being held by COOKED_READ and RAW_READ and not actually being updated when the API message was _copied_ as it was shuffled off to the background to become a "Wait" message. It turns out that it's trivially possible to crash the console by sending two API calls--one that waits and one that completes immediately--when the waiting message or the "wait completer" has a bunch of dangling pointers in it. It further turns out that some accessibility software (like JAWS) attaches directly to the console session, much like winpty and ConEmu and friends. They're trying to read out the buffer (API call!) and sometimes there's a shell waiting for input (API call!). Oops. In this commit, we fix up the message's internal pointers (in lieu of giving it a proper copy constructor; see GH-10076) and then tell the wait completion routine (which is going to be a COOKED_READ, RAW_READ, DirectRead or WriteData) about the new buffer location. This is a scoped fix that should be replaced (TODO GH-10076) with a final one after Ask mode. Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev eca0875950fd3a9735662474613405e2dc06f485 References GH-10076 Fixes MSFT-33127449 Fixes GH-9692
64 lines
1.9 KiB
C++
64 lines
1.9 KiB
C++
/*++
|
|
Copyright (c) Microsoft Corporation
|
|
Licensed under the MIT license.
|
|
|
|
Module Name:
|
|
- readData.hpp
|
|
|
|
Abstract:
|
|
- This file defines the interface for read data structures.
|
|
- Read data structures are used to pass context between various layers of the read
|
|
as well as to persist state across a read call that must wait until additional
|
|
data is added to the buffer at a later time.
|
|
|
|
Author:
|
|
- Austin Diviness (AustDi) 1-Mar-2017
|
|
- Michael Niksa (MiNiksa) 1-Mar-2017
|
|
|
|
Revision History:
|
|
--*/
|
|
|
|
#pragma once
|
|
|
|
#include "../server/IWaitRoutine.h"
|
|
#include "../server/WaitTerminationReason.h"
|
|
|
|
class ReadData : public IWaitRoutine
|
|
{
|
|
public:
|
|
ReadData(_In_ InputBuffer* const pInputBuffer,
|
|
_In_ INPUT_READ_HANDLE_DATA* const pInputReadHandleData);
|
|
|
|
virtual ~ReadData();
|
|
|
|
ReadData(const ReadData&) = delete;
|
|
ReadData(ReadData&&);
|
|
ReadData& operator=(const ReadData&) & = delete;
|
|
ReadData& operator=(ReadData&&) & = delete;
|
|
|
|
virtual void MigrateUserBuffersOnTransitionToBackgroundWait(const void* oldBuffer, void* newBuffer) = 0;
|
|
virtual bool Notify(const WaitTerminationReason TerminationReason,
|
|
const bool fIsUnicode,
|
|
_Out_ NTSTATUS* const pReplyStatus,
|
|
_Out_ size_t* const pNumBytes,
|
|
_Out_ DWORD* const pControlKeyState,
|
|
_Out_ void* const pOutputData) = 0;
|
|
|
|
InputBuffer* GetInputBuffer() const;
|
|
INPUT_READ_HANDLE_DATA* GetInputReadHandleData() const;
|
|
|
|
// TODO MSFT:11285829 this is a temporary kludge until the constructors are ironed
|
|
// out, so that we can still run the tests in the meantime.
|
|
#if UNIT_TESTING
|
|
ReadData() :
|
|
IWaitRoutine(ReplyDataType::Read),
|
|
_pInputBuffer{ nullptr },
|
|
_pInputReadHandleData{ nullptr }
|
|
{
|
|
}
|
|
#endif
|
|
protected:
|
|
InputBuffer* _pInputBuffer;
|
|
INPUT_READ_HANDLE_DATA* _pInputReadHandleData;
|
|
};
|