RFR 8029891 : Deadlock detected in java/lang/ClassLoader/deadlock/GetResource.java

Peter Levart peter.levart at gmail.com
Mon May 4 19:33:52 UTC 2015


Hi Brent,

I think all you need for test is this:


import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CheckOverrides {

     public static void main(String[] args) {
         Set<MethodSignature> pMethodSignatures =
             Stream.of(Properties.class.getDeclaredMethods())
                 .filter(CheckOverrides::isMethodOfInterest)
                 .map(MethodSignature::new)
                 .collect(Collectors.toSet());

         Map<MethodSignature, Method> unoverriddenMethods = new HashMap<>();
         for (Class<?> superclass = Properties.class.getSuperclass();
              superclass != Object.class;
              superclass = superclass.getSuperclass()) {
             Stream.of(superclass.getDeclaredMethods())
                 .filter(CheckOverrides::isMethodOfInterest)
                 .forEach(m -> unoverriddenMethods.putIfAbsent(new 
MethodSignature(m), m));
         }
         unoverriddenMethods.keySet().removeAll(pMethodSignatures);

         if (!unoverriddenMethods.isEmpty()) {
             throw new RuntimeException(
                 "The following methods should be overridden by 
Properties class:\n" +
                     unoverriddenMethods.values().stream()
                         .map(Method::toString)
                         .collect(Collectors.joining("\n  ", "  ", "\n"))
             );
         }
     }

     static boolean isMethodOfInterest(Method method) {
         int mods = method.getModifiers();
         return !Modifier.isStatic(mods) &&
             (Modifier.isPublic(mods) || Modifier.isProtected(mods));
     }

     static class MethodSignature {
         final Class<?> returnType;
         final String name;
         final Class<?>[] parameterTypes;

         MethodSignature(Method method) {
             this(method.getReturnType(), method.getName(), 
method.getParameterTypes());
         }

         private MethodSignature(Class<?> returnType, String name, 
Class<?>[] parameterTypes) {
             this.returnType = returnType;
             this.name = name;
             this.parameterTypes = parameterTypes;
         }

         @Override
         public boolean equals(Object o) {
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
             MethodSignature that = (MethodSignature) o;
             if (!returnType.equals(that.returnType)) return false;
             if (!name.equals(that.name)) return false;
             return Arrays.equals(parameterTypes, that.parameterTypes);
         }

         @Override
         public int hashCode() {
             int result = returnType.hashCode();
             result = 31 * result + name.hashCode();
             result = 31 * result + Arrays.hashCode(parameterTypes);
             return result;
         }
     }
}



Regards, Peter


On 05/04/2015 08:32 PM, Peter Levart wrote:
>
>
> On 05/04/2015 06:11 PM, Brent Christian wrote:
>> Hi,
>>
>> Please review this fix, courtesy of Peter Levart (thanks!), that I 
>> would like to get in.
>>
>> https://bugs.openjdk.java.net/browse/JDK-8029891
>> http://cr.openjdk.java.net/~bchristi/8029891/webrev.0/
>>
>> There is some discussion of it in the bug report, starting at 
>> 2014-12-31.
>>
>> The problem, as stated by Mandy:
>>
>> "System Properties is a hashtable that synchronizes on itself for any 
>> access. Currently System.getProperties returns the Properties 
>> instance accessed by the system in which any application code might 
>> synchronize on it (that's what the test is doing). The problem 
>> reported JDK-6977738 is about Properties.store method that was fixed 
>> not to synchronize on this instance. System property is a common way 
>> for changing the default setting and so it's impractical to expect 
>> the class loading code path not to call System.getProperty."
>>
>> This fix changes java.util.Properties to store its values in an 
>> internal ConcurrentHashMap, ignoring its Hashtable heritage.  In this 
>> way, Properties can be "de-sychronized": all methods inherited from 
>> Hashtable are overridden, to remove synchronization, and delegate to 
>> the internal CHM.
>>
>> The serialized form is unchanged.
>>
>>
>> An alternative approach considered would be for 
>> System.getProperties() to return a duplicate snapshot of the current 
>> Properties.  This presents a compatibility risk to existing code that 
>> keeps a reference to the return value of System.getProperties() and 
>> expects to either read new properties added afterwards, or set 
>> properties on the cached copy.
>>
>> -Brent
>>
>
> Hi Brent,
>
> The test looks mostly good, but I would refrain from matching the 
> exception types as part of method signature. Why?
>
> - javac already performs all the necessary checks about declared 
> exceptions if some method overrides another method
> - overriding method can declare a subset and/or subtypes of checked 
> exceptions of those than overridden method declares and this is OK.
> - overriding/overridden methods can declare arbitrary unrelated sets 
> of unchecked exceptions and this is OK.
>
> Another question is whether return type should be considered part of 
> the method signature. For JVM it is, but Java, the language, just 
> matches the method's name and parameter types and javac makes sure 
> that overriding method declarest the same return type or a subtype of 
> overridden method's return type. Well, javac generates two methods in 
> the later case - the one declared in the source code with covariant 
> return type and a synthetic bridge method with overridden method's 
> return type that just calls the declared method. 
> Class.getDeclaredMethods() returns both methods in that case. So 
> either "key" shape would work (one that takes returnType as part of 
> key and one that doesn't).
>
> I don't think you need or even want to check that Properties declares 
> all the methods with signatures from all interfaces. Just checking 
> superclass(es) would do, as Properties is not abstract and in order to 
> compile it must implement all abstract methods (either by inheriting 
> from superclass(es) or implementing them itself). Specifically, you 
> would not want to enforce interface default methods to be overridden 
> by Properties if they are not overridden by superclass(es) (as the 
> interface default method can only call other methods in the interface 
> or Object methods and you need not override such method in Properties 
> for Properties to be OK).
>
> Regards, Peter
>




More information about the core-libs-dev mailing list