https://bugs.winehq.org/show_bug.cgi?id=48891
--- Comment #16 from Damjan Jovanovic damjan.jov@gmail.com --- Cygwin's "strace" command turned out to be very useful: strace -o ../strace.txt command
What we see, comparing dofork() in code with logging output, is that this line: syscall_printf ("%R = fork()", res); logs: ... forkme 1023 ... dofork(): 0 = fork(); ... forkme 1024 ... dofork(): 0 = fork();
So both the parent and the child think they are the child. Interestingly the parent can't write to the terminal, but if you make a sample application in which the child from fork() creates a file with the return value from GetCurrentProcessId() in the filename, 2 files get created.
fork() calls dofork(), whose res comes from:
---snip--- if (!ischild) res = grouped.parent (stackp); else { res = grouped.child (stackp); in_forkee = false; ischild = true; /* might have been reset by fork mem copy */ } ---snip---
It's grouped.parent() that return 0 for the parent, and we know ischild is correct because strace logging from grouped.parent() happens and happens only once.
grouped.parent() is the frok::parent() method, which always return -1 on failure. It returned 0, so it doesn't think it failed. The success return value comes from child_pid, which is set by:
---snip--- child_pid = cygwin_pid (pi.dwProcessId); ---snip---
pi.dwProcessId is definitely valid. What does cygwin_pid() do, that results in it returning 0?
---snip--- /* Convert Windows WINPID into Cygwin PID. Utilize the "winpid.WINPID" symlinks created for each process. The symlink contains the Cygwin PID as target. Return 0 if no "winpid.WINPID" symlink exists for this WINPID. */ pid_t cygwin_pid (DWORD dwProcessId) { WCHAR sym_name[24]; WCHAR pid_name[12]; UNICODE_STRING sym_str; UNICODE_STRING pid_str; OBJECT_ATTRIBUTES attr; HANDLE sym_hdl; NTSTATUS status;
__small_swprintf (sym_name, L"winpid.%u", dwProcessId); RtlInitUnicodeString (&sym_str, sym_name); InitializeObjectAttributes (&attr, &sym_str, OBJ_CASE_INSENSITIVE, get_shared_parent_dir (), NULL); status = NtOpenSymbolicLinkObject (&sym_hdl, SYMBOLIC_LINK_QUERY, &attr); if (!NT_SUCCESS (status)) return 0; RtlInitEmptyUnicodeString (&pid_str, pid_name, sizeof pid_name - sizeof (WCHAR)); status = NtQuerySymbolicLinkObject (sym_hdl, &pid_str, NULL); NtClose (sym_hdl); if (!NT_SUCCESS (status)) { system_printf ("NtOpenSymbolicLinkObject: %y, PID %u, ret 0", status, dwProcessId); return 0; } pid_str.Buffer[pid_str.Length / sizeof (WCHAR)] = L'\0'; pid_t ret = (pid_t) wcstoul (pid_str.Buffer, NULL, 10); return ret; } ---snip---
There are 3 paths out of the function. The middle one would log an NtOpenSymbolicLinkObject failure (it's a typo, it's actually NtQuerySymbolicLinkObject fails), but that's not visible in the strace. Therefore it's the first or the last return that returned 0.
So one of the following took place: 1. NtOpenSymbolicLinkObject() failed, returning 0 without logging anything. 2. NtQuerySymbolicLinkObject() succeeded but returned "0" which was parsed to 0 by wcstoul() and return to the caller, either due to a Wine bug in it, or another Wine bug when the symbolic link was created/stored.