There is a internal class SynchronizedCollection - inside java.util.Collections with two constructor. the first takes the collection and the other takes collection and a mutex. former constructor checks argument for not being null. but the later don't!. here is the implementation.
SynchronizedCollection(Collection<E> c) {
if (c==null)
throw new NullPointerException();
this.c = c;
mutex = this;
}
SynchronizedCollection(Collection<E> c, Object mutex) {
this.c = c;
this.mutex = mutex;
}
with this implementation i can break the class invariant by sending null to second constructor.
i believe it should be something like this:
SynchronizedCollection(Collection<E> c) {
this(c,this)
}
SynchronizedCollection(Collection<E> c, Object mutex) {
if (c==null)
throw new NullPointerException();
this.c = c;
this.mutex = mutex;
}
however i can't convince myself Josh Bloch and Neal Gafter couldn't see this. so can you really tell me what i missed here?
edited: possible attack
Map<String, String> m = new Map<String, String>(){
@Override
public int size() {
// TODO Auto-generated method stub
return 0;
}
.
.
.
@Override
public Collection<String> values() {
return null;
}
};
Map<String, String> synchronizedMap = Collections.synchronizedMap(m);
Collection<String> values = synchronizedMap.values();
Sure this is a bug. The both constructors should be consistent, either both should throw an exception or none should throw.
This has been fixed in Java 8. Now both constructors will throw the exception:
SynchronizedCollection(Collection<E> c) {
this.c = Objects.requireNonNull(c);
mutex = this;
}
SynchronizedCollection(Collection<E> c, Object mutex) {
this.c = Objects.requireNonNull(c);
this.mutex = Objects.requireNonNull(mutex);
}
Both of those constructors are package protected and only the first one can possibly be used with a null
argument through the public
synchronizedList()
and synchronizedSet()
methods of Collections
.
The other constructor is used internally (in the Collections
class) and the first argument can never be null
in the various implementations (calling code) so you cannot break it.
You could always try to create something in the java.util
package but you will most likely get a SecurityException
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With