使用sqlite进行子进程,编码和日志记录的问题

时间:2013-04-22 04:54:51

标签: python python-2.7 sqlite subprocess fuzzing

我已经搜索了这个问题的答案了很长一段时间,我认为很多都与我对子进程模块的工作方式不熟悉有关。如果有人有兴趣,这是一个模糊测试程序。另外,我应该提到这一切都是在Linux中完成的(我认为这是相关的)我有一些像这样的代码:

# open and run a process and log get return code and stderr information
process = subprocess.Popen([app, file_name], stdout=subprocess.PIPE,
                                             stderr=subprocess.PIPE)
return_code = process.wait()
err_msg = process.communicate()[1]

# insert results into an sqlite database log
log_cur.execute('''INSERT INTO log (return_code, error_msg) 
                   VALUES (?,?)''', [unicode(return_code), unicode(error_msg)])
log_db.commit()

在100次中有99次可以正常工作但偶尔会出现类似于以下错误:

UnicodeDecodeError:'utf8'编解码器无法解码位置43的字节0xce:无效的连续字节

编辑:完整跟踪

Traceback (most recent call last):
  File "openscadfuzzer.py", line 72, in <module>
    VALUES (?,?)''', [crashed, err_msg.decode('utf-8')])
  File "/home/username/workspace/GeneralPythonEnv/openscadfuzzer/lib/python2.7/encodings/utf_8.py",    line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xdb in position 881: invalid continuation byte

这是子进程的问题,我使用它运行的应用程序还是我的代码?任何指针都会受到赞赏(尤其是当它与子进程stdout和stderr的正确用法有关时)。

2 个答案:

答案 0 :(得分:2)

我的猜测是问题在于这个问题:

unicode(error_msg)

error_msg的类型是什么?我相当确定默认情况下子进程API将返回子程序输出的原始字节,对unicode的调用尝试通过假设某些编码将字节转换为字符(代码点)(在本例中为utf8) )。

我的猜测是字节无效utf8,但是有效的latin1。您可以指定在字节和字符之间转换的编解码器:

error_msg.decode('latin1')

这是一个有希望展示问题和解决方法的示例:

>>> b'h\xcello'.decode('utf8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.2/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xce in position 1: invalid continuation byte

>>> b'h\xcello'.decode('latin1')
'hÎllo'

更好的解决方案可能是让您的子进程输出utf8,但这取决于您的数据库能够存储的数据。

答案 1 :(得分:1)

你可以在这里找到非常好的子流程教程http://pymotw.com/2/subprocess/及其官方文档:http://docs.python.org/2/library/subprocess.html,但是根据你获得的错误的格​​式,似乎不是你的代码,而是你的获取错误的应用程序,而您只是看到它,因为您正在收集输出。要确认这一点,您可以使用简单的bash循环在代码外部运行您的应用程序,以查看是否可以再次捕获错误并在代码中检查应用程序的退出代码 - 当您看到错误时如果应用程序正确提供退出代码,它应该与0不同。