SetDIBitsToDevice fails when using large page - winapi

I have just discovered that SetDIBitsToDevice function fails (returns 0) when I'm trying to display an image which data was allocated via large page using this call:
VirtualAlloc(NULL, imageSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE)
Just after the failure, GetLastError returns 0, which means "no error". Note that removing MEM_LARGE_PAGES flag makes the code work correctly.
Is it a bug or a correct behavior? Documentation doesn't say anything about it.

Related

Are There any Cases When ReadProcessMemory Would Fail?

I am currently writing a program that utilizes ReadProcessMemory to save a block of memory to a file as text. Within the program, the user will designate the base address and size of the memory block. Input validations are done before the call to ReadProcessMemory to ensure that there are no parameter-related errors. Memory bounds are also restricted to pre-allocated regions to ensure that the user does not attempt to read non-allocated memory. Due to the fact that all allocated memory is readable, I believe that there should not be a need to perform general post-call error checking for ReadProcessMemory. Am I correct in stating this? Assuming all parameters are valid, of course. I have used ReadProcessMemory many times before in the past with proper error checking and found it to be unnecessary because the function always succeeded.
Examples would also be appreciated.
Thanks in advance!
I assume that all parameters are valid:
The handle have PROCESS_VM_READ access to the process;
lpBaseAddress is valid;
nSize <= the size of lpBuffer.
...
I think the only factor that will cause ReadProcessMemory failure is Memory Protection attributes.
As #IInspectable: "memory is allocated doesn't imply that you can read it".
After testing, I found that the following situations will get failed.
PAGE_NOACCESS
https://learn.microsoft.com/en-us/windows/win32/memory/reserving-and-committing-memory
lpvBase = VirtualAlloc(
NULL, // System selects address
PAGELIMIT*dwPageSize, // Size of allocation
MEM_RESERVE, // Allocate reserved pages
PAGE_NOACCESS); // Protection = no access
PAGE_GUARD | ...
https://learn.microsoft.com/en-us/windows/win32/memory/creating-guard-pages
lpvAddr = VirtualAlloc(NULL, dwPageSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READONLY | PAGE_GUARD);
Or modified by VirtualProtectEx:
VirtualProtectEx(hProcess, lpAddress, dwSize, PAGE_NOACCESS, &old);
and
VirtualProtectEx(hProcess, lpAddress, dwSize, PAGE_GUARD | PAGE_READONLY, &old);
GetLastError will return 299(ERROR_PARTIAL_COPY)
Use VirtualQueryEx to retrieve the The access protection of the pages in the specified region

What causes WriteFile to return error 38 (ERROR_HANDLE_EOF)?

What would cause WriteFile to return error 38 (ERROR_HANDLE_EOF, Reached the end of the file)? The "file" in this case is a mailslot. The way my program works is I have a process (running as a Windows service) that creates multiple child processes. Each child opens a mailslot of the same name in order to send status information back to its parent. In my small scale testing this works fine, but I am seeing cases where when I have several processes
running (like 16) I am getting this error. The code below shows how I am opening and writing to the mailslot in the child process.
Is it perhaps because the parent is not reading the mailslot fast enough? Is there a way to increase capacity of a mailslot so that end of file never gets reached? I really don't see how a mailslot can get full anyway, as long
as there is disk space (which there is plenty of).
char gLocalSlotName[256]="\\\\.\\mailslot\\TMAgentSlot-ComputerName";
gAgentSlot = CreateFile(gLocalSlotName, GENERIC_WRITE, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);
fResult = WriteFile(gAgentSlot, (char *)&ProcStat, sizeof(PROCSTAT), &cbWritten, (LPOVERLAPPED) NULL);
if (!fResult) {
derr = GetLastError();
printf("WriteFile error=%d", derr);
}
WriteFile is thin shell over NtWriteFile. if NtWriteFile return error NTSTATUS - it will be converted to its equivalent win32 error code (via RtlNtStatusToDosError) and WriteFile return false. win32 error code you can got via GetLastError(). however original NTSTATUS you can got via RtlGetLastNtStatus() exported by ntdll.dll api. problem with win32 errors codes - some time several different NTSTATUS values converted to the same win32 error.
in case ERROR_HANDLE_EOF - 2 different NTSTATUS converted to it:
STATUS_END_OF_FILE and STATUS_FILE_FORCED_CLOSED. the STATUS_END_OF_FILE never (look like) returned by msfs.sys (driver which handle mailslots). from another side - STATUS_FILE_FORCED_CLOSED (The specified file has been closed by another process.) can be returned when you write data to mailslot (by msfs.MsCommonWrite) if server end of the mailslot (end which you create via CreateMailslot call) already closed.
formally when last server handle was closed - all connecting clients marked as in closing state (inside MsFsdCleanup) and then if you call WriteFile for such client - the STATUS_FILE_FORCED_CLOSED is returned.
so -
What causes WriteFile to return error 38 (ERROR_HANDLE_EOF)?
the server process by some reason close self mailslot handle. you need search in this direction - when and why you close mailsot handle in parent process

Reading pipe asynchronously using ReadFile

