-2

I need some way to get an instance of a class that called some method. For example, in this program, I want to get the instance of Person (named Jack here) that called method Main.call().

public class Main {
   public static Person p;
   public static void main(String[] args) {
      p = new Person("Jack");
      p.call();
   }
   public static void call() {
      Object caller = Magic.getTrace()[1].getObject(); // This is what I need
      System.out.println(((Person)caller).getName()); // Output: Jack
      Class<?> clazz = Magic.getTrace()[2].getClass(); // This too
      System.out.println(clazz.getName()); // Output: Main
}
public class Person {
   private String name;
   public Person(String _name) {
      name = _name
   }
   public String getName() { return name; }
   public void call() {
      Main.call();
   }
}

So, is there any way to accomplish that? It should be possible because debuggers can use that.

For mods: I don't want the NAME of the class, but the INSTANCE...

Thanks!

RORAK
  • 26
  • 7
  • To get an _instance_ of the calling class: no. You can get stack trace details about it, but the actual instance can only be retrieved if you passed it to the call. However, within `Person#call`, you know which `Person` is calling `Main#call` (as it would be the `this` keyword). You can see this in a debugger as well, when inside `Main#call`, there is no `Person` to refer to. – Rogue Jul 13 '22 at 17:34
  • @Rogue I don't want to use it in this person case. I'm making some lock security class, where only objects that created the lock can access it. And if you passed the object as an argument, it'd be super easy to bypass... I could use some security code, but that is also unsafe because reflection is a thing... – RORAK Jul 13 '22 at 17:37
  • I've created a [similar tool](https://github.com/Codelanx/CodelanxCommons/blob/master/src/main/java/com/codelanx/commons/util/Reflections.java#L71-L136) years back, and it is not without several drawbacks. First and foremost, these checks can be invalidated by anyone adept enough to do so. Secondly, your code can be decompiled and recompiled. You can still pass the object that you want to access the Lock, so it can internally check if that object should get access, raising an exception if they do not. Preventing the call itself will not happen, and the stacktrace check will be very expensive. – Rogue Jul 13 '22 at 17:40
  • If the question is reopened, there's a plausible solution using package-private and two separate classes: one to hold the `Lock` once it is created, and another to specify who may access it. For now, I would add more details regarding the actual classes you wish to restrict access with (e.g. are they continuously created throughout your program's lifetime, and is it for only known classes or potentially any new class) – Rogue Jul 13 '22 at 17:42
  • @Rogue and can package-private classes be accessed using reflection? – RORAK Jul 13 '22 at 17:46
  • Yes they can. You are not going to circumvent reflection in any easy manner. The old java way was through the use of a SecurityManager, which has since been deprecated. You should include more information regarding your specific situation (loading third-party plugins?), as there may be other tools available than what has been mentioned thus far. – Rogue Jul 13 '22 at 17:47
  • Why do you need this? It smells of an underlying design issue unless this is purely for curiosity. – Tintin Jul 13 '22 at 19:30
  • @Tintin I'm making library for users where interfaces can have fields in storage and I need to check if the interface accessing the field is the same that created the field... – RORAK Jul 14 '22 at 17:39

1 Answers1

1

There isn't a way to do it that can't be subverted with relative ease. Which renders this kind of pointless as a security mechanism.

Note that it might be (have been!) possible to do something using SecurityManager, but that assumes that your code is only called from code that is in a "sandbox". And all sorts of things would need to be disabled in the sandbox ... starting with reflection ... which would be too burdensome for a modern Java programmer.

Basically, if you have a security mechanism that needs to be enforced against the users of your code, then it needs to be done outside of the JVM where their code runs. Typically you would perform the checks on a remote server ... that your users cannot interfere with.

(The "do it in a server" approach may be unworkable or unacceptable to you. In that case: sorry but there is no real solution. Only approaches that give you the illusion that you have solved the problem.)

You noted this:

It should be possible because debuggers can use that.

Sorry, but no.

Debuggers use a debug-agent to access the state of the JVM they are debugging. Unfortunately (or maybe fortunately, depending on your perspective!) a JVM cannot use a debug-agent on itself. It doesn't work.

My understanding is that the debug-agent code pauses all threads in the target JVM while it is doing its thing. When a JVM tries to "debug itself", that includes the thread in the JVM that is trying to use the agent. Instant deadlock.

And besides, someone wanting to subvert any agent-based security mechanism simply needs to not attach the agent when they start their JVM.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216