2010-01-28 2 views
6

Я пишу веб-приложение для обучения Java. Используя, какие пользователи могут скомпилировать свой код на моем serwer +, запустите этот код. компилирования легко с JavaCompiler:компиляция и запуск кода пользователя с JavaCompiler и ClassLoader

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", " ")); 
    } 

мне удается загрузить класс с кодом:

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); 
    } 

Как я могу защитить мое приложение от бесконечного цикла и злых студентов;)

  1. есть ли способ запустить этот код с пожизненным?
  2. есть ли риск утечки памяти, и что я могу сделать, чтобы исправить это.
  3. это хорошее решение, или вы можете предложить что-то лучше?

thx. Tzim

ответ

2

Как я могу защитить мое приложение от бесконечного цикла, и дурные студентов;)

Вы не можете в одной виртуальной машины Java. Зловым студентам особенно сложно справиться, потому что умные придумают какой-то способ подорвать ваши механизмы контроля.

1) Есть ли способ запустить этот код с пожизненным?

Нет, если вы не запускаете его в отдельной JVM.

2) есть ли риск утечки памяти, и что я могу сделать, чтобы исправить это.

Да, есть, и вы ничего не можете с этим поделать (кроме отдельных JVM). На самом деле это было бы проблемой, даже если бы вы могли убить студенческие программы, которые застревают в цикле и т. Д. Вероятно, есть много способов, которыми приложение может привести к тому, что библиотеки классов Java будут утечка памяти/ресурсов ... даже после приложения сам закончил и был GC'ed.

3) Это хорошее решение, или вы можете предложить что-то лучше?

Запуск каждого студенческого приложения в отдельной JVM, которую вы запускаете с вашего сервера, используя Process и друзей. Вам нужно будет написать конкретную информацию операционной системы хоста, чтобы установить временные рамки выполнения, и убить студенческие приложения, которые зашли в тупик. Кроме того, у вас есть всевозможные проблемы, следя за тем, чтобы вы случайно не уничтожали производительность хост-машины, выпустив слишком много JVM.

Лучший ответ - предоставить каждому ученику настольный компьютер или виртуальную машину и позволить им делать свою собственную работу.

+0

+1: Но с оговоркой, что вы должны иметь возможность использовать SecurityManager для песочного кода студента, даже в том же JVM. Но вы захотите использовать политику: заблокировать все, а затем разрешить выбранные действия. –

+0

Thx. heh худшая часть что я должен сделать это с одним сервером. Я попытаюсь использовать процесс. Спасибо за ответ. – tzim

1

Есть ли способ запустить этот код с пожизненным?

Создайте процесс, который контролирует дочерние процессы и завершает его, если он занимает слишком много времени.

есть ли риск утечки памяти, и что я могу сделать, чтобы исправить это.

Вы должны быть в состоянии сделать это, в некоторой степени, контролируя, сколько памяти выделяется (например, параметр для виртуальной машины Java компании Sun -Xmx).

это хорошее решение, или вы можете предложить что-то лучше?

Я не уверен, что решение было предложено, но вот мысль. Установите SecurityManager, что значительно ограничивает выполнение исполняемого кода, например, доступ к файловой системе, процессы всплывания и т. Д. Объедините это с процессом, который контролирует таймауты, ограничивает выделенную память, запускает приложение под отдельной учетной записью пользователя и т. Д. , и я думаю, что у вас есть что-то работоспособное.

Возможно, что вы ищете, но может быть не совсем так, если вы ограничены только Java.

1

Добавляя к ответу Калеба, обязательно запустите целевую JVM со строгим ограничением кучи (например, -Xmx16M). И, конечно же, вы захотите ограничить количество запущенных JVM.

1

Мое текущее решение выглядит следующим образом:

выполнения кода:

@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; 


} 

где killJavaProcesses() выглядит, что

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(); 
} 

Я не могу убить процесс другого. Использование proc.destroy() не работает прямо на машинах Ubuntu/Win XP. Теперь я попытаюсь настроить и использовать SecurityManager.

 Смежные вопросы

  • Нет связанных вопросов^_^