Question

Je suis en train d'écrire l'application web pour l'apprentissage java. L'utilisation que les utilisateurs peuvent compiler leur code sur mon serwer + exécuter ce code. Est facile avec Compiling JavaCompiler:

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
    CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, prepareFile(nazwa, content));

    task.call();

    List<String> returnErrors = new ArrayList<String>();
    String tmp = new String();
    for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
        tmp = String.valueOf(diagnostic.getLineNumber());
        tmp += " msg: " + diagnostic.getMessage(null);
        returnErrors.add(tmp.replaceAll("\n", " "));
    }

Je parviens à charger la classe avec le code:

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);

    try {
        URL[] urls = {new URL("file:///root/"), new URL("file://C:\\serv\\Apache Tomcat 6.0.20\\bin\\")};
        ClassLoader cl_old = Thread.currentThread().getContextClassLoader();
        ClassLoader cl_new = new URLClassLoader(urls, cl_old);
        Class compiledClass = cl_new.loadClass(CLASS_NAME);
        Method myMethod = compiledClass.getMethod(METHOD_NAME);
        Object tmp = myMethod.invoke(null);
    } catch (Exception ex) {
        Logger.getLogger(ITaskCompile.class.getName()).log(Level.SEVERE, null, ex);
    }

Comment puis-je protéger mon application de la boucle sans fin, et les étudiants mal;)

  1. est-il possible d'exécuter ce code avec une vie?
  2. est-il un risque de fuites de mémoire, et que puis-je faire pour résoudre ce problème.
  3. est cette bonne solution, ou pouvez-vous suggérer quelque chose de mieux?

thx. Tzim

Était-ce utile?

La solution

  

Comment puis-je protéger mon application de la boucle sans fin, et les étudiants mal;)

Vous ne pouvez pas dans une machine virtuelle Java. les étudiants du mal sont particulièrement difficiles à traiter parce que les plus intelligents vont trouver un moyen de contourner vos mécanismes de contrôle.

  

1) est-il un moyen d'exécuter ce code avec une vie?

Non, à moins que vous l'exécutez dans une machine virtuelle Java séparée.

  

2) est-il un risque de fuites de mémoire, et que puis-je faire pour résoudre ce problème.

Oui, il y a, et il n'y a rien que vous pouvez faire à ce sujet (en dehors de JVMs séparés). En fait, ce serait un problème, même si vous pouvez tuer des programmes d'étudiants qui se coincent dans les boucles, etc. Il y a probablement plusieurs façons qu'une application peut faire en sorte que les bibliothèques de classes Java de fuite de mémoire / ressources ... même après l'application lui-même a fini et été GC'ed.

  

3) est cette bonne solution, ou pouvez-vous suggérer quelque chose de mieux?

Exécuter chaque application de l'étudiant dans une machine virtuelle Java séparée que vous lancez à partir de votre serveur en utilisant Process et les amis. Vous aurez besoin d'écrire le système d'exploitation hôte choses spécifiques à fixer des délais d'exécution et de tuer des applications d'étudiants de cette impasse. De plus, vous avez toutes sortes de problèmes en vous assurant que vous ne trash accidentellement les performances de la machine hôte en tirant hors trop JVMs.

Une meilleure réponse est de fournir à chaque élève un ordinateur de bureau ou une machine virtuelle et laissez-les faire leur propre chose.

Autres conseils

  

est-il possible d'exécuter ce code avec une vie?

Créer un processus qui contrôle les processus de l'enfant et se termine si elle prend trop de temps.

  

est-il un risque de fuites de mémoire, et que puis-je faire pour résoudre ce problème.

Vous devriez être en mesure de le faire, dans une certaine mesure, en contrôlant la quantité de mémoire est allouée (comme le paramètre -Xmx à la machine virtuelle Java de Sun).

  

est cette bonne solution, ou pouvez-vous suggérer quelque chose de mieux?

