2014-03-07 8 views
11

Ich habe Probleme mit dem Subprozess-Modul, um die Ausgabe von abgestürzten Programmen zu erhalten. Ich verwende python2.7 und subprocess ein Programm mit seltsamen Argumente aufrufen, um einige segfaults Um das zu bekommen, das Programm zu nennen, verwende ich den folgenden Code:Capture "Segmentation Fault" Nachricht für einen abgestürzten Subprozess: nein out und err nach einem Aufruf zur Kommunikation()

proc = (subprocess.Popen(called, 
         stdout=subprocess.PIPE, 
         stderr=subprocess.PIPE)) 
out,err=proc.communicate() 
print out,err 

genannt ist eine Liste der enthaltenden Name des Programms und das Argument (eine Zeichenfolge mit zufälligen Bytes mit Ausnahme des NULL-Byte, das Subprozess überhaupt nicht mag)

Der Code verhalten und zeigen Sie mir die stdout und stderr, wenn das Programm nicht abstürzt, aber wenn es stürzt ab, und Fehler sind leer, anstatt den berühmten "Segmentierungsfehler" zu zeigen.

Ich möchte einen Weg zu erhalten und Fehler auch beim Programmabsturz finden.

Hoffnung jemand hier als Idee :)

PS: Ich habe auch versucht die check_output/Call/check_call Methoden

EDIT:

  • Ich laufe dieses Skript auf einem Archlinux 64 Bit in einer virtuellen Python-Umgebung (sollte hier nicht wichtig sein, aber man weiß nie: p)

  • Der Segfault passiert im C-Programm m Ich versuche zu laufen und ist eine Folge eines Pufferüberlauf

  • Das Problem ist, dass, wenn der segfault auftritt, kann ich nicht die Ausgabe von dem, was passiert mit subprocess

  • Ich erhalte die Rückkehr rechts: -11 (SIGSEGV)

  • mit python i erhalten:

    ./dumb2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
    ('Exit code was:', -11) 
    ('Output was:', '') 
    ('Errors were:', '') 
    
  • Während draußen python ich:

    ./dumb2 $(perl -e "print 'A'x50") 
    BEGINNING OF PROGRAM 
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
    END OF THE PROGRAM 
    Segmentation fault (core dumped) 
    
  • Der Rückgabewert der Shell ist der gleiche: echo $? 139 kehrt so -11 ($? & 128)

Antwort

0

EDIT: Kam hier wieder: es funktioniert wie ein Charme mit Subprozess von Python3 und wenn Sie auf Linux sind, gibt es einen Backport zu Python2 genannt Subprocess32, die die Arbeit ziemlich gut tut

  • GELöST: Früher habe ich pexpect und es funktioniert

    def cmdlineCall(name, args): 
        child = pexpect.spawn(name, args) 
        # Wait for the end of the output 
        child.expect(pexpect.EOF) 
        out = child.before # we get all the data before the EOF (stderr and stdout) 
        child.close() # that will set the return code for us 
        # signalstatus and existstatus read as the same (for my purpose only) 
        if child.exitstatus is None: 
         returncode = child.signalstatus 
        else: 
         returncode=child.exitstatus 
        return (out,returncode) 
    

PS: ein wenig langsame

+0

