16

While developing a Java application under Eclipse I got the warning about "method/value accessed via a synthetic method". The solution was simply changing a private access modifier to a default level.

That left me wondering: what's the penalty on using a synthetic method? There is some? I assume so as the compiler/Eclipse raises the warning, but it's something so relevant or something that could be safely ignored?

I've not seen this information around here, so I'm asking.

Mr_and_Mrs_D
  • 32,208
  • 39
  • 178
  • 361
Pere Villega
  • 16,429
  • 5
  • 63
  • 100

2 Answers2

16

Eclipse is warning you that you may be exposing information you think is private. Synthetic accessors can be exploited by malicious code as demonstrated below.

If your code needs to run in a secure VM, it may be unwise to use inner classes. If you can use reflection and have full access to everything, synthetic accessors are unlikely to make a measurable difference.


For example, consider this class:

public class Foo {
  private Object baz = "Hello";
  private class Bar {
    private Bar() {
      System.out.println(baz);
    }
  }
}

The signature for Foo is actually:

public class Foo extends java.lang.Object{
    public Foo();
    static java.lang.Object access$000(Foo);
}

access$000 is generated automatically to let the separate class Bar access baz and will be marked with the Synthetic attribute. The precise names generated are implementation dependent. Regular compilers won't let you compile against this method, but you can generate your own classes using ASM (or similar) like this:

import org.objectweb.asm.*;
public class FooSpyMaker implements Opcodes {
  public static byte[] dump() throws Exception {
    ClassWriter cw = new ClassWriter(0);
    cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "Spy", null, "java/lang/Object",null);
    MethodVisitor ctor = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
    ctor.visitCode();
    ctor.visitVarInsn(ALOAD, 0);
    ctor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
    ctor.visitInsn(RETURN);
    ctor.visitMaxs(1, 1);
    ctor.visitEnd();
    MethodVisitor getBaz = cw.visitMethod(ACC_PUBLIC, "getBaz",
        "(LFoo;)Ljava/lang/Object;", null, null);
    getBaz.visitCode();
    getBaz.visitVarInsn(ALOAD, 1);
    getBaz.visitMethodInsn(INVOKESTATIC, "Foo", "access$000",
        "(LFoo;)Ljava/lang/Object;");
    getBaz.visitInsn(ARETURN);
    getBaz.visitMaxs(1, 2);
    getBaz.visitEnd();
    cw.visitEnd();
    return cw.toByteArray();
  }
}

This creates a simple class called Spy that will allow you to call access$000:

public class Spy extends java.lang.Object{
    public Spy();
    public java.lang.Object getBaz(Foo);
}

Using this, you can inspect the value of baz without reflection or any method exposing it.

public class Test {
  public static void main(String[] args) {
    Foo foo = new Foo();
    Spy spy = new Spy();
    System.out.println(spy.getBaz(foo));
  }
}

The Spy implementation requires that it be in the same package as Foo and that Foo isn't in a sealed JAR.

Ori Marko
  • 56,308
  • 23
  • 131
  • 233
McDowell
  • 107,573
  • 31
  • 204
  • 267
  • 1
    +0: I would think that using reflections is a hell of a lot easier to access/modify private fields. So I don't see accessors adding to the problem at all. ;) – Peter Lawrey Apr 06 '11 at 07:30
  • 4
    @Peter Lawrey - I was trying to make this point in my open remarks - this stuff is can only be considered an exploit under certain (abnormal) conditions: 1) you're using a security manager that forbids reflection (or at least [setAccessible](http://download.oracle.com/javase/6/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible%28boolean%29) 2) the attacker can run their own code 3) the package isn't sealed. We're talking about writing secured applet-like frameworks. _The reason for the example is because once you start thinking about it, it's hard not to go off and try it._ – McDowell Apr 06 '11 at 09:24
  • @McDowell How can I see `access$000` in `Foo`? When I try printing all methods inside `Class` it doesn;t print `access$000`. – Jatin May 24 '14 at 10:19
  • 1
    @Jatin See the [javap](http://docs.oracle.com/javase/8/docs/technotes/tools/) tool. – McDowell May 26 '14 at 07:09
4

I'm pretty sure the penalty is nothing more than an additional method invocation. In other words, completely irrelevant to almost all use cases.

If it's in a particularly hot path you might get worried, but you should establish with a profiler that this is actually your problem first.

I just turn the warning off.

Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100
  • 2
    As the synthetic method is always trivial, it should be in-lined. It will only make a difference in JVMs with little optimization e.g. some J2ME. I don't like synthetic methods because the pollute the call stack in stack traces. ;) – Peter Lawrey Apr 06 '11 at 07:33