Last active
January 4, 2017 22:52
-
-
Save rprichard/37bfd1dd6a2ef91ba7af49efbe0461ed to your computer and use it in GitHub Desktop.
Rust output collection bug
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <assert.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <vector> | |
volatile LONG counter = 0; | |
static DWORD spew(void*) { | |
OVERLAPPED over = {}; | |
const HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); | |
assert(event != NULL); | |
const DWORD kBufSize = 1024 * 32; | |
std::vector<void*> buffers; | |
for (int i = 0; i < 100; ++i) { | |
void *buf = VirtualAlloc(NULL, kBufSize, MEM_COMMIT, PAGE_READWRITE); | |
assert(buf != NULL); | |
memset(buf, 'A', kBufSize); | |
buffers.push_back(buf); | |
} | |
while (!buffers.empty()) { | |
void *const buf = buffers.back(); | |
buffers.pop_back(); | |
DWORD actual = 0; | |
#if 1 | |
BOOL ret = WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), | |
buf, kBufSize, &actual, NULL); | |
#else | |
over = OVERLAPPED {}; | |
over.hEvent = event; | |
BOOL ret = WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), | |
buf, kBufSize, &actual, &over); | |
if (!ret && GetLastError() == ERROR_IO_PENDING) { | |
ret = GetOverlappedResult(GetStdHandle(STD_OUTPUT_HANDLE), | |
&over, &actual, TRUE); | |
} | |
#endif | |
assert(ret && "WriteFile failed"); | |
//fprintf(stderr, "child: WriteFile reported %u bytes written\n", actual); | |
InterlockedExchangeAdd(&counter, actual); | |
const BOOL freeRet = VirtualFree(buf, 0, MEM_RELEASE); | |
assert(freeRet); | |
} | |
return 0; | |
} | |
static HANDLE create_thread() { | |
HANDLE h = CreateThread(NULL, 0, spew, NULL, 0, NULL); | |
assert(h != NULL); | |
return h; | |
} | |
int main() { | |
std::vector<HANDLE> handles; | |
for (int i = 0; i < 20; ++i) { | |
handles.push_back(create_thread()); | |
} | |
for (HANDLE h : handles) { | |
WaitForSingleObject(h, INFINITE); | |
} | |
fprintf(stderr, "child: WriteFile reported %u bytes written total\n", counter); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::process::{Command, Stdio}; | |
fn main() { | |
let c = Command::new(".\\child.exe") | |
// .stdout(Stdio::null()) | |
// .stdout(Stdio::inherit()) | |
.stderr(Stdio::inherit()) | |
.output() | |
.expect("failed to execute child"); | |
let data = c.stdout; | |
println!("parent: child exited with: {}", c.status); | |
println!("parent: child wrote {} bytes, expected {}", | |
data.len(), 1024 * 32 * 100 * 20); | |
for b in data { | |
if b != b'A' { | |
println!("parent: found wrong byte: {}", b); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
With normal non-overlapped I/O in the child, we see this: | |
C:\rprichard\mess\iotest>parent | |
child: WriteFile reported 37715968 bytes written total | |
parent: child exited with: exit code: 0 | |
parent: child wrote 65372160 bytes, expected 65536000 | |
C:\rprichard\mess\iotest>parent | |
child: WriteFile reported 35848192 bytes written total | |
parent: child exited with: exit code: 0 | |
parent: child wrote 65110016 bytes, expected 65536000 | |
C:\rprichard\mess\iotest>parent | |
child: WriteFile reported 34766848 bytes written total | |
parent: child exited with: exit code: 0 | |
parent: child wrote 65503232 bytes, expected 65536000 | |
C:\rprichard\mess\iotest>parent | |
child: WriteFile reported 35454976 bytes written total | |
parent: child exited with: exit code: 0 | |
parent: child wrote 65372160 bytes, expected 65536000 | |
If the child instead uses overlapped I/O, we see: | |
C:\rprichard\mess\iotest>parent | |
child: WriteFile reported 65536000 bytes written total | |
parent: child exited with: exit code: 0 | |
parent: child wrote 65536000 bytes, expected 65536000 | |
C:\rprichard\mess\iotest>parent | |
child: WriteFile reported 65536000 bytes written total | |
parent: child exited with: exit code: 0 | |
parent: child wrote 65536000 bytes, expected 65536000 | |
C:\rprichard\mess\iotest>parent | |
child: WriteFile reported 65536000 bytes written total | |
parent: child exited with: exit code: 0 | |
parent: child wrote 65536000 bytes, expected 65536000 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment