2

I'm trying to run a java application , more specifically a jar compiled one, using execve() in c
something like that:

char *cmd[] = {"a.jar"};
execve("a.jar",cmd,NULL);

that is working OK but when I try to limit the number of threads that this program can open using something like that:

struct rlimit rlp;
rlp.rlim_cur = rlp.rlim_max = limit_nproc; 
setrlimit(RLIMIT_NPROC,&rlp);

I have a problem with the JVM which would open threads and I'm preventing that so I have this error:

java.lang.OutOfMemoryError: Cannot create GC thread. Out of system resources.

how can I prevent the threads opened in the java application but not those opened by the JVM ? !

please notice , the question is how to prevent user threads but not system threads , I need a restriction to the running environment like what i did in my second code "RLIMIT_NPROC"

and Thanks!

Ali Kanaan
  • 45
  • 7
  • detecting its happening would do the work with me also – Ali Kanaan Jun 08 '16 at 11:37
  • Possible duplicate of [java run out of memory issue](http://stackoverflow.com/questions/18078859/java-run-out-of-memory-issue) – Andrew Henle Jun 08 '16 at 11:44
  • Setting a limit on the number of processes/threads won't stop Java from trying to start threads. If you run out of memory or system resources trying to create threads, setting `RLIMIT_NPROC` to a lower number will just cause your Java process to run out of threads *faster*. – Andrew Henle Jun 08 '16 at 11:44
  • @AndrewHenle I think you're missing that OP already knows this. OP is trying to prevent Java *user* threads from being created by using the `RLIMIT_NPROC`, but it also prevent Java *system* threads, like the GC thread, from being created, so question is: How to prevent *user* threads without blocking *system* threads. – Andreas Jun 08 '16 at 11:47
  • @AliKanaan If detecting is enough, the debugging API should be able to tell you which threads are running. By monitoring that, you can detect when threads are started and stopped. – Andreas Jun 08 '16 at 11:48
  • @Andreas you are right , the question is how to prevent user threads but not java system threads – Ali Kanaan Jun 08 '16 at 11:51
  • @Andreas I'll do my homework for what you suggested with debugging API and see what I would have , Thanks :) – Ali Kanaan Jun 08 '16 at 11:54
  • 1
    Read the similar [question and answer](http://stackoverflow.com/questions/15868534/why-java-security-manager-doesnt-forbid-neither-creating-new-thread-nor-start), it should point you in the right direction. – Per Huss Jun 08 '16 at 11:56
  • 1
    If there is no parameter you can pass to the java code to control the number of threads created, its most likely the code will not work properly if you inhibit thread creation by some external means. After all the Thread-API does not declare or document an exception for failure to start a thread. – Durandal Jun 08 '16 at 12:01
  • @Andreas To prevent the JVM from starting *user* threads, the application has to be changed. Again: *Setting a limit on the number of processes/threads won't stop Java from trying to start threads.* – Andrew Henle Jun 08 '16 at 12:19
  • @PerHuss thanks for your advice it was good, but , what I want is to restrict the environment around the java code which I can not change nor expect its work ! thanks again :) – Ali Kanaan Jun 08 '16 at 12:44
  • @Durandal thanks for your answer, please see my previous answer, and what I want is what you think it's a problem, I do not want the code to work properly if it contains threads usage! , thanks again :) – Ali Kanaan Jun 08 '16 at 12:49
  • @AndrewHenle I tried to restrict the number of threads and succeeded as I mentioned in my question ! , what do you mean by Setting a limit on the number of processes/threads won't stop Java from trying to start threads !, thanks for your response – Ali Kanaan Jun 08 '16 at 12:54
  • 1
    @AliKanaan, If I write a program that _needs_ to do X, and you run the program in an environment that prevents it from doing X, then the program will not behave as it was intended in that environment. It won't "work". If I write a program that _able_ to take advantage of Y when Y is available, but which is designed to solve the problem in a different way when Y is unavailable, then that's a different story. It all depends on how the program was written. If the program is a server, and the environment prevents it from starting its "accept" thread, then it won't be serving any requests. – Solomon Slow Jun 08 '16 at 13:32
  • @jameslarge thanks for your response, but you cannot say that this is not useful some time , what you said is like saying that the C function setrlimit() is not useful as well as its usage in restricting RLIMIT_NPROC, please excuse me if I misunderstand you – Ali Kanaan Jun 08 '16 at 13:52
  • 1
    You misunderstand me. I'm not denying that setrlimit() is useful. I'm saying that you can't just impose arbitrary limits on any program, and expect the program to work. I can design a program that uses as many threads as it is able to create. I can design another program, that solves a different problem by creating exactly four threads. If you try to run both programs in an environment that limits each program to three threads, then the first program will adapt to that limit and function as intended, but the second program will fail. – Solomon Slow Jun 08 '16 at 14:16
  • @AliKanaan The Java [`Thread.start()`](https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html) method does not provide direct feedback to the caller that it actually started the thread. Setting a limit on the number of threads does not prevent application code from calling `Thread.start()` - **but it can prevent `Thread.start()` from working**. Yes, you can prevent threads from starting. But whatever the application was using those thread(s) to do - calculations, IO, whatever - won't get done. In other words - you broke the application. – Andrew Henle Jun 08 '16 at 15:19
  • @jameslarge thanks again for your response, and I'm sorry for the misunderstanding, but what you think is a problem is exactly what I want, I really want the second code you supposed to fail ! :) , any ideas ? – Ali Kanaan Jun 09 '16 at 00:55
  • @AndrewHenle YYYep that's what I want to do , I need to break the application if it's using threads ! :p , any ideas ? please; I can accomplish that for applications written in c or c++ by limiting the system resources using setrlimit() and that works because they are native applications, now java applications are using JVM which get use of system resources so I'm not able now to limit it because of the needs of the JVM ! DAMN ! – Ali Kanaan Jun 09 '16 at 01:00

2 Answers2

2

This can be achieved with JVMTI agent.

The idea is to intercept native Thread.start0() method and throw an exception whenever it is called.

Here is a sample agent written in C++:

#include <jvmti.h>

// Original native implementation of Thread.start0(), if you wish to call it
extern "C" void JNICALL JVM_StartThread(JNIEnv* env, jthread thread);

void JNICALL StartThreadHook(JNIEnv* env, jthread thread) {
    env->ThrowNew(env->FindClass("java/lang/Error"), "Threads forbidden");
}

void JNICALL VMInit(jvmtiEnv* jvmti, JNIEnv* env, jthread thread) {
    // After VM is initialized, intercept Thread.start0() with our hook function
    jclass thread_class = env->FindClass("java/lang/Thread");
    JNINativeMethod start0 = {(char*)"start0", (char*)"()V", (void*)StartThreadHook};
    env->RegisterNatives(thread_class, &start0, 1);
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
    jvmtiEnv* jvmti;
    vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0);

    jvmtiEventCallbacks callbacks = {0};
    callbacks.VMInit = VMInit;
    jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
    jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);

    return 0;
}