versuchen ['out, returncode = run (command, withexitstatus = 1); signal = 128 - returncode'] (http://stackoverflow.com/a/22253472/4279) – jfs

+0

hinweis: 'child.before' ist eine Zeichenkette. Es ist nicht abrufbar; Entferne '()'. – jfs

+0

geben signalstatus und exitstatus nicht als denselben Wert zurück; Sie sind nicht. – jfs

-1
proc = (subprocess.Popen(called, stdout=subprocess.PIPE, stderr=subprocess.PIPE)) 

print(proc.stdout.read()) 
print(proc.stderr.read()) 

Dies sollte besser funktionieren.
Persönlich würde ich mit gehen:

from subprocess import Popen, PIPE 

handle = Popen(called, shell=True, stdout=PIPE, stderr=PIPE) 
output = '' 
error = '' 

while handle.poll() is None: 
    output += handle.stdout.readline() + '\n' 
    error += handle.stderr.readline() + '\n' 

handle.stdout.close() 
handle.stderr.close() 

print('Exit code was:', handle.poll()) 
print('Output was:', output) 
print('Errors were:', error) 

Und wahrscheinlich epoll() wenn möglich für die stderr wie es manchmal blockiert den Anruf zu verwenden, weil es leer ist, weshalb ich stderr=STDOUT am Ende tun, wenn ich faul bin.

+0

Dank für die schnelle Antwort (weil es eine Pseudo-tty laichen), erhalte ich das gleiche Ergebnis Es gibt keine Ausgabe oder Fehler (außer '\ n') In den Fällen nicht segfauling, bekomme ich etwas komisch, die Ausgabe ist troncatured: nur die erste Zeile wird angezeigt – Tic

+0

@Tic Und Sie sind sicher, dass die 'called' Anwendung ist nicht segfauling? Dies wird nicht empfohlen, da dies dazu führen kann, dass Ihre Anwendung hängen bleibt, wenn zu viel ausgegeben wird, aber ersetzen Sie "output + = .." und "error + = ...' mit 'pass" und lassen Sie die Schleife los, bis der Prozess beendet ist . Nach dem 'while handle.poll()' mache einen Sweep der Ausgabe, indem du folgendes tust: 'output = handle.stdout.read()' und das selbe auch für 'stderr', ob das etwas mehr fängt .. Sie sollten Führen Sie die gleiche Art von Operation durch, aber versuchen Sie es einfach und sehen Sie, ob es hilft. – Torxed

+0

Machen Sie auch eine 'python -m trace --trace myscript.py' und sehen Sie, wenn Sie etwas Nützliches daraus erhalten, es sollte Ihnen sagen, wo Ihr segfault passiert und Ihnen eine Vorstellung davon geben, wo Sie anfangen sollen. – Torxed

7

"Segmentation fault" Nachricht möglicherweise von einer Shell generiert werden. Um herauszufinden, ob der Prozess durch SIGSEGV beendet wird, überprüfen Sie proc.returncode == -signal.SIGSEGV.

Wenn Sie die Meldung sehen möchten, können Sie den Befehl in der Shell ausgeführt:

#!/usr/bin/env python 
from subprocess import Popen, PIPE 

proc = Popen(shell_command, shell=True, stdout=PIPE, stderr=PIPE) 
out, err = proc.communicate() 
print out, err, proc.returncode 

ich es mit shell_command="python -c 'from ctypes import *; memset(0,1,1)'" getestet haben, die bewirkt, dass segfault und die Nachricht wird in err erfasst.

Wenn die Nachricht direkt an das Terminal gedruckt wird, dann könnte man pexpect Modul verwenden, um sie zu erfassen:

#!/usr/bin/env python 
from pipes import quote 
from pexpect import run # $ pip install pexpect 

out, returncode = run("sh -c " + quote(shell_command), withexitstatus=1) 
signal = returncode - 128 # 128+n 
print out, signal 

Oder mit pty stdlib Modul direkt:

#!/usr/bin/env python 
import os 
import pty 
from select import select 
from subprocess import Popen, STDOUT 

# use pseudo-tty to capture output printed directly to the terminal 
master_fd, slave_fd = pty.openpty() 
p = Popen(shell_command, shell=True, stdin=slave_fd, stdout=slave_fd, 
      stderr=STDOUT, close_fds=True) 
buf = [] 
while True: 
    if select([master_fd], [], [], 0.04)[0]: # has something to read 
     data = os.read(master_fd, 1 << 20) 
     if data: 
      buf.append(data) 
     else: # EOF 
      break 
    elif p.poll() is not None: # process is done 
     assert not select([master_fd], [], [], 0)[0] # nothing to read 
     break 
os.close(slave_fd) 
os.close(master_fd) 
print "".join(buf), p.returncode-128 
+0

ich mit der Shell-Option versucht, ich das gleiche Verhalten erhalten: ./dumb2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ('Exit-Code war:', -11) (‘ Ausgabe war: ',' ') (' Fehler waren: ',' ') während außerhalb python bekomme ich: ./ dumb2 $ (perl -e "print Ax50") DEBUT DU-PROGRAMM Erleur de segmentation (Core-Dump) – Tic

+0

Das bedeutet, dass die Fehlermeldung direkt auf das Terminal außerhalb der Shell-Standardausgabe gedruckt wird. Sie könnten Pexpect, Pty-Module verwenden, um solche Ausgabe zu erfassen – jfs

+0

BTW, Exit-Code '-11' bedeutet, dass segfault passierte – jfs