JDK-4407429 : (reflect spec) doc presence of synthetic members
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 1.3.0,1.3.1,1.4.0
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic,solaris_7,windows_2000
  • CPU: generic,x86
  • Submitted: 2001-01-24
  • Updated: 2012-09-28
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Description

Name: boT120536			Date: 01/23/2001


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)


The reflection API is unclear as to whether synthetic members (classes,
constructors, methods, and fields) are to show up during reflection.  In my
opinion, they should not be visible to reflection, as synthetic members are only
meant to be accessed by trusted code generated by the compiler, not haphazardly
by reflection.  This is particularly true since other compilers do not
have to follow the same naming convention as JDK; so simply compiling identical
source on different compilers can lead to different program results, although
Java source code is supposed to behave identically regardless of the compiler.

However, if you do decide that synthetic members should be accessible, you
should probably have a separate API to get to them (such as
Class.getSyntheticMethod()), and you should include
Modifier.SYNTHETIC as a way to identify such members.  You may also consider
adding appropriate Securities to the reflection of synthetic members, because
there could be a security breach if a user can access the private members of a
class by figuring out the right synthetic methods to reflect.

It appears that JDK creates all its synthetic members with at most default
(package) access, so a true security breach would require the rogue class belong
to the same package or override access checking.  Thus, a security model that
prevents the addition of rogue classes to a package during the life of the
VM/ClassLoader and that prevents overriding accessibility checks would safely
thwart all attempts to breach a package from outside; then it is just a matter
of only having trusted code within the package.

========
import java.lang.reflect.*;

public class Synthetic {
  public static void main(String[] args) {
    try {
// the XXX.class access generates synthetic blank finals, and class$()
      output("methods in Synthetic", Synthetic.class.getDeclaredMethods());
      output("fields in Synthetic", Synthetic.class.getDeclaredFields());
      output("constructors in Synthetic",
             Synthetic.class.getDeclaredConstructors());
      output("classes in Synthetic", Synthetic.class.getDeclaredClasses());
      output("methods in Sub", Sub.class.getDeclaredMethods());
      output("fields in Sub", Sub.class.getDeclaredFields());
      output("constructors in Sub", Sub.class.getDeclaredConstructors());
      output("classes in Sub", Sub.class.getDeclaredClasses());
// invoke the synthetic class$() method on a completely unrelated class!
      System.out.println(Synthetic.class
			 .getDeclaredMethod("class$",
					    new Class[] {String.class})
			 .invoke(null, new Object[] {"java.lang.Integer"} ));
// constructing a Sub generates a synthetic class in JDK1.3
      System.out.println("Sub contains " + new Synthetic().new Sub());
    } catch (Exception e) {
    }
  }

// a default constructor is generated, but this is not synthetic
//  Synthetic() {}

// i must be a private, non-constant to generate synthetic accessor method
  private int i = 1 + 2;

  class Sub {
// private constructor requires synthetic constructor to access
    private Sub() {}
    public String toString() { return ""+i; }
  }

  static void output(String prefix, Object[] array) {
    System.out.print(prefix + ":\n[" + (array.length > 0 ? array[0] : ""));
    for (int i=1; i<array.length; i++)
      System.out.print(",\n " + array[i]);
    System.out.println("]");
  }

}
=========
output of Synthetic:
methods in Synthetic
[public static void Synthetic.main(java.lang.String[]),
 static int Synthetic.access$100(Synthetic),                 //synthetic
 static java.lang.Class Synthetic.class$(java.lang.String),  //synthetic
 static void Synthetic.output(java.lang.Object[])]
fields in Synthetic
[private int Synthetic.i,
 static java.lang.Class Synthetic.class$Synthetic,           //synthetic
 static java.lang.Class Synthetic.class$Synthetic$Sub,       //synthetic
 static java.lang.Class Synthetic.class$java$lang$String]    //synthetic
constructors in Synthetic
[public Synthetic()] // although this is generated, it is not synthetic
classes in Synthetic
[class Synthetic$1,                                          //synthetic
 class Synthetic$Sub]
methods in Sub
[public java.lang.String Synthetic$Sub.toString()]
fields in Sub
[private final Synthetic Synthetic$Sub.this$0]               //synthetic
constructors in Sub
[Synthetic$Sub(Synthetic,Synthetic$1),                       //synthetic
 private Synthetic$Sub(Synthetic)]
classes in Sub
[]
class java.lang.Integer  // We just abused the class$() method
Sub contains 3

===========
import java.lang.reflect.*;

public class Breach {
  public static void main(String[] args) {
    try {
      Method m = Synthetic.class
	.getDeclaredMethod("access$100", new Class[] {Synthetic.class} );
      Synthetic s = new Synthetic();
      System.out.println("I just read the private field Synthetic.i: " +
			 m.invoke(s, new Object[] {s} ));
    } catch (Exception e) {
      System.out.println("Caught: " + e);
    }
  }
}
=========
output of Breach:
I just read the private field Synthetic.i: 3
(Review ID: 108233) 
======================================================================

Comments
WORK AROUND Name: boT120536 Date: 01/23/2001 When doing reflection, assume that any member that contains '$' in the name is synthetic, and ignore it. This is not a catch-all, and does not prevent the potential for a security breach. ======================================================================
11-06-2004

EVALUATION At this point, given compatibility constraints, the only thing we can probably do is document the present behaviour regarding synthetic members. We could also add APIs to distinguish synthetic members from those explicitly declared. -- iag@sfbay 2001-11-05 Apparently, the addition of reflection methods to distinguish synthetic members was approved by the CCC in the 1.2 time frame (4526329). -- iag@sfbay 2001-11-13 4546736 reports that use of a class literal adds a synthetic method. -- iag@sfbay 2001-12-05 4891872 adds a Method.isSynthetic /** * Returns <tt>true</tt> if this method is a synthetic * method; returns <tt>false</tt> otherwise. * * @return true if and only if this method is a synthetic * method as defined by the Java Language Specification. * @since 1.5 */ public boolean isSynthetic(); Similar methods for Field and Constructor have also been added. All that remains for this bug is to document when synthetic members are returned in the exsiting parts of the reflection API. -- iag@sfbay 2003-11-06
06-11-2003