Compile the agent:

g++ -fPIC -shared -olibnothreads.so -Wl,-soname,libnothreads.so nothreads.cpp

Run the application with the agent:

java -agentpath:/path/to/libnothreads.so -jar app.jar

Note that you may also use JVMTI to implement custom logic when to allow and when to deny starting new threads. For example, ThreadStart and ThreadEnd events will help to count created threads. GetStackTrace function will help to find which classes are trying to create a thread.

apangin
  • 92,924
  • 10
  • 193
  • 247
  • I wonder if you can achieve this same thing through meta programming in groovy. Would be am interesting exercise none the less. .. – Chewy Jun 09 '16 at 01:08
  • I'm not able to see the link you provided to JVMTI agent, I may be in a country where this site is forbidden, so I'll get use of the example you provided , if you can give me other useful examples I'd be glade , thanks a lot this was really helpful :) – Ali Kanaan Jun 09 '16 at 01:17
  • @AliKanaan The link basically leads to JVM Tool Interface specification, you may find it elsewhere. More JVMTI examples are in official JDK demos under 'jvmti' directory. Anyway, the above example is going to do exactly what you've asked for. – apangin Jun 09 '16 at 21:29
0

how can I prevent the threads opened in the java application but not those opened by the JVM ?

I'm not sure you can. Preventing the JVM from creating threads is like saying that you want to limit the number of Strings that it creates. If the code creates a thread then there is nothing you can do about it.

About the only thing that might help is the security policy, but as I read it, thread creation is not controlled. See Java's docs on the permissions under control.

java.lang.OutOfMemoryError: Cannot create GC thread. Out of system resources.

As you probably know, in addition to the "main" thread, Java starts a number of other JVM specific threads that work in the background. For example, a simple main(String[] args) program starts "main" and an additional 5 threads for me which doesn't included the GC thread(s) I believe. The JVM threads are needed for memory management and other important tasks. If you are limiting threads up to a point where the GC thread(s) can't start then the JVM is not going to be able to run at all.

<HACK> One thing that you could do is to limit the number of threads to the precise number to include the system threads and "main". Inside of main(), before the user code has an opportunity to start more threads, you could count the number of running threads using Thread.getAllStackTraces().size() or and then set your OS limits to that number. If this still fails then try adding 1 or 2 to the size() to account for other background threads not accounted for in the stack trace map. </HACK>

All this said, the question I have is what are you trying to accomplish? If you are worried about a Java process taking over your server then I wonder if there are OS settings that would be better in controlling how many system resources are given to the process. How about limiting the concurrency instead of the number of threads. Maybe look for thread affinity settings? This would be very OS dependent however.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • thanks gray for your response, I thought about what you suggested as a hack but faced a problem to think deeply about it , what if the number of processes needed to run the JVM and the main class may differ by 2 threads or even one between two different runs for two different codes ? ; however, what if this precise number of threads differs between the different versions ! :\ ??!! is it guaranteed that this number of threads will not change ! – Ali Kanaan Jun 08 '16 at 13:59
  • Unfortunately, it is not guaranteed @AliKanaan between different Java versions but different runs with the same JVM version up to main _should_ fork the same number of system threads. I don't think there is variability there but I'm not 100% sure. Hence the hack. Best of luck. – Gray Jun 08 '16 at 14:05