Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a bug in Java SynchronizedCollection class?

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();
like image 302
Morteza Adi Avatar asked Sep 29 '13 15:09

Morteza Adi


2 Answers

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);
}
like image 59
mentallurg Avatar answered Nov 12 '22 09:11

mentallurg


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.

like image 21
Sotirios Delimanolis Avatar answered Nov 12 '22 09:11

Sotirios Delimanolis