致命的 Python 错误:无法获取随机数来初始化 Python

Fatal Python error: failed to get random numbers to initialize Python

本文关键字:Python 取随机数 初始化 错误      更新时间:2023-10-16

Fatal Python 错误:无法获取随机数来初始化 Python

环境窗口 10, VSC 15

使用 CreateProcessA winapi 并传递 lpenvironment 变量来运行带有脚本的 python。 当 LPENVIRONMENT 传递 NULL 时,它工作正常。 如果我设置环境变量 PATH 和 PYTHONPATH = "paths",并传递该 LPSTR(env.c_Str(((,它会在运行时抛出上述错误。 python版本是3.5.6

有什么帮助吗?


更多细节。

  1. 我使用 CreateProcessA WINAPI 运行子进程 python.exe"C:\Program Files\endpoint\Python_ML\mlprocessor_server.py"。
  2. 我想使用两个环境变量"PYTHONPATH"和"PATH"运行子进程。 PYTHONPATH="C:\Program Files\endpoint\Python";"C:\Program Files\endpoint\Python\Scripts";"C:\Program Files\endpoint\Python\include";"C:\Program Files\endpoint\Python\Lib";"C:\Program Files\endpoint\Python\libs";"C:\Program Files\endpoint\Python\Lib\site-packages";"C:\程序文件\端点\Python_ML" PATH="C:\Program Files\endpoint\Python";"C:\Program Files\endpoint\Python\Lib";"C:\Program Files\endpoint\Python\Scripts";"C:\Program Files\endpoint\Python\libs">

由于某种原因,CreateProcessA 中的第 7 个参数失败,如果 python.exe为空,则成功运行,否则它会打印"致命的 Python 错误:无法获取随机数来初始化 Python"。

我设置参数的方式如下...

std::string Base = Configuration::getBasePath((;

std::string environPython = Base;
environPython.append("\Python;");
environPython.append(Base);
environPython.append("\Python\Scripts;");
environPython.append(Base);
environPython.append("\Python\include;");
environPython.append(Base);
environPython.append("\Python\Lib;");
environPython.append(Base);
environPython.append("\Python\libs;");
environPython.append(Base);
environPython.append("\Python\Lib\site-packages;");
environPython.append(Base);
environPython.append("\Python\_ML;");
environPython.push_back('');

std::string environPath = Base;
environPath.append("\Python;");
environPath.append(Base);
environPath.append("\Python\Lib;");
environPath.append(Base);
environPath.append("\Python\Scripts;");
environPath.append(Base);
environPath.append("\Python\libs;");
environPath.push_back('');
std::string cmd = Base;
cmd.append("\Python\python.exe");
std::string params = """;
params.append(cmd);
params.append("" "");
params.append(Base);
params.append("\Python\_ML\mlprocessor_server.py"");

std::map env = { { "PYTHONPATH", environPython.data(( }, { "PATH", environPath.data(( }};

// example for generating block of strings
std::vector<char> envBlock;
std::for_each(env.begin(), env.end(),
    [&envBlock](const std::pair<std::string, std::string> & p) {
    std::copy(p.first.begin(), p.first.end(), std::back_inserter(envBlock));
    envBlock.push_back('=');
    std::copy(p.second.begin(), p.second.end(),   std::back_inserter(envBlock));
    envBlock.push_back('');
}
);
envBlock.push_back('');
// feed this into ::CreateProcess()
LPVOID lpEnvironment = (LPVOID)envBlock.data();
bool result = CreateProcessA(cmd.c_str(), (LPSTR)params.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, lpEnvironment, NULL, &info, &pi);

结果总是正确的,python.exe没有显示在任务管理器中,并给出致命的Python错误:无法获取随机数来初始化Python。

如果 lpEnvironment 为 NULL,python.exe 将显示在任务管理器中。

您传递给CreateProcessA的环境必须包含SYSTEMROOT,否则在初始化期间在 python 内部调用 Win32 API 调用CryptAcquireContext将失败。

当以 lpEnvironment 形式传入 NULL 时,新进程将继承已定义SYSTEMROOT调用进程的环境。

为了跟进一个例子,如何在现实世界中的纯Python软件中非常容易地触发它,有时Python打开自己的实例来执行某些任务很有用,其中子任务需要设置特定的PYTHONPATH。 通常,这可以在不那么挑剔的平台(即不是Windows(上懒惰地完成,如下所示:

import sys
from subprocess import Popen
p = Popen([sys.executable, '-c', 'print("hello world")'], env={
    'PYTHONPATH': '',  # set it to somewhere
})

但是,在 Windows 上这样做将导致以下令人困惑的失败:

Python 3.8.10 (...) [MSC v.1928 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> from subprocess import Popen
>>> p = Popen([sys.executable, '-c', 'print("hello world")'], env={
...     'PYTHONPATH': ''
... })
Fatal Python error: _Py_HashRandomization_Init: failed to get random numbers to initialize Python
Python runtime state: preinitialized

解决方法很明显:克隆os.environ以确保SYSTEMROOT到位,从而避免@Joe Savage的答案指出的问题,例如:

>>> import os
>>> env = os.environ.copy()
>>> env['PYTHONPATH'] = ''
>>> p = Popen([sys.executable, '-c', 'print("hello world")'], env=env)
hello world

需要此类修复的实际示例:

  • Glean SDK
  • LocalStack 的 aws 包装器
  • 完善
  • setuptools(仅在测试中,但可以作为一个例子,说明几乎任何人都可以轻易犯这个错误(。