Review request for 7198429: need checked categorization of caller-sensitive methods in the JDK

Peter Levart peter.levart at gmail.com
Wed Apr 3 07:39:59 UTC 2013


On 04/03/2013 12:25 AM, Mandy Chung wrote:
> On 4/2/13 3:00 PM, Peter Levart wrote:
>> Hi Mandy,
>>
>> There could be:
>>
>> public class SM1 extends SecurityManager {
>> @Override
>> public void checkMemberAccess(Class<?> clazz, int which) {...
>>
>> and:
>>
>> public class SM2 extends SM1 { ... // no checkMemberAccess override
>>
>> now if if you take SM2.class.getDeclaredMethod("checkMemberAccess", 
>> ...) it will throw NoSuchMethodException, but the method is overriden in
>> SM1. So I think it's better to use what John suggested (although not 
>> using getDeclaredMethod, but getMethod instead):
>>
>> smgr.getClass().getMethod("checkMemberAccess", 
>> ...).getDeclaringClass() == SecurityManager.class
>
> Are you concerned the overhead of an exception thrown that we should 
> avoid?

Hi Mandy,

No, I was not thinking of performance. Just the correctness. 
Class.getDeclaredMethod(name, ...) only considers methods "declared" by 
the class (not inherited from a superclass - directy or indirectly). But 
you could have, like in example above, a hierarchy: SM2 extends SM1 
extends SecurityManager where SM1 overrides the method in 
SecurityManager and SM2 doesn't. Now if you try 
SM2.class.getDeclaredMethod(), you will get NoSuchMethodException, but 
that does not mean the method is not overriden - it is in class SM1.

You could use getDeclaredMethod on the class and all superclasses until 
reaching SecurityManager to find out if the method is overriden, but 
it's fortunate that the method is public and so Class.getMethod(name, 
...) can be used which does exactly that and already considers 
inheritance and overriding and returns the most specific method in the 
hierarchy. Explicit search using getDeclaredMethod() could skip 
searching the method in SecurityManager class though, but:

- negative answer via exception is slow
- getMethod() only searches among public methods (which are separately 
cached in special array) and can therefore be faster if there is 
relatively large share of non-public methods declared in the class being 
searched.

Here's a quick micro-benchmark for the common case (only one level of 
subclassing the SecurityManager) and both variants (the method is 
overriden in SecurityManager subclass or not):

##############################################################
# Java: 1.8.0-internal-peter_2013_01_16_13_44-b00
# VM: OpenJDK 64-Bit Server VM 25.0-b14 (mixed mode)
# OS: Linux 3.7.9-104.fc17.x86_64 (amd64)
# CPUs: 8 (virtual)
#
#-------------------------------------------------------------
# GetDeclaredMethodOverridenSearch: run duration: 3,000 ms
#
# Warm up:
# 1 threads, Tavg = 327.59 ns/op (σ = 0.00 ns/op) [ 327.59]
# 1 threads, Tavg = 326.06 ns/op (σ = 0.00 ns/op) [ 326.06]
# Measure:
1 threads, Tavg = 325.18 ns/op (σ = 0.00 ns/op) [ 325.18]
#
#-------------------------------------------------------------
# GetPublicMethodOverridenSearch: run duration: 3,000 ms
#
# Warm up:
# 1 threads, Tavg = 325.69 ns/op (σ = 0.00 ns/op) [ 325.69]
# 1 threads, Tavg = 329.67 ns/op (σ = 0.00 ns/op) [ 329.67]
# Measure:
1 threads, Tavg = 325.88 ns/op (σ = 0.00 ns/op) [ 325.88]
#
#-------------------------------------------------------------
# GetDeclaredMethodNotOverridenSearch: run duration: 3,000 ms
#
# Warm up:
# 1 threads, Tavg = 1,405.84 ns/op (σ = 0.00 ns/op) [ 1,405.84]
# 1 threads, Tavg = 1,371.14 ns/op (σ = 0.00 ns/op) [ 1,371.14]
# Measure:
1 threads, Tavg = 1,358.02 ns/op (σ = 0.00 ns/op) [ 1,358.02]
#
#-------------------------------------------------------------
# GetPublicMethodNotOverridenSearch: run duration: 3,000 ms
#
# Warm up:
# 1 threads, Tavg = 557.50 ns/op (σ = 0.00 ns/op) [ 557.50]
# 1 threads, Tavg = 553.05 ns/op (σ = 0.00 ns/op) [ 553.05]
# Measure:
1 threads, Tavg = 554.59 ns/op (σ = 0.00 ns/op) [ 554.59]
#
#-------------------------------------------------------------
# END.
##############################################################


Here's the source of the test:


public class MethodSearchTest extends TestRunner {

static final Class[] paramTypes = {Class.class, int.class};

static class SMOverriden extends SecurityManager {
@Override
public void checkMemberAccess(Class<?> clazz, int which) {
}
}

static class SMNotOverriden extends SecurityManager {
}

public static class GetDeclaredMethodOverridenSearch extends Test {
@Override
protected void doLoop(Loop loop, DevNull devNull1, DevNull devNull2, 
DevNull devNull3, DevNull devNull4, DevNull devNull5) {
while (loop.nextIteration()) {
try {
SMOverriden.class.getDeclaredMethod("checkMemberAccess", paramTypes);
devNull1.yield(true);
}
catch (NoSuchMethodException e) {
devNull1.yield(false);
}
}
}
}

public static class GetPublicMethodOverridenSearch extends Test {
@Override
protected void doLoop(Loop loop, DevNull devNull1, DevNull devNull2, 
DevNull devNull3, DevNull devNull4, DevNull devNull5) {
while (loop.nextIteration()) {
try {
devNull1.yield(SMOverriden.class.getMethod("checkMemberAccess", 
paramTypes).getDeclaringClass() != SecurityManager.class);
}
catch (NoSuchMethodException e) {
throw new Error(e);
}
}
}
}

public static class GetDeclaredMethodNotOverridenSearch extends Test {
@Override
protected void doLoop(Loop loop, DevNull devNull1, DevNull devNull2, 
DevNull devNull3, DevNull devNull4, DevNull devNull5) {
while (loop.nextIteration()) {
try {
SMNotOverriden.class.getDeclaredMethod("checkMemberAccess", paramTypes);
devNull1.yield(true);
}
catch (NoSuchMethodException e) {
devNull1.yield(false);
}
}
}
}

public static class GetPublicMethodNotOverridenSearch extends Test {
@Override
protected void doLoop(Loop loop, DevNull devNull1, DevNull devNull2, 
DevNull devNull3, DevNull devNull4, DevNull devNull5) {
while (loop.nextIteration()) {
try {
devNull1.yield(SMNotOverriden.class.getMethod("checkMemberAccess", 
paramTypes).getDeclaringClass() != SecurityManager.class);
}
catch (NoSuchMethodException e) {
throw new Error(e);
}
}
}
}

public static void main(String[] args) throws Exception {
startTests();
doTest(GetDeclaredMethodOverridenSearch.class, 3000L, 1, 1, 1);
doTest(GetPublicMethodOverridenSearch.class, 3000L, 1, 1, 1);
doTest(GetDeclaredMethodNotOverridenSearch.class, 3000L, 1, 1, 1);
doTest(GetPublicMethodNotOverridenSearch.class, 3000L, 1, 1, 1);
endTests();
}
}


Regards, Peter

>
> Mandy




More information about the core-libs-dev mailing list