2012-03-21 11 views
8

Załóżmy, że pracujesz z jakimś ciałem, któremu nie możesz zaufać, czy istnieje sposób na bezpieczne działanie bez utraty kontroli nad scenariuszem?Jak bezpiecznie uruchomić nierzetelny kawałek kodu?

Przykładem może być funkcja, która działa tylko przez pewien czas i może się nie udać losowo/spektakularnie, jak można spróbować ponownie, dopóki nie zadziała? Próbowałem hakowania przy użyciu modułu wątków, ale miałem problem z porządnym zabiciem zwiniętego wątku.

#!/usr/bin/env python 

import os 
import sys 
import random 

def unreliable_code(): 

    def ok(): 
    return "it worked!!" 

    def fail(): 
    return "it didn't work" 

    def crash(): 
    1/0 

    def hang(): 
    while True: 
     pass 

    def bye(): 
    os._exit(0) 

    return random.choice([ok, fail, crash, hang, bye])() 


result = None 
while result != "it worked!!": 
    # ??? 
+5

Jak spektakularnie może nastąpić awaria kodu? Czy jest nawet bezpieczne, aby uruchomić go w tym samym interpreterze python, co Twój własny kod? Jeśli używa zepsutych rozszerzeń c (lub nadużywa niezłamanych) lub potencjalnie modyfikuje globale Pythona, może być konieczne uruchomienie go w zupełnie innym interprerze pythona w podprocesie. –

Odpowiedz

5

Aby być bezpiecznym przed wyjątkami, użyj polecenia try/except (ale domyślam się, że to wiesz).

Aby być bezpiecznym przed wiszącym kodem (pętlą bez końca), jedynym sposobem, jaki znam, jest uruchomienie kodu w innym procesie. Ten proces potomny, który możesz zabić z procesu ojca, na wypadek, gdyby wkrótce się nie zakończył.

Aby być bezpiecznym przed nieprzyjemnym kodem (robić rzeczy, których nie powinno robić), spójrz na numer http://pypi.python.org/pypi/RestrictedPython.

+3

Istnieje również PySandbox - https://github.com/haypo/pysandbox/ – Darb

4

W swojej prawdziwej sprawie wniosek można przełączyć na tryb wieloprocesowy? Wygląda na to, że to, o co prosisz, można wykonać za pomocą multiprocessing + threading.Timer + try/except.

Spójrz na to:

class SafeProcess(Process): 
    def __init__(self, queue, *args, **kwargs): 
     self.queue = queue 
     super().__init__(*args, **kwargs) 
    def run(self): 
     print('Running') 
     try: 
      result = self._target(*self._args, **self._kwargs) 
      self.queue.put_nowait(result) 
     except: 
      print('Exception') 

result = None 
while result != 'it worked!!': 
    q = Queue() 
    p = SafeProcess(q, target=unreliable_code) 
    p.start() 
    t = Timer(1, p.terminate) # in case it should hang 
    t.start() 
    p.join() 
    t.cancel() 
    try: 
     result = q.get_nowait() 
    except queues.Empty: 
     print('Empty') 
    print(result) 

że w jednej (na szczęście) sprawy dał mi:

Running 
Empty 
None 
Running 
it worked!! 

W próbek kodu masz 4 z 5 szans na zdobycie błąd, więc możesz też odrodzić pulę lub coś, co zwiększy twoje szanse na poprawny wynik.

Powiązane problemy