Author: hbelusca
Date: Fri Aug 8 17:06:28 2014
New Revision: 63841
URL: http://svn.reactos.org/svn/reactos?rev=63841&view=rev
Log:
[KERNEL32][CONSRV]
For WriteConsoleOutput API only!! Diagnosed with ApiMonitor from Rohitab.
If one tries to write a too large buffer (>= 80*198 CHAR_INFO cells), the CsrAllocateCaptureBuffer API helper fails, because it uses the non-growable CSR port heap of fixed size 64kB.
Since many applications use the API with large buffers (for example, Far Manager <= 1.70, the Windows XTree app http://textmode.netne.net/Extreme.html , ...) and maybe NTVDM,
Windows (and hence ReactOS for compatibility reasons) allocates a buffer in the process' heap (and not in the CSR port heap via the CSR capture API), so that the big buffer allocation
should work. Then, to be able to access it, CSR needs to call NtReadVirtualMemory for capturing the buffer.
CORE-5006 CORE-6397 CORE-8424 #resolve
Modified:
branches/condrv_restructure/dll/win32/kernel32/client/console/readwrite.c
branches/condrv_restructure/include/reactos/subsys/win/conmsg.h
branches/condrv_restructure/win32ss/user/winsrv/consrv/conoutput.c
Modified: branches/condrv_restructure/dll/win32/kernel32/client/console/readwrite.c
URL: http://svn.reactos.org/svn/reactos/branches/condrv_restructure/dll/win32/ke…
==============================================================================
--- branches/condrv_restructure/dll/win32/kernel32/client/console/readwrite.c [iso-8859-1] (original)
+++ branches/condrv_restructure/dll/win32/kernel32/client/console/readwrite.c [iso-8859-1] Fri Aug 8 17:06:28 2014
@@ -881,6 +881,7 @@
{
WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer;
// CaptureBuffer = NULL;
+ WriteOutputRequest->UseVirtualMemory = FALSE;
}
else
{
@@ -888,17 +889,36 @@
/* Allocate a Capture Buffer */
CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
- if (CaptureBuffer == NULL)
- {
- DPRINT1("CsrAllocateCaptureBuffer failed with size %ld!\n", Size);
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
-
- /* Allocate space in the Buffer */
- CsrAllocateMessagePointer(CaptureBuffer,
- Size,
- (PVOID*)&WriteOutputRequest->CharInfo);
+ if (CaptureBuffer)
+ {
+ /* Allocate space in the Buffer */
+ CsrAllocateMessagePointer(CaptureBuffer,
+ Size,
+ (PVOID*)&WriteOutputRequest->CharInfo);
+ WriteOutputRequest->UseVirtualMemory = FALSE;
+ }
+ else
+ {
+ /*
+ * CsrAllocateCaptureBuffer failed because we tried to allocate
+ * a too large (>= 64 kB, size of the CSR heap) data buffer.
+ * To circumvent this, Windows uses a trick (that we reproduce for
+ * compatibility reasons): we allocate a heap buffer in the process'
+ * memory, and CSR will read it via NtReadVirtualMemory.
+ */
+ DPRINT1("CsrAllocateCaptureBuffer failed with size %ld, let's use local heap buffer...\n", Size);
+
+ WriteOutputRequest->CharInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
+ WriteOutputRequest->UseVirtualMemory = TRUE;
+
+ /* Bail out if we still cannot allocate memory */
+ if (WriteOutputRequest->CharInfo == NULL)
+ {
+ DPRINT1("Failed to allocate heap buffer with size %ld!\n", Size);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ }
}
/* Capture the user buffer contents */
@@ -945,7 +965,16 @@
Success = NT_SUCCESS(ApiMessage.Status);
/* Release the capture buffer if needed */
- if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
+ if (CaptureBuffer)
+ {
+ CsrFreeCaptureBuffer(CaptureBuffer);
+ }
+ else
+ {
+ /* If we used a heap buffer, free it */
+ if (WriteOutputRequest->UseVirtualMemory)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, WriteOutputRequest->CharInfo);
+ }
/* Retrieve the results */
_SEH2_TRY
Modified: branches/condrv_restructure/include/reactos/subsys/win/conmsg.h
URL: http://svn.reactos.org/svn/reactos/branches/condrv_restructure/include/reac…
==============================================================================
--- branches/condrv_restructure/include/reactos/subsys/win/conmsg.h [iso-8859-1] (original)
+++ branches/condrv_restructure/include/reactos/subsys/win/conmsg.h [iso-8859-1] Fri Aug 8 17:06:28 2014
@@ -544,7 +544,12 @@
SMALL_RECT WriteRegion;
BOOLEAN Unicode;
- ULONG Unknown;
+ /*
+ * If we are going to write too large (>= 64 kB, size of the CSR heap)
+ * data buffers, we allocate a heap buffer in the process' memory, and
+ * CSR will read it via NtReadVirtualMemory.
+ */
+ BOOLEAN UseVirtualMemory;
} CONSOLE_WRITEOUTPUT, *PCONSOLE_WRITEOUTPUT;
typedef struct
Modified: branches/condrv_restructure/win32ss/user/winsrv/consrv/conoutput.c
URL: http://svn.reactos.org/svn/reactos/branches/condrv_restructure/win32ss/user…
==============================================================================
--- branches/condrv_restructure/win32ss/user/winsrv/consrv/conoutput.c [iso-8859-1] (original)
+++ branches/condrv_restructure/win32ss/user/winsrv/consrv/conoutput.c [iso-8859-1] Fri Aug 8 17:06:28 2014
@@ -463,15 +463,15 @@
DPRINT("SrvReadConsoleOutput\n");
+ NumCells = (ReadOutputRequest->ReadRegion.Right - ReadOutputRequest->ReadRegion.Left + 1) *
+ (ReadOutputRequest->ReadRegion.Bottom - ReadOutputRequest->ReadRegion.Top + 1);
+
/*
* For optimization purposes, Windows (and hence ReactOS, too, for
* compatibility reasons) uses a static buffer if no more than one
* cell is read. Otherwise a new buffer is used.
* The client-side expects that we know this behaviour.
*/
- NumCells = (ReadOutputRequest->ReadRegion.Right - ReadOutputRequest->ReadRegion.Left + 1) *
- (ReadOutputRequest->ReadRegion.Bottom - ReadOutputRequest->ReadRegion.Top + 1);
-
if (NumCells <= 1)
{
/*
@@ -520,47 +520,83 @@
NTSTATUS Status;
PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest;
PTEXTMODE_SCREEN_BUFFER Buffer;
+ PCSR_PROCESS Process = CsrGetClientThread()->Process;
ULONG NumCells;
PCHAR_INFO CharInfo;
DPRINT("SrvWriteConsoleOutput\n");
- /*
- * For optimization purposes, Windows (and hence ReactOS, too, for
- * compatibility reasons) uses a static buffer if no more than one
- * cell is written. Otherwise a new buffer is used.
- * The client-side expects that we know this behaviour.
- */
NumCells = (WriteOutputRequest->WriteRegion.Right - WriteOutputRequest->WriteRegion.Left + 1) *
(WriteOutputRequest->WriteRegion.Bottom - WriteOutputRequest->WriteRegion.Top + 1);
- if (NumCells <= 1)
- {
- /*
- * Adjust the internal pointer, because its old value points to
- * the static buffer in the original ApiMessage structure.
- */
- // WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer;
- CharInfo = &WriteOutputRequest->StaticBuffer;
- }
- else
- {
- if (!CsrValidateMessageBuffer(ApiMessage,
- (PVOID*)&WriteOutputRequest->CharInfo,
- NumCells,
- sizeof(CHAR_INFO)))
- {
- return STATUS_INVALID_PARAMETER;
- }
-
- CharInfo = WriteOutputRequest->CharInfo;
- }
-
- Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+ Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(Process),
WriteOutputRequest->OutputHandle,
&Buffer, GENERIC_WRITE, TRUE);
if (!NT_SUCCESS(Status)) return Status;
+
+ /*
+ * Validate the message buffer if we do not use a process' heap buffer
+ * (CsrAllocateCaptureBuffer succeeded because we haven't allocated
+ * a too large (>= 64 kB, size of the CSR heap) data buffer).
+ */
+ if (!WriteOutputRequest->UseVirtualMemory)
+ {
+ /*
+ * For optimization purposes, Windows (and hence ReactOS, too, for
+ * compatibility reasons) uses a static buffer if no more than one
+ * cell is written. Otherwise a new buffer is used.
+ * The client-side expects that we know this behaviour.
+ */
+ if (NumCells <= 1)
+ {
+ /*
+ * Adjust the internal pointer, because its old value points to
+ * the static buffer in the original ApiMessage structure.
+ */
+ // WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer;
+ CharInfo = &WriteOutputRequest->StaticBuffer;
+ }
+ else
+ {
+ if (!CsrValidateMessageBuffer(ApiMessage,
+ (PVOID*)&WriteOutputRequest->CharInfo,
+ NumCells,
+ sizeof(CHAR_INFO)))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Quit;
+ }
+
+ CharInfo = WriteOutputRequest->CharInfo;
+ }
+ }
+ else
+ {
+ /*
+ * This was not the case: we use a heap buffer. Retrieve its contents.
+ */
+ ULONG Size = NumCells * sizeof(CHAR_INFO);
+
+ CharInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size);
+ if (CharInfo == NULL)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quit;
+ }
+
+ Status = NtReadVirtualMemory(Process->ProcessHandle,
+ WriteOutputRequest->CharInfo,
+ CharInfo,
+ Size,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ ConsoleFreeHeap(CharInfo);
+ // Status = STATUS_NO_MEMORY;
+ goto Quit;
+ }
+ }
Status = ConDrvWriteConsoleOutput(Buffer->Header.Console,
Buffer,
@@ -568,6 +604,11 @@
CharInfo,
&WriteOutputRequest->WriteRegion);
+ /* Free the temporary buffer if we used the process' heap buffer */
+ if (WriteOutputRequest->UseVirtualMemory && CharInfo)
+ ConsoleFreeHeap(CharInfo);
+
+Quit:
ConSrvReleaseScreenBuffer(Buffer, TRUE);
return Status;
}
Author: jgardou
Date: Thu Aug 7 18:20:46 2014
New Revision: 63837
URL: http://svn.reactos.org/svn/reactos?rev=63837&view=rev
Log:
[CMAKE]
- separate the custom target and the custom command generating reactos.cab, so that it isn't regenerated each time a bootcd is built
Note to make user: I tried a hack so that the sequence 'make module/fast reactos_cab/fast bootcd/fast' still works, but this is untested. Please use ninja if you really want fast dependency resolution.
Modified:
trunk/reactos/boot/bootdata/CMakeLists.txt
trunk/reactos/boot/bootdata/packages/CMakeLists.txt
trunk/reactos/cmake/CMakeMacros.cmake
Modified: trunk/reactos/boot/bootdata/CMakeLists.txt
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/bootdata/CMakeLists.t…
==============================================================================
--- trunk/reactos/boot/bootdata/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/boot/bootdata/CMakeLists.txt [iso-8859-1] Thu Aug 7 18:20:46 2014
@@ -18,10 +18,14 @@
COMMAND native-utf16le ${_hive} ${_converted_hive}
DEPENDS native-utf16le ${_hive})
list(APPEND _converted_common_hives ${_converted_hive})
- add_cd_file(FILE ${_converted_hive} DESTINATION reactos NO_CAB FOR bootcd regtest)
endforeach()
add_custom_target(converted_hives DEPENDS ${_converted_common_hives})
+add_cd_file(TARGET converted_hives
+ FILE ${_converted_common_hives}
+ DESTINATION reactos
+ NO_CAB
+ FOR bootcd regtest)
# livecd hives
list(APPEND _livecd_hives
@@ -84,7 +88,7 @@
add_link(NAME ${name} CMD_LINE_ARGS ${app} ICON ${app} PATH livecd_start.cmd GUID "{450D8FBA-AD25-11D0-98A8-0800361B1103}" MINIMIZE)
list(APPEND LIVECD_SHORTCUTS "${CMAKE_CURRENT_BINARY_DIR}/${name}.lnk")
add_cd_file(FILE "${CMAKE_CURRENT_BINARY_DIR}/${name}.lnk"
- TARGET livecd_links
+ TARGET livecd_links
DESTINATION ${dest}
FOR livecd)
endmacro(add_livecd_shortcut)
Modified: trunk/reactos/boot/bootdata/packages/CMakeLists.txt
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/bootdata/packages/CMa…
==============================================================================
--- trunk/reactos/boot/bootdata/packages/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/boot/bootdata/packages/CMakeLists.txt [iso-8859-1] Thu Aug 7 18:20:46 2014
@@ -15,12 +15,18 @@
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/reactos.dff.dyn "")
+# This finalizes reactos.dff by concat-ing the two files: one generated and one static containing the optional file.
+# please keep it this way as it permits to add files to reactos.dff.in without having to run cmake again
+# and also avoids rebuilding reactos.cab in case nothing changes after a cmake run
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/reactos.dff
COMMAND ${CMAKE_COMMAND} -D SRC1=${CMAKE_CURRENT_SOURCE_DIR}/reactos.dff.in
-D SRC2=${CMAKE_CURRENT_BINARY_DIR}/reactos.dff.dyn
- -D DST=${CMAKE_CURRENT_BINARY_DIR}/reactos.dff
+ -D DST=${CMAKE_CURRENT_BINARY_DIR}/reactos.dff.maydiff
-P ${CMAKE_CURRENT_BINARY_DIR}/concat.cmake
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_BINARY_DIR}/reactos.dff.maydiff
+ ${CMAKE_CURRENT_BINARY_DIR}/reactos.dff
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/reactos.dff.in
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/reactos.dff.dyn
)
@@ -34,10 +40,15 @@
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/reactos.dff native-cabman)
# Then we create the actual cab file using a custom target
-# Please do not change this into custom command + custom target. This breaks reactos.cab dependencies on modules
-# and you can't do something like "make gdi32/fast reactos_cab/fast bootcd/fast"
-add_custom_target(reactos_cab
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/reactos.cab
COMMAND native-cabman -C ${CMAKE_CURRENT_BINARY_DIR}/reactos.dff -RC ${CMAKE_CURRENT_BINARY_DIR}/reactos.inf -L ${CMAKE_CURRENT_BINARY_DIR} -N -P ${REACTOS_SOURCE_DIR}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/reactos.inf native-cabman)
-add_cd_file(TARGET reactos_cab FILE ${CMAKE_CURRENT_BINARY_DIR}/reactos.cab ${CMAKE_CURRENT_BINARY_DIR}/reactos.inf DESTINATION reactos NO_CAB FOR bootcd regtest)
+add_custom_target(reactos_cab DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/reactos.cab)
+
+add_cd_file(
+ TARGET reactos_cab
+ FILE ${CMAKE_CURRENT_BINARY_DIR}/reactos.cab ${CMAKE_CURRENT_BINARY_DIR}/reactos.inf
+ DESTINATION reactos
+ NO_CAB FOR bootcd regtest)
Modified: trunk/reactos/cmake/CMakeMacros.cmake
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/cmake/CMakeMacros.cmake?re…
==============================================================================
--- trunk/reactos/cmake/CMakeMacros.cmake [iso-8859-1] (original)
+++ trunk/reactos/cmake/CMakeMacros.cmake [iso-8859-1] Thu Aug 7 18:20:46 2014
@@ -318,6 +318,12 @@
if(_CD_TARGET)
#manage dependency
add_dependencies(reactos_cab ${_CD_TARGET})
+ # add this so that the combination make target/fast reactos_cab/fast bootcd/fast properly detects that reactos.cab must be rebuilt
+ if (CMAKE_BUILD_TOOL STREQUAL "make")
+ add_custom_command(TARGET ${_CD_TARGET}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E touch ${REACTOS_BINARY_DIR}/boot/bootdata/packages/reactos.dff)
+ endif()
endif()
endif()
endif() #end bootcd