Je ne suis pas sûr une solution a été proposée, mais est là une pensée. Installer un SecurityManager qui limite grandement ce que la code exécuté peut faire, comme l'accès au système de fichiers, les processus d'apparition, etc. Combinez cela avec un processus qui surveille les délais d'attente, limite la mémoire allouée, exécute l'application sous un compte utilisateur séparé, etc., et je pense que vous pouvez avoir quelque chose pratique.

Qu'est-ce que vous cherchez est possible, mais ne peut pas être tout à fait si votre limité à seulement Java.

Ajout à la réponse de Kaleb, assurez-vous d'exécuter la machine virtuelle Java cible avec une limite de tas stricte (par exemple. -Xmx16M). Et, bien sûr, vous aurez envie de limiter le nombre de JVMs en cours d'exécution.

Ma solution actuelle ressemble à ce que:

Code de l'exécution:

@RequestMapping("/student/runITask.action")
public String student_runITask(@ModelAttribute(value = "program") ProgramToCompile program, ModelMap map) {
    //1. code compile
    ITaskCompile itcompile = new ITaskCompile();
    List<String> errorList = itcompile.compileTask(program.getClassname(), program.getProgram());
    Date tmp = new Date();
    this.setPathName(program.getClassname() + tmp.hashCode());
    //2. if compiled... 
    if (errorList.size() < 1) {
        try {
            String[] cmd = {"/bin/sh", "-c", "java -Xmx16M -Xms2M -cp /root/ " + program.getClassname() + "> " + getPathName() + ".data"};
            Runtime rt = Runtime.getRuntime();
            final Process proc = rt.exec(cmd);
            Thread.sleep(1000);
            proc.destroy();
            if (proc.exitValue() > 0) {
                try {
                    killJavaProcesses();
                    map.addAttribute("comment", "Endless LOOP!");
                } catch (Exception ex1) {
                    Logger.getLogger(CompileITaskControler.class.getName()).log(Level.SEVERE, null, ex1);
                }
            } else {
                StringBuffer fileData = new StringBuffer(1000);
                BufferedReader reader = new BufferedReader(new FileReader("/root/" + getPathName() + ".data"));
                char[] buf = new char[1024];
                int numRead = 0;
                while ((numRead = reader.read(buf)) != -1) {
                    fileData.append(buf, 0, numRead);
                }
                reader.close();
                map.addAttribute("comment","Output: <br/><br/><br/><pre>"+fileData.toString()+"</pre>");
            }
        } catch (Exception ex) {
            try {
                killJavaProcesses();
                map.addAttribute("comment", "Endless LOOP!");
            } catch (Exception ex1) {
                Logger.getLogger(CompileITaskControler.class.getName()).log(Level.SEVERE, null, ex1);
            }
        }
    } else {
        map.addAttribute("errorList", errorList);
        map.addAttribute("comment", "PROGRAM NIE ZOSTAŁ URUCHOMIONY");

    } //3. return 
    return DISPLAY_COMP_MSG;


}

où killJavaProcesses () ressemble à ce que

public void killJavaProcesses() throws IOException, InterruptedException {
    String[] getProcessList = {"/bin/sh", "-c", "ps | grep java"};
    String[] killProcessByIdList = {"/bin/sh", "-c", "kill -9 "};
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec(getProcessList);
    InputStream inputstream = proc.getInputStream();
    InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
    BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
    String line2;
    String kill = new String();
    while ((line2 = bufferedreader.readLine()) != null) {
        kill += line2 + "\n";
    }
    proc.destroy();
    String arraykill[] = kill.split("\n");
    String element2kill = "";
    String[] tmp;
    if (arraykill.length >= 1) {
        element2kill = arraykill[arraykill.length - 1].trim().split(" ")[0];
    }
    killProcessByIdList[2] += element2kill;
    Process proc2 = rt.exec(killProcessByIdList);
    proc2.waitFor();
}

Je ne peux pas tuer processus différent. L'utilisation proc.destroy () ne fonctionne pas correctement sur les machines Ubuntu / Win XP. Maintenant, je vais essayer de configurer et utiliser SecurityManager .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top