From a74a2a8f0a218698feabf8b2de0d40c7de57fb6f Mon Sep 17 00:00:00 2001 From: simonis Date: Tue, 11 Nov 2014 18:28:01 +0100 Subject: [PATCH 1/2] Make default constructors accessible from witin IntrinsicObjectModel.constructWithin --- .../main/java/org/ObjectLayout/IntrinsicObjectModel.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjectModel.java b/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjectModel.java index d1770bd..7b66a95 100644 --- a/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjectModel.java +++ b/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjectModel.java @@ -34,9 +34,13 @@ final class IntrinsicObjectModel extends AbstractIntrinsicObjectModel { */ final T constructWithin(final Object containingObject) { try { + Constructor ctor = getObjectClass().getDeclaredConstructor(); + if (!ctor.isAccessible()) { + ctor.setAccessible(true); + } return instantiate( containingObject, - getObjectClass().getDeclaredConstructor(), + ctor, (Object[]) null ); } catch (NoSuchMethodException ex) { From ba8387b50da71f628241fb80e8b76177e66c49f9 Mon Sep 17 00:00:00 2001 From: simonis Date: Thu, 11 Dec 2014 17:36:39 +0100 Subject: [PATCH 2/2] After we've made the default constructors accessible within IntrinsicObjectModel.constructWithin() we have to ensure that they are also accessible at the call site of IntrinsicObjectModel.constructWithin(). In other words, IntrinsicObjectModel.constructWithin() should only be able to call a constructor, if this constructor was also callable at the point where we actually initialize an @Intrinisc field. --- ObjectLayout/pom.xml | 2 +- .../AbstractIntrinsicObjectModel.java | 11 ++++- .../org/ObjectLayout/IntrinsicObjects.java | 49 ++++++++++++++++++- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/ObjectLayout/pom.xml b/ObjectLayout/pom.xml index 504fb8e..48d3666 100644 --- a/ObjectLayout/pom.xml +++ b/ObjectLayout/pom.xml @@ -65,7 +65,7 @@ maven-surefire-plugin 2.12.4 - -Xmx1g + -Xmx1g -Xbootclasspath/a:${basedir}/target/classes false diff --git a/ObjectLayout/src/main/java/org/ObjectLayout/AbstractIntrinsicObjectModel.java b/ObjectLayout/src/main/java/org/ObjectLayout/AbstractIntrinsicObjectModel.java index 1445186..27a20c7 100644 --- a/ObjectLayout/src/main/java/org/ObjectLayout/AbstractIntrinsicObjectModel.java +++ b/ObjectLayout/src/main/java/org/ObjectLayout/AbstractIntrinsicObjectModel.java @@ -45,6 +45,14 @@ Class getObjectClass() { return objectClass; } + Class getContainingClass() { + return containingClass; + } + + Field getField() { + return field; + } + private void sanityCheckAtModelConstruction() { if ((primitiveArrayModel != null) && !primitiveArrayModel._getArrayClass().equals(objectClass)) { @@ -141,7 +149,8 @@ final void _sanityCheckInstantiation(final Object containingObject) { try { if (field.get(containingObject) != null) { throw new IllegalStateException("Intrinsic object field \"" + field.getName() + - "\" in containing object is already initialized"); + "\" in containing object " + containingObject + " is already initialized to " + + field.get(containingObject)); } } catch (IllegalAccessException e) { throw new IllegalStateException(e); diff --git a/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjects.java b/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjects.java index 13a074d..c5e32e1 100644 --- a/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjects.java +++ b/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjects.java @@ -12,6 +12,9 @@ import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + /** * Intrinsic objects (declared with the {@link org.ObjectLayout.Intrinsic @Intrisic} annotation) may have * their layout within the containing object instance optimized by JDK implementations, such that access @@ -55,10 +58,24 @@ private IntrinsicObjects() { * @param containingObject The object instance that will contain this intrinsic object * @return A reference to the the newly constructed intrinsic object */ + @CallerSensitive + @SuppressWarnings("restriction") public static T constructWithin( final String fieldName, - final Object containingObject) { + final Object containingObject) throws IllegalArgumentException { + + // First we do some plausibility/security checks + Class caller = Reflection.getCallerClass(); + if (!containingObject.getClass().equals(caller)) + throw new IllegalArgumentException(); + IntrinsicObjectModel model = lookupModelFor(fieldName, containingObject); + + // Check if our caller is allowed to access the constructor. + // We wrap the "IllegalAccessException" in an unchecked "IllegalArgumentException" + // to avoid try/catch clauses around every call to "constructWithin" + sanityCheckAccessRights(caller, model.getObjectClass(), null); + return model.constructWithin(containingObject); } @@ -75,12 +92,26 @@ public static T constructWithin( * @param args the arguments to be used with the objectConstructor * @return A reference to the the newly constructed intrinsic object */ + @CallerSensitive + @SuppressWarnings("restriction") public static T constructWithin( final String fieldName, final Object containingObject, final Constructor objectConstructor, final Object... args) { + + // First we do some plausibility/security checks + Class caller = Reflection.getCallerClass(); + if (!containingObject.getClass().equals(caller)) + throw new IllegalArgumentException(); + IntrinsicObjectModel model = lookupModelFor(fieldName, containingObject); + + // Check if our caller is allowed to access the constructor. + // We wrap the "IllegalAccessException" in an unchecked "IllegalArgumentException" + // to avoid try/catch clauses around every call to "constructWithin" + sanityCheckAccessRights(caller, model.getObjectClass(), objectConstructor); + return model.constructWithin(containingObject, objectConstructor, args); } @@ -339,4 +370,20 @@ private static void sanityCheckAnnotation(Intrinsic intrinsicAnnotation, Cla } } } + + @SuppressWarnings("restriction") + private static void sanityCheckAccessRights(Class caller, Class field, Constructor ctor) { + // Check if our caller is allowed to access the constructor. + // We wrap the "IllegalAccessException" in an unchecked "IllegalArgumentException" + // to avoid try/catch clauses around every call to "constructWithin" + try { + if (ctor == null) + ctor = field.getDeclaredConstructor(); + Reflection.ensureMemberAccess(caller, field, ctor, ctor.getModifiers()); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException(e); + } + } }