I think I need some clarification on how to read from a named pipe and have it return immediately, data or not. What I am seeing is ReadFile fails, as expected, but GetLastError returns either ERROR_IO_PENDING or ERROR_PIPE_NOT_CONNECTED, and it does this until my surrounding code times out. I get these errors EVEN THOUGH THE DATA HAS IN FACT ARRIVED. I know this by checking my read buffer and seeing what I expect. And the pipe keeps working. I suspect I am not using the overlapped structure correctly, I'm just setting all fields to zero. My code looks like this:
gPipe = CreateFile(gPipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
pMode = PIPE_READMODE_MESSAGE;
bret = SetNamedPipeHandleState(gPipe, &pMode, NULL, NULL);
OVERLAPPED ol;
memset(&ol, 0, sizeof(OVERLAPPED));
// the following inside a loop that times out after a period
bret = ReadFile(gPipe, &tmostat, sizeof(TMO64STAT), NULL, &ol);
if (bret) break;
err = GetLastError();
// seeing err == ERROR_IO_PENDING or ERROR_PIPE_NOT_CONNECTED
So I can do what I want by ignoring the errors and checking for arrived data, but it troubles me. Any idea why I am getting this behavior?
Windows OVERLAPPED I/O doesn't work like the non-blocking flag on other OSes (For example on Linux, the closest equivalent is aio_*() API, not FIONBIO)
With OVERLAPPED I/O, the operation hasn't failed, it proceeds in the background. But you are never checking on it... you just try again. There's a queue of pending operations, you're always starting new ones, never checking on the old ones.
Fill in the hEvent field in the OVERLAPPED structure, and use it to detect when the operation completes. Then call GetOverlappedResult() to get the number of bytes actually transferred.
Another important note -- the OS owns the OVERLAPPED structure and the buffer until the operation completes, you must take care to make sure these stay valid and not deallocate them or use them for any other operation until you confirm that the first operation completed.
Note that there is an actual non-blocking mode for Win32 pipes, but Microsoft strongly recommends against using it:
The nonblocking-wait mode is supported for compatibility with Microsoft LAN Manager version 2.0. This mode should not be used to achieve overlapped input and output (I/O) with named pipes. Overlapped I/O should be used instead, because it enables time-consuming operations to run in the background after the function returns.
Named Pipe Type, Read, and Wait Modes

WriteFile Fails with error code 87 when writing to USB

I am trying to communicatate with a USB device on Windows 7. After I find the device using the vendor and product ID I open it with the following command
dev->device_handle = CreateFile( path, (GENERIC_WRITE | GENERIC_READ),
(FILE_SHARE_READ|FILE_SHARE_WRITE),
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
Then I do a write into the device using
res = WriteFile(dev->device_handle, buf, length, &bytes_written, &ol);
where length is 64.
My device can read and write 64 bytes of data in this interface and this has been tested on Linux and using another tool in windows (I dont have the source of the tool).
The WriteFile function gives me an error code of 87. which is invalid parameters.
Could anybody please point me out the mistake I am making.
P.S. I have already analysed the question
WriteFile returning error code 87
I have made some debug logs
--------------------------------------------------
Before write call
dev_handle:152
buf:2293463
length:65
bytes_written:0
overlap:0
--------------------------------------------------
--------------------------------------------------
After write call
dev_handle:152
buf:2293463
length:65
bytes_written:0
overlap:259
--------------------------------------------------
Last Error: 87
Well, there are 5 parameters:
dev->device_handle could be INVALID_HANDLE_VALUE if CreateFile failed.
buf should not be NULL
length cannot be checked, so it can't be the problem.
&bytes_written is rather pointless (use GetOverlappedResult).
&lo must contain a valid offset and event. Also, all other fields must be zeroed.
Lacking context, we can't fault any specific parameter. I'd check &bytes_written first because it's the most obvious suspect to me.

Windows drivers - shared memory from user mode->kernel mode

I'm messing around with some driver development and I'm having an issue getting some of my code to work. I'm not sure if it's a quirk with the API that I'm unaware of or what.
I have a user app that has created a named shared object under BaseNamedObjects with CreateFileMapping, MapViewOfFile, etc. I'm trying to read this shared object inside of my driver code using ZwOpenSection and ZwMapViewOfSection
The problem code is below:
char *sharedData = NULL;
SIZE_T vs = 256;
InitializeObjectAttributes(&myAttributes,&sectionName,OBJ_KERNEL_HANDLE,NULL,NULL);
ZwOpenSection(&sectionHandle,SECTION_MAP_READ,&myAttributes)
ZwMapViewOfSection(&sectionHandle, ZwGetCurrentProcess(), (PVOID *)sharedData, 0, 256,
NULL, &vs, ViewUnmap, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
The call to ZwOpenSection completes successfully and I get the object properly, but the second call fails. The status returned says it's an issue with the ninth parameter, but I've tried every combination I could think of with nothing to show for it, so I'm not sure if it's an issue with a different parameter causing the 9th to be "incorrect" or if I'm missing something else
Thanks.
Is the access permission with which the section was created the same as the one you have passed here?
MEM_COMMIT is not allowed in a direct call in this function. If you still want to commit and reserve pages, try calling the virtualalloc(), otherwise just pass NULL in the 8th parameter.

Resources