diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index c10abcc72e660a3de1565e0b3dcd9144df449328..990f3e8d30cbcd69ca6bde6d9e87fadbb99be4f8 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -40,6 +40,7 @@ import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.Objects; import java.util.function.IntBinaryOperator; import java.util.function.IntUnaryOperator; import sun.reflect.CallerSensitive; @@ -410,7 +411,17 @@ public abstract class AtomicIntegerFieldUpdater { if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); - this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass; + // Access to protected field members is restricted to receivers only + // of the accessing class, or one of its subclasses, and the + // accessing class must in turn be a subclass (or package sibling) + // of the protected member's defining class. + // If the updater refers to a protected field of a declaring class + // outside the current package, the receiver argument will be + // narrowed to the type of the accessing class. + this.cclass = (Modifier.isProtected(modifiers) && + tclass.isAssignableFrom(caller) && + !isSamePackage(tclass, caller)) + ? caller : tclass; this.tclass = tclass; this.offset = U.objectFieldOffset(field); } @@ -431,6 +442,21 @@ public abstract class AtomicIntegerFieldUpdater { return false; } + /** + * Returns true if the two classes have the same class loader and + * package qualifier + */ + private static boolean isSamePackage(Class class1, Class class2) { + return class1.getClassLoader() == class2.getClassLoader() + && Objects.equals(getPackageName(class1), getPackageName(class2)); + } + + private static String getPackageName(Class cls) { + String cn = cls.getName(); + int dot = cn.lastIndexOf('.'); + return (dot != -1) ? cn.substring(0, dot) : ""; + } + /** * Checks that target argument is instance of cclass. On * failure, throws cause. diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index e701c67005f92466a114fca959fb33ed3af4174e..b1d14c5820b83074912e572323fc680f06add401 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -40,6 +40,7 @@ import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.Objects; import java.util.function.LongBinaryOperator; import java.util.function.LongUnaryOperator; import sun.reflect.CallerSensitive; @@ -408,7 +409,17 @@ public abstract class AtomicLongFieldUpdater { if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); - this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass; + // Access to protected field members is restricted to receivers only + // of the accessing class, or one of its subclasses, and the + // accessing class must in turn be a subclass (or package sibling) + // of the protected member's defining class. + // If the updater refers to a protected field of a declaring class + // outside the current package, the receiver argument will be + // narrowed to the type of the accessing class. + this.cclass = (Modifier.isProtected(modifiers) && + tclass.isAssignableFrom(caller) && + !isSamePackage(tclass, caller)) + ? caller : tclass; this.tclass = tclass; this.offset = U.objectFieldOffset(field); } @@ -539,7 +550,17 @@ public abstract class AtomicLongFieldUpdater { if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); - this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass; + // Access to protected field members is restricted to receivers only + // of the accessing class, or one of its subclasses, and the + // accessing class must in turn be a subclass (or package sibling) + // of the protected member's defining class. + // If the updater refers to a protected field of a declaring class + // outside the current package, the receiver argument will be + // narrowed to the type of the accessing class. + this.cclass = (Modifier.isProtected(modifiers) && + tclass.isAssignableFrom(caller) && + !isSamePackage(tclass, caller)) + ? caller : tclass; this.tclass = tclass; this.offset = U.objectFieldOffset(field); } @@ -620,4 +641,19 @@ public abstract class AtomicLongFieldUpdater { } while (acl != null); return false; } + + /** + * Returns true if the two classes have the same class loader and + * package qualifier + */ + private static boolean isSamePackage(Class class1, Class class2) { + return class1.getClassLoader() == class2.getClassLoader() + && Objects.equals(getPackageName(class1), getPackageName(class2)); +} + + private static String getPackageName(Class cls) { + String cn = cls.getName(); + int dot = cn.lastIndexOf('.'); + return (dot != -1) ? cn.substring(0, dot) : ""; + } } diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index 76fa0a761c7538bd4c88d9940cea98d8daf0378d..cd18e4840ea885a58988813ff43edcc671a4b94c 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -40,6 +40,7 @@ import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.Objects; import java.util.function.BinaryOperator; import java.util.function.UnaryOperator; import sun.reflect.CallerSensitive; @@ -346,7 +347,17 @@ public abstract class AtomicReferenceFieldUpdater { if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); - this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass; + // Access to protected field members is restricted to receivers only + // of the accessing class, or one of its subclasses, and the + // accessing class must in turn be a subclass (or package sibling) + // of the protected member's defining class. + // If the updater refers to a protected field of a declaring class + // outside the current package, the receiver argument will be + // narrowed to the type of the accessing class. + this.cclass = (Modifier.isProtected(modifiers) && + tclass.isAssignableFrom(caller) && + !isSamePackage(tclass, caller)) + ? caller : tclass; this.tclass = tclass; this.vclass = vclass; this.offset = U.objectFieldOffset(field); @@ -368,6 +379,21 @@ public abstract class AtomicReferenceFieldUpdater { return false; } + /** + * Returns true if the two classes have the same class loader and + * package qualifier + */ + private static boolean isSamePackage(Class class1, Class class2) { + return class1.getClassLoader() == class2.getClassLoader() + && Objects.equals(getPackageName(class1), getPackageName(class2)); + } + + private static String getPackageName(Class cls) { + String cn = cls.getName(); + int dot = cn.lastIndexOf('.'); + return (dot != -1) ? cn.substring(0, dot) : ""; + } + /** * Checks that target argument is instance of cclass. On * failure, throws cause.