{"record":{"id":"c0a4eee8788abf51","repo":"dotnet/runtime","slug":"problem-reading-from-createdump-child-read-pipe-c0a4ee","errorCode":null,"errorMessage":"Problem reading from createdump child_read_pipe: %s (%d)\\n","messagePattern":"Problem reading from createdump child_read_pipe: (.+?) \\((.+?)\\)\\\\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/coreclr/pal/src/thread/process.cpp","lineNumber":1527,"sourceCode":"        }\n        return false;\n    }\n    else if (childpid == 0)\n    {\n        int callbackResult = 0;\n\n        close(parent_read_pipe);\n        close(parent_write_pipe);\n\n        // Wait for prctl(PR_SET_PTRACER, childpid) in parent\n        char buffer;\n        int bytesRead;\n        while((bytesRead = read(child_read_pipe, &buffer, 1)) < 0 && errno == EINTR);\n        close(child_read_pipe);\n\n        if (bytesRead != 1)\n        {\n            fprintf(stderr, \"Problem reading from createdump child_read_pipe: %s (%d)\\n\", strerror(errno), errno);\n            close(child_write_pipe);\n            exit(-1);\n        }\n\n        // Only dup the child's stderr if there is error buffer\n        if (errorMessageBuffer != nullptr)\n        {\n            dup2(child_write_pipe, STDERR_FILENO);\n        }\n        if (g_createdumpCallback != nullptr)\n        {\n            // Remove the signal handlers inherited from the runtime process\n            SEHCleanupSignals(true /* isChildProcess */);\n\n            // Call the statically linked createdump code\n            int argc = 0;\n            while (argv[argc] != nullptr && argc < MAX_ARGV_ENTRIES)\n            {","sourceCodeStart":1509,"sourceCodeEnd":1545,"githubUrl":"https://github.com/dotnet/runtime/blob/290d5ab72cc1102813fbc0406fb186ceadabc340/src/coreclr/pal/src/thread/process.cpp#L1509-L1545","documentation":"Emitted by the forked child in the CoreCLR PAL crash-dump path PROCLaunchCreateDump (process.cpp:1527). After fork the child closes the parent-side fds and blocks on read(child_read_pipe) waiting for the parent's single-byte prctl(PR_SET_PTRACER) signal; the read is retried only on EINTR. If bytesRead != 1 (read returned 0 = EOF or a hard error) the child prints this, closes child_write_pipe and exit(-1) BEFORE the g_createdumpCallback / execve branch is ever reached, so no dump is generated by either mechanism.","triggerScenarios":"DOTNET_DbgEnableMiniDump=1 (or a runtime-triggered dump) on the full CoreCLR runtime causes a fork; the child is waiting on child_read_pipe but the parent never wrote the 'S' byte because it died, was killed, or crashed inside the prctl(PR_SET_PTRACER) block (lines 1571-1577) before reaching the write() at line 1580. The child's read then returns EOF.","commonSituations":"Parent process killed by the OOM killer or a container runtime between fork and the signal write; parent took a second, more fatal signal (e.g. SIGSEGV in the signal handler itself) during prctl setup; pipe fds exhausted/closed prematurely; running under a debugger or tracer that interferes with PR_SET_PTRACER and the parent aborted; very tight memory/fd limits on the crash path.","solutions":["Enable verbose diagnostics and reproduce: set DOTNET_CreateDumpDiagnostics=1 DOTNET_CreateDumpVerboseDiagnostics=1 to capture what the parent did before it stopped writing.","Check for external kills during the crash: `dmesg -T | grep -i 'killed process'` (oom-killer) and container runtime OOM events; raise cgroup memory limits.","Raise the open-files limit (ulimit -n) so the crash path has the fds it needs for the two pipes.","If PR_SET_PTRACER setup is the culprit (hardened kernel/Yama ptrace_scope), set /proc/sys/kernel/yama/ptrace_scope to 0 or 1, or run as root, to let the parent complete the prctl step.","Fall back to kernel core dumps: unset DOTNET_DbgEnableMiniDump and configure /proc/sys/kernel/core_pattern, removing the dependency on the in-process fork handshake."],"exampleFix":"# before\n$ DOTNET_DbgEnableMiniDump=1 ./app\n# Problem reading from createdump child_read_pipe: Success (0)   # parent died (EOF)\n\n# after: confirm/relieve the cause of the parent dying\n$ dmesg -T | grep -i 'killed process'\n$ ulimit -n 65536\n$ DOTNET_DbgEnableMiniDump=1 DOTNET_CreateDumpVerboseDiagnostics=1 ./app","handlingStrategy":"validation","validationCode":"# Validate that the parent can complete the prctl handshake on this host before enabling dumps.\ncat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null | grep -Eq '^[01]$' || echo \"WARN: ptrace_scope may block PR_SET_PTRACER\"\n[ \"$(ulimit -n)\" -ge 1024 ] || ulimit -n 65536\n# Ensure the process won't be OOM-killed during crash handling:\ngrep MemAvailable /proc/meminfo\nDOTNET_DbgEnableMiniDump=1 DOTNET_CreateDumpVerboseDiagnostics=1 \"$@\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["On hardened kernels, set /proc/sys/kernel/yama/ptrace_scope to 0 or 1 so PR_SET_PTRACER succeeds and the parent reaches the signal write.","Give the crashing process enough memory/fds to survive through the fork+prctl sequence (cgroup limits, ulimit -n).","Run the workload as PID 1 (or without an aggressive reaper) so the parent is not externally killed mid-handshake.","Enable DOTNET_CreateDumpDiagnostics=1 to capture the parent's behavior when the child reports a failed read.","Keep kernel core_pattern as a fallback dump source independent of the parent/child pipe."],"tags":["dotnet","coreclr","pal","createdump","crash-dump","pipe","diagnostics","linux"],"analyzedSha":"290d5ab72cc1102813fbc0406fb186ceadabc340","analyzedAt":"2026-08-06T19:57:01.276Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}