Skip to content

Memory error not catched by sandbox #2

@nimdanor

Description

@nimdanor

Le processus runner.py meurt car le student.py demande trop de mémoire.
Et il n'y a pas de message d'erreur clair.

Il faut que l'appel docker soit fait dans le runner pour permettre la gestion d'un message plus malin.

Ce problème est plus un problème de sandbox.


C'est une situation délicate : si votre code Python et le code inconnu s'exécutent dans le même processus, lorsque l'OOM Killer (ou une autre erreur fatale) tue le processus, tout est perdu. Vous ne pouvez pas attraper l'erreur ni la remonter.

Pour résoudre ce problème et garantir que votre code Python puisse attraper l'erreur ou signaler le problème, vous devez isoler l'exécution du code inconnu dans un processus séparé.

Voici les solutions recommandées en Python pour gérer et monitorer cette exécution isolée :


1. Utiliser le module subprocess (Recommandé) ⚙️

C'est la méthode la plus simple pour lancer un autre script ou commande comme processus enfant. Votre script Python parent pourra alors surveiller l'état de l'enfant (y compris s'il est terminé de manière anormale).

Mise en place

Le script inconnu doit être un script exécutable séparé (code_inconnu.py par exemple).

import subprocess
import time

try:
    # Lancement du script inconnu dans un processus séparé
    # (Remplacez 'python code_inconnu.py' par la commande exacte)
    result = subprocess.run(
        ['python', 'code_inconnu.py'],
        capture_output=True,  # Capture la sortie (stdout/stderr)
        timeout=60,           # Optionnel : Tuer le processus après 60 secondes
        check=True            # Lève une exception si le code de sortie n'est pas zéro
    )
    
    # Si le processus se termine normalement (sans OOM kill ou erreur)
    print("Le code inconnu s'est terminé avec succès.")
    
except subprocess.CalledProcessError as e:
    # Attrapé si 'check=True' et le processus enfant a un code de retour non nul
    print(f"Erreur d'exécution du code inconnu (Code de retour : {e.returncode}).")
    print(f"Sortie d'erreur (stderr) : {e.stderr.decode()}")
    # Ici, vous pouvez lever votre propre erreur
    raise RuntimeError(f"Le code inconnu a échoué : {e.returncode}")
    
except subprocess.TimeoutExpired as e:
    # Attrapé si le timeout est atteint
    print("Le code inconnu a dépassé le temps imparti et a été tué.")
    raise RuntimeError("Délai d'exécution dépassé.")
    
except Exception as e:
    # Gestion d'autres erreurs potentielles (ex: fichier introuvable)
    print(f"Erreur inattendue : {e}")

2. Isoler la Mémoire avec Docker ou Conteneurs 🐳

Si le problème est spécifiquement lié à la mémoire (OOM Kill), la meilleure approche est d'utiliser un conteneur Docker pour limiter strictement la quantité de RAM disponible pour le code inconnu.

Avantages

  • Isolation stricte : Le code inconnu ne pourra jamais consommer plus de mémoire que la limite fixée, même si votre conteneur parent en a plus.
  • Contrôle du Tueur OOM : Si le code inconnu atteint la limite, seul le conteneur enfant est tué, et votre script Python parent peut détecter l'échec de la commande docker run.

Schéma d'exécution

  1. Votre script Python parent exécute :
    subprocess.run(["docker", "run", "--memory", "512m", "image_pour_code_inconnu"])
  2. Si l'exécution échoue à cause d'un OOM Kill dans le conteneur enfant, le processus Docker (et donc subprocess.run) retourne un code de sortie non nul que vous pouvez attraper avec subprocess.CalledProcessError.

3. Utiliser le module multiprocessing (Moins recommandé ici)

Vous pouvez aussi utiliser le module multiprocessing pour lancer une fonction dans un processus séparé. Cependant, il est plus difficile de garantir l'isolation complète des ressources (comme la mémoire) que ne le fait subprocess en exécutant une commande externe (surtout si elle est conteneurisée).


Conclusion

Utilisez la méthode subprocess.run() pour lancer le code inconnu. Cela assure que, même si le processus enfant est tué par l'OOM Killer ou s'arrête en erreur, votre processus Python parent continue son exécution dans un état stable et peut lever l'erreur comme vous le souhaitez.

Avez-vous besoin d'aide pour adapter votre code inconnu afin qu'il puisse être appelé via subprocess.run() ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions