EDITED2:
在下面的已修改代码中,f_out.write(bytearray(out or ""))
应更换(两次):
f_out.write(bytearray((out or ""), 'utf8'))
#删除universal_newlines=True
之前
OR
f_out.write(out or "")
#AFTER删除universal_newlines=True
msw,tdelaney和j-f-sebastian - 非常感谢你的帮助!
已编辑 - 因此,这是我的脚本的编辑版本,它现在一直触发UnicodeDecodeError:
#!python3 # Run this script with Python 3.x (in Windows, assuming pylauncher is installed).
import subprocess
import sys
sys.stderr = sys.stdout = open('std.outerr', 'w')
# Redirected stdout/stderr so that they can be seen even when script is not run from command line.
child = subprocess.Popen([r"Evince\bin\Evince.exe", "fuzzed.pdf"], bufsize=0,
stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, universal_newlines=True)
# `universal_newlines=True` TEMPORARILY left in to show that UnicodeDecodeError is triggered.
# `universal_newlines=True` WILL be removed from FINAL script.
try:
(out, _) = child.communicate(timeout=5)
# 1 second wasn't long enough for UnicodeDecodeError to consistently be triggered.
# Since subprocess's stderr was redirected to its stdout, 2nd element of tuple will be `None`.
except subprocess.TimeoutExpired:
child.kill()
(out, _) = child.communicate() # Try a 2nd time, without timeout.
with open('subprocess.out', 'wb') as f_out:
f_out.write(bytearray(out or "")) # Treat `None` as an empty string).
else:
print("\nERROR: A crash occurred before the timeout expired!\n")
with open('subprocess.out', 'wb') as f_out:
f_out.write(bytearray(out or ""))
已编辑 - 现在(使用上面的脚本,减去universal_newlines=True
),正确捕获了Evince生成的1.2MB,18,978行stderr:
错误:PDF文件已损坏 - 尝试重建外部参照表... 错误:Kid对象(第1页)不是间接引用(整数)
............................................... .....................
(Evince.exe:6800):GLib-GObject-CRITICAL **:g_object_unref: 断言“G_IS_OBJECT(对象)”失败
对于我正在做的一些fuzzing,subprocess.Popen()
调用以下内容:
import subprocess
proc = subprocess.Popen([r"Evince\bin\Evince.exe", "fuzzed.pdf"],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True)
try:
proc.communicate(timeout=1) # Works the same with timeout=60 seconds.
except subprocess.TimeoutExpired: # This exception is new to Python 3.3.
proc.kill()
# Other code here.
else:
print("\nERROR: A crash occurred before the timeout expired!\n")
给了我一个UnicodeDecodeError
:
Exception in thread Thread-1: Traceback (most recent call last):
File "p:\python35-64\lib\threading.py", line 914, in _bootstrap_inner self.run()
File "p:\python35-64\lib\threading.py", line 862, in run self._target(*self._args, **self._kwargs)
File "p:\python35-64\lib\subprocess.py", line 1279, in _readerthread buffer.append(fh.read())
File "p:\python35-64\lib\encodings\cp1252.py", line 23, in decode return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 291289: character maps to [undefined]
即使我将“其他代码”简化为time.sleep(1)
这样简单的事情,也会发生这种情况。然而,当我删除“其他代码”时,没有发生异常。
我现在意识到发生异常是因为我在universal_newlines=True
电话上不必要地指定了Popen()
。 [那是不与写入stderr
的字节兼容,其值大于127(这是一种发作)。]
但是,因为只有在proc.kill()
之后有一些“其他代码”时才会发生异常,所以看起来其他东西对我的代码来说可能不太合适。所以,我暂时在我的代码中留下了universal_newlines=True
,并省略了我的“其他代码”,以便更好地确定它是什么。
我尝试更改buf_size
并尝试flush()
同时stdout
和stderr, but none of that seems to make any difference.
我在Python docs中看到:
通过with语句支持Popen对象作为上下文管理器:在退出时, 标准文件描述符已关闭,等待该过程。
所以我尝试用{/ p>替换我的Popen()
来电
with subprocess.Popen(..., universal_newlines=True) as proc:
并生成了UnicodeDecodeError
,即使没有“其他代码”也存在。所以,这是“修复”我的代码的一种方法,但是(由于我还需要做一些额外的事情),我最好使用第三方PyPI
psutil模块。而且,令人遗憾的是,目前不支持上下文管理器。所以,如果可能的话,我想在没有with ... as
的情况下对此进行编码。
我可以在代码中更改其他内容(universal_newlines
的值除外)以“修复”它吗?
基于文档所说的“'Popen'对象作为上下文管理器的支持”,我尝试添加:
if proc.stdout:
proc.stdout.close()
if proc.stderr:
proc.stderr.close()
if proc.stdin:
proc.stdin.close()
和/或proc.wait()
就在proc.kill()
之前,但是proc.kill
从未到达。
with ... as
我应该做什么?
提前致谢。
答案 0 :(得分:2)
输出可以被缓冲,因此即使在子进程已经死亡之后也可以解码文本。如果没有time.sleep(1)
,那么父进程可能会在解码遇到错误之前退出(.communicate()
启动的I / O阅读器守护程序线程被终止,然后父进程退出)。