[英]Why OpenProcess Gives me a non-NULL HANDLE for a non existing pid?
I reduced the code as much as I could to keep it sscce What this code does: 我尽可能地减少代码以保持代码sscce这段代码的作用:
CreateProcess
CreateProcess
启动Windows记事本 TerminateProcess
on the Handle we got from CreateProcess
. CreateProcess
获得的句柄中的TerminateProcess
杀死记事本。 TerminateProcess
is async TerminateProcess
是异步的 OpenProcess
on the dead pid OpenProcess
You can easily check (before OpenProcess) in debug that the given Pid is nowhere to be found in either the task manager or processExplorer. 您可以在调试中轻松检查(在OpenProcess之前),在任务管理器或processExplorer中找不到给定的Pid。 But no other windows API functions seems to accept this Pid
但没有其他Windows API函数似乎接受这个Pid
#include "stdafx.h"
#include <windows.h>
#include "Psapi.h"
#include <TlHelp32.h>
#include <iostream>
#include <cassert>
typedef unsigned long PID;
typedef const std::string& P_PATH;
// Launch an executable given by a path and set a few infomatives stuffs passed as ref parameters
bool launch_process(P_PATH path, STARTUPINFO& info, PROCESS_INFORMATION& processInfo, HANDLE& hProcess, PID& pid)
{
setlocale(LC_ALL, "en_US.utf8");
std::wstring widestr = std::wstring(path.begin(), path.end());
const wchar_t* widecstr = widestr.c_str();
LPTSTR szCmdline = _tcsdup(widecstr);
if (CreateProcess(szCmdline, NULL, NULL, NULL, false, NULL, NULL, NULL, &info, &processInfo))
{
hProcess = processInfo.hProcess;
pid = processInfo.dwProcessId;
return true;
}
return false;
}
int main(int argc, char* argv[])
{
// Setup
// -----
bool OK = false;
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
HANDLE hProcess;
PID pid = 0;
// launch notepad
// --------------
OK = launch_process("C:\\WINDOWS\\System32\\notepad.exe", info, processInfo, hProcess, pid);
assert(OK);
// wait a bit
// ----------
system("PAUSE");
SetLastError(0);
// get Handle on notepad
// ---------------------
hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, false, static_cast<DWORD>(pid));
std::cout << "Error: " << GetLastError() << std::endl;
// Kill notepad
// ------------
UINT exitCode = 0;
DWORD dwWaitResult = 0;
SetLastError(0);
OK = TerminateProcess(hProcess, exitCode);
std::cout << "Error: " << GetLastError() << std::endl;
// ensure everything went well ( we need to wait because TerminateProcess is asynchronous )
if (!OK || (dwWaitResult != WaitForSingleObject(hProcess, INFINITE)))
return -1;
// Cleanup
CloseHandle(hProcess);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
hProcess = nullptr;
processInfo.hProcess = nullptr;
// Ya know what let's reopen the pid I just killed
// ( you can see that notepad was started then killed, you can check the pid does not exist in either the task manager or processExplorer )
SetLastError(0);
hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, false, static_cast<DWORD>(pid));
std::cout << "Error: " << GetLastError() << std::endl;
// Yeah I can speak to the deads!
if (hProcess != nullptr)
{
LPWSTR szProcessName = L"";
GetModuleFileNameEx(hProcess, NULL, szProcessName, sizeof szProcessName);
char c_szText[MAX_PATH];
wcstombs(c_szText, szProcessName, wcslen(szProcessName) + 1);
// But the deads have no names
std::cout << "Error: " << GetLastError() << std::endl;
std::cout << "Zombie Name: " << c_szText << std::endl;
}
return 0;
}
It's not appearing in the list of processes in Task Manager because it has terminated. 它没有出现在任务管理器的进程列表中,因为它已终止。 Task Manager doesn't show zombies (this behaviour differs from eg Linux
ps -Af f
which does show zombies). 任务管理器不显示僵尸(此行为不同于例如Linux
ps -Af f
确实显示僵尸)。
It's still there and accessible to OpenProcess
because the process object has not been destroyed, ie it is in the zombie state. 它仍然存在并且可以被
OpenProcess
访问,因为进程对象尚未被破坏,即它处于僵尸状态。 This will be because another process has an open handle to it. 这将是因为另一个进程有一个开放的句柄。 For example,
例如,
Morals: 德:
Don't expect the process object to be destroyed as soon as you close your handle, because yours is not the only handle. 一旦关闭句柄,不要指望过程对象被销毁,因为你的句柄不是唯一的句柄。
Zombie state is a perfectly legitimate state for a process to be in. All processes will be in the zombie state if they have terminated, and someone is waiting to read their exit code with GetExitCodeProcess
, or have any other interest in the state of the process. 僵尸状态对于进程来说是完全合法的状态。如果它们已经终止,所有进程将处于僵尸状态,并且有人正在等待使用
GetExitCodeProcess
读取其退出代码,或者对进程状态有任何其他兴趣。 Typically once the exit code has been read, interest in the process wanes, handles are closed, and finally the process will be destroyed. 通常,一旦读取了退出代码,对流程的兴趣就会消失,句柄会被关闭,最后流程将被销毁。
The PID can be reused once the process is destroyed. 一旦过程被破坏,PID就可以重复使用。 (Conversely, the PID cannot be reused until all handles are closed).
(相反,在关闭所有句柄之前,不能重复使用PID)。 In Windows, the kernel prefers low numbered PIDs and will reuse them quite quickly.
在Windows中,内核更喜欢低编号的PID,并且可以非常快速地重用它们。 This behaviour differs from Linux which prefers incrementing PIDs and won't reuse them until the maximum value is reached.
此行为与Linux不同,后者更喜欢递增PID,并且在达到最大值之前不会重复使用它们。
If you want the handle to the process, don't close it. 如果您想要进程的句柄,请不要关闭它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.