EDITED2:Почему UnicodeDecodeError скрыт до добавления time.sleep (1)?
В EDITED ниже код, f_out.write(bytearray(out or ""))
следует заменить (оба раза) с:
f_out.write(bytearray((out or ""), 'utf8'))
# ПЕРЕД удалением universal_newlines=True
ИЛИ
f_out.write(out or "")
# после удаления universal_newlines=True
msw, tdelaney и j- f-sebastian - Большое вам спасибо за вашу помощь!
EDITED - В результате, вот сокращенная версия моего сценария, который сейчас ПОСЛЕДОВАТЕЛЬНО ТРИГГЕРЫ 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 ""))
EDITED - А теперь (с выше сценарий, минус universal_newlines=True
), то 1.2MB, 18978 линия STDERR, которые выказывают генерироваться правильно захвачена:
Error: PDF file is damaged - attempting to reconstruct xref table... Error: Kid object (page 1) is not an indirect reference (integer)
....................................................................
(Evince.exe:6800): GLib-GObject-CRITICAL **: g_object_unref: assertion `G_IS_OBJECT (object)' failed
Для некоторых 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 (который был occcuring).]
Однако, поскольку исключение происходит только тогда, когда есть какой-то «Другой код» после моего proc.kill()
, было бы кажется, что что-то еще, по-видимому, не совсем корректно с моим кодом. Итак, я временно оставил universal_newlines=True
в моем коде и опустил мой «Другой код», чтобы лучше определить, что это такое.
Я попытался изменить buf_size
и попытался flush()
ИНГ как stdout
и stderr, but none of that seems to make any difference.
Я видел в Python docs, что:
Popen objects are supported as context managers via the with statement: on exit, standard file descriptors are closed, and the process is waited for.
поэтому я попытался заменить мой 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
, что я должен делать?
Заранее спасибо.
Когда вы нажимаете таймаут, потоки фона все еще читают 'stdout' и' stderr'. Вы не увидите ошибку до тех пор, пока эти потоки не прекратятся. В соответствии с документами _ «Детский процесс не убивается, если истекает время ожидания, поэтому для правильной очистки корректное приложение должно убить дочерний процесс и завершить связь:« _ так просто добавьте 'proc.communicate() 'после убийства. Я думаю, что ваш родитель вышел, прежде чем данные были закачаны в stderr. – tdelaney
Есть ли причина не использовать 'stdin = subprocess.DEVNULL, stdout = subprocess.DEVNULL, stderr = subprocess.STDOUT' здесь? – jfs
** tdelaney: ** Спасибо. \t Я пропустил это дополнение к 3.3 документам (где был добавлен тайм-аут). Извини за это. \t Но теперь я еще более озадачен. \t Теперь я добавил эту добавку в свой сценарий, и если я запустил измененный скрипт [без time.sleep()] только один раз, он не заметит разницы. \t Но если я запустил скрипт 2-го (или 3-го или ...) времени (без перезагрузки), то он получит UnicodeDecodeError со второго раза. – Russell