0

I am working on a research project for deterministic fault reproduction in the JVM and am struggling to make classloading deterministic between different app runs. By that I mean that I want to ensure that always the same thread loads a class that loaded it in a previous run as well.

Let's say I recorded which thread loaded a given class in the first run (that's the easy part) and stored that information somewhere. I then want to control that no other thread will load the class in any following application runs (e.g. by halting them before they would lead to a load class event).

While most of the things I managed to do via byte code modifications or JVMTI I am not sure how I could approach this problem as the loading is controlled by the JVM and there is obviously no byte code saying before load class, neither a proper JVMTI event.

I am open for any suggestion, no matter how 'freaky'. So even using non-public JVM internals would be fine; C/C++ or Java. Not sure where to hook in though.

Haasip Satang
  • 457
  • 3
  • 17
  • Static constructor doesn't fit your needs? – Oscar Jun 18 '18 at 21:41
  • No, static initializers (``) are not executed at class loading time but only once class initialization is actually needed. But even if they would be executed direclty AFTER the class was loaded, it would still be AFTER the class was loaded. I need something to stop before a class gets loaded. – Haasip Satang Jun 18 '18 at 21:52
  • **Why?** It should not matter which thread loads a class; as you said yourself, loading and initialization are two different things. If you encounter multiple threads trying to load the class at the same time, you already have multi-threading related indeterminism and the loading operation is the last thing affected by that. – Holger Jun 21 '18 at 10:15
  • The problem is non-determinism that *might* happen inside a custom classloader. Although I don't know a classloader that does this there might be one accessing some information from the thread or using something that accesses `ThreadLocal`s, etc. Also it might access some shared resources and the current mechanism to control determinism is developed in a way that it guarantees the access order to be same same as in the initial run. So in order to be 100% deterministic we need to control the classloading behaviour as well and ensure it is the same thread entering the classloader. – Haasip Satang Jun 21 '18 at 10:56
  • Before JDK1.7 there was the problem that the lock to enter the classloaders was held inside the JVM. So I couldn't simply block a thread that was already inside the classloader since then noone else could enter. Since JDK1.7 allows classloaders to register themselves as parallel capable I could maybe allow parallel entries for all classloaers but then block the unwanted ones and force early returns after the class got loaded by the thread I want. There must be another solution though as years ago there was a product called ReplayDirector you was able to deal with that even for Java 1.5 and 1.6 – Haasip Satang Jun 21 '18 at 11:04
  • @Holger Any idea what would be the best/easiest way to patch the (Open)JDK to achieve something like this? I really have no other idea anymore... – Haasip Satang Jul 10 '18 at 20:41
  • It seems you didn’t get me. If you really have a scenario where such concurrent loading could happen, the indeterminism is already in all operations happening before the loading. Thread scheduling is always nondeterministic. Just imagine the following scenario: two threads try to acquire the same lock and while holding the lock, set a thread local variable and initiate the loading of a class using a custom class loader reading the variable. Your attempt to force the other thread as loading thread will cause a deadlock *in the best case*. Unless you can control which thread wins at locking… – Holger Jul 11 '18 at 08:21
  • @Holger Yes, I'm absolutely aware of everything you wrote. I already can control the order for how threads aquire locks to ensure same execution as in the initial run. As the inital run worked and was only observed by me but execution was not influenced in any way there are no deadlocks I could cause. In subsequent executions I want to ensure the same execution order as in the initial run. In the scenario you sketeched one thread woud have won the race for the lock and this thread would then have loaded the class. If there is no lock upfront,however,either thread might cause the classload. – Haasip Satang Jul 11 '18 at 08:29
  • The problem is really about complete deterministic replay of any application run. This involves handling a lot of different events (locks, clinints, References/GC, native methods, etc). A lot of things are handled already but class loading still puzzles me. Check this out for example, which is the result of just one of dozens of research papers in this field https://sites.google.com/site/leaphkust/home – Haasip Satang Jul 11 '18 at 08:34
  • That is contradicting your problem description. As you said yourself, the JVM loads classes under a lock by default. Further, even concurrent loaders use concurrent data structures to control loading. If you were able to control the outcome of these operations, there was no need to control class loading that is built atop these constructs. The class loading should already be deterministic as a side effect of controlling the other constructs. – Holger Jul 11 '18 at 08:36
  • Nope, unfortunately not. The thing is that I can control locks that are Java code (synchronized methods and blocks / monitorEnter events). There is no such lock in byte code, however, therefore I can't control it yet. The lock is inside the JVM. Imagine the following scenario: Two threads do NOT try aquire a lock, they simple create a new instance of same same class. Either threads wins and would lead the JVM to trigger the classloader which would block the other thread until the loading is completed. Nothing in bytecode that I could intercept. – Haasip Satang Jul 11 '18 at 08:41
  • Theoretically I could weave in my code before every `new SomeObject()` (and any other events that trigger classloading) and ensure proper execution order. Needless to say that this would be an extreme overhead that is not acceptable. – Haasip Satang Jul 11 '18 at 08:43
  • You mean, besides the extreme overhead of trying to make every concurrent operation deterministic? I mean, if you are serious, you would have to intercept every field and array access to make racy access deterministic. And then you have the problem that you can’t reproduce errors which are caused by the indeterminism. Like when the JIT optimizes away a redundant access. I see a lot of unsolvable problems there and it is pointless to focus on the unlikely scenario of a custom class loader depending on the loading thread. – Holger Jul 11 '18 at 09:37
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/174793/discussion-between-haasip-satang-and-holger). – Haasip Satang Jul 11 '18 at 10:22

0 Answers0