使用JavaCompiler和ClassLoader编译和运行用户代码

使用JavaCompiler和ClassLoader编译和运行用户代码,java,classloader,java-compiler-api,Java,Classloader,Java Compiler Api,我正在为java学习编写web应用程序。使用哪些用户可以在my serwer+上编译代码并运行该代码。 使用JavaCompiler进行编译很容易: JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

我正在为java学习编写web应用程序。使用哪些用户可以在my serwer+上编译代码并运行该代码。 使用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", " "));
    }
如何保护我的应用程序免受无休止的循环和邪恶的学生的攻击;)

  • 有没有办法在整个生命周期内运行该代码
  • 内存泄漏是否存在任何风险,我可以做些什么来修复此问题
  • 这是一个好的解决方案,还是你能提出更好的建议 thx。 齐姆

    如何保护我的应用程序免受无休止的循环和邪恶的学生的攻击;)

    不能在一个JVM中运行。邪恶的学生尤其难以对付,因为聪明的学生会想出一些方法来颠覆你的控制机制

    1) 有没有办法在整个生命周期内运行该代码

    不,除非您在单独的JVM中运行它

    2) 内存泄漏是否存在任何风险,我可以做些什么来修复此问题

    是的,确实存在,但对此您无能为力(除了单独的JVM)。事实上,即使您可以杀死陷入循环中的学生程序,这也会是一个问题。应用程序可能有很多方法导致Java类库泄漏内存/资源。。。即使在应用程序本身已经完成并被GC'ed之后

    3) 这是一个好的解决方案,还是你能提出更好的建议

    在一个单独的JVM中运行每个学生应用程序,您可以使用
    Process
    和friends从服务器启动该JVM。您需要编写特定于主机操作系统的东西来设置执行时间限制,并杀死死锁的学生应用程序。此外,您还遇到了各种各样的问题,以确保不会因触发太多JVM而意外破坏主机性能

    更好的答案是为每个学生提供一台台式计算机或一台虚拟机,让他们做自己的事情

    有没有办法在整个生命周期内运行该代码

    创建一个进程,该进程监视子进程,如果花费的时间太长,则终止它

    内存泄漏是否存在任何风险,我可以做些什么来修复此问题

    在某种程度上,您应该能够通过控制分配了多少内存来做到这一点(比如Sun的JVM的
    -Xmx
    参数)

    这是一个好的解决方案,还是你能提出更好的建议

    我不确定是否提出了解决方案,但这里有一个想法。安装一个可以极大地限制已执行代码的功能的程序,例如访问文件系统、生成进程等。将其与一个监视超时、限制分配内存、在单独的用户帐户下运行应用程序等的进程结合起来,我认为您可以获得一些可行的功能


    您所寻找的是可能的,但如果您的应用程序仅限于Java,则可能并非完全如此。

    在Kaleb的回答中,请确保使用严格的堆限制(例如-Xmx16M)运行目标JVM。当然,您还需要限制运行的JVM数量。

    我当前的解决方案如下所示:

    运行代码:

    @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;
    
    
    }
    
    我不能杀不同的人。在Ubuntu/Win XP机器上使用proc.destroy()无法正常工作。
    现在我将尝试配置和使用

    +1:但是需要注意的是,即使在同一个JVM中,您也应该能够使用SecurityManager来沙盒学生代码。但您需要使用的策略是:全部阻止,然后允许所选操作。Thx。呵呵,最糟糕的是,我必须用一台服务器来完成这项工作。我将尝试使用这个过程。谢谢你的回复。
    @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;
    
    
    }
    
    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();
    }