6

Java学習用のWebアプリを書いています。どのユーザーが自分のサーバーでコードをコンパイルし、そのコードを実行できるかを使用します。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", " "));
    }

私はコードでクラスをロードすることに成功しました:

    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. これは良い解決策ですか、それとももっと良いものを提案できますか?

どうも。ツィム

4

4 に答える 4

2

無限ループや邪悪な学生からアプリを保護するにはどうすればよいですか ;)

1 つの JVM ではできません。頭の良い学生は、あなたの制御メカニズムを覆す方法を見つけ出すため、悪意のある学生は特に対処が困難です。

1)そのコードを生涯にわたって実行する方法はありますか?

いいえ、別の JVM で実行しない限り。

2)メモリリークのリスクはありますか?これを修正するにはどうすればよいですか。

はい、あります。それについてできることは何もありません (別の JVM を除いて)。実際、これは、ループなどでスタックする学生プログラムを強制終了できたとしても、問題になります。おそらく、アプリケーションが Java クラス ライブラリにメモリ/リソース リークを引き起こす可能性がある多くの方法があります ...アプリケーションの後でさえもそれ自体は終了し、GC されています。

3)これは良い解決策ですか、それとももっと良いものを提案できますか?

Processおよび友人を使用してサーバーから起動する個別の JVM で、各学生アプリケーションを実行します。実行時間の制限を設定し、デッドロックする学生アプリケーションを強制終了するには、ホスト オペレーティング システム固有のものを作成する必要があります。さらに、あまりにも多くの JVM を起動してホスト マシンのパフォーマンスを誤って台無しにしないようにするために、あらゆる種類の問題があります。

より良い答えは、各生徒にデスクトップ コンピューターまたは仮想マシンを提供し、生徒が自分のことをできるようにすることです。

于 2010-01-28T23:01:38.043 に答える
1

Kalebの回答に加えて、ターゲットJVMを厳密なヒープ制限(例:-Xmx16M)で実行してください。そしてもちろん、実行するJVMの数を制限する必要があります。

于 2010-01-28T23:21:34.020 に答える
1

そのコードを生涯にわたって実行する方法はありますか?

子プロセスを監視し、時間がかかりすぎる場合は終了するプロセスを作成します。

メモリリークのリスクはありますか?これを修正するにはどうすればよいですか?

割り当てられるメモリの量を制御することで、ある程度それを行うことができるはずです ( -XmxSun の JVM のパラメータのように)。

これは良い解決策ですか、それとももっと良いものを提案できますか?

解決策が提案されているかどうかはわかりませんが、ここに考えがあります。ファイルシステムへのアクセス、プロセスの生成など、実行されたコードが実行できることを大幅に制限するSecurityManagerをインストールします。これを、タイムアウトを監視し、割り当てられたメモリを制限し、別のユーザー アカウントでアプリケーションを実行するなどのプロセスと組み合わせます。 、そして、実行可能なものを手に入れることができると思います。

あなたが探しているものは可能ですが、Javaだけに制限されている場合は完全にそうではないかもしれません.

于 2010-01-28T23:20:01.037 に答える
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を構成して使用しようとします。

于 2010-01-31T18:32:17.840 に答える