Request for review : 7121314 : Behavior mismatch between AbstractCollection.toArray(T[] ) and its spec

Sean Chou zhouyx at linux.vnet.ibm.com
Sun Apr 1 09:24:28 UTC 2012


Hi David,

    I made the new webrev with your modified testcase:
http://cr.openjdk.java.net/~zhouyx/7121314/webrev.04/  .


The link to the bug:
  http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7121314
The link to the start of the thread:

http://mail.openjdk.java.net/pipermail/core-libs-dev/2012-March/009512.html


On Sun, Apr 1, 2012 at 11:25 AM, David Holmes <david.holmes at oracle.com>wrote:

> Simplified testcase below.
>
> Let's finalise this please.
>
> Thanks,
> David
>
>
> On 1/04/2012 1:08 PM, Sean Chou wrote:
>
>> Hi Ulf,
>>
>>     This is a regression testcase, there is no performance issue or
>> future refactoring.
>>     Please wait for David's comments.
>>
>> On Sun, Apr 1, 2012 at 7:22 AM, Ulf Zibis <Ulf.Zibis at gmx.de
>> <mailto:Ulf.Zibis at gmx.de>> wrote:
>>
>>    Hi Sean,
>>
>>    thanks for your effort.
>>
>>    Am 31.03.2012 11:43, schrieb Sean Chou:
>>
>>        Hi David and Ulf,
>>
>>           The new webrev is at:
>>        http://cr.openjdk.java.net/~__**zhouyx/7121314/webrev.03/<http://cr.openjdk.java.net/~__zhouyx/7121314/webrev.03/>
>>        <http://cr.openjdk.java.net/~**zhouyx/7121314/webrev.03/<http://cr.openjdk.java.net/~zhouyx/7121314/webrev.03/>
>> >
>>        <http://cr.openjdk.java.net/%_**_7Ezhouyx/7121314/webrev.03/
>>
>>        <http://cr.openjdk.java.net/%**7Ezhouyx/7121314/webrev.03/<http://cr.openjdk.java.net/%7Ezhouyx/7121314/webrev.03/>>>
>>  .
>>
>>
>>        About the fix, I remained the previous one.
>>        About the testcase, I merged the 3 files into one.
>>        During merging, there are 2 modifications:
>>        1. I added static modifier to the 3 classes, which are enclosed
>>        by class ToArrayTest;
>>
>>    You do not need the indirection via main()...run()...test() if you
>>    have all in 1 file. This was only necessary to feature a general
>>    usability of InfraStructure. You can go back to David's 1 + 1 nested
>>    class approach replacing TConcurrentHashMapX by TestCollection and
>>    maybe rename realMain() to test().
>>    Additionally, loading 4 classes for 1 test would have some
>>    performance impact on the test run, which could be avoided.
>>
>>
>>        2. I removed field TestCollection.fixedSize, which is never read
>>        after Ulf fixed the bug in testcase.
>>
>>    This field would serve to "reset" the TestCollection to fixed
>>    default size without the need of new instantiation for later
>>    refactoring or testcase addition.
>>
>>    As just discussed before, the doc for setSizeSequence() could be
>>    little more specific:
>>      71         /*
>>      72          * Sets the values that size() will return on each use.
>>    The first
>>      73          * call to size will return sizes[0], then sizes[1]
>>    etc. This
>>      74          * allows us to emulate a concurrent change to the
>>    contents of
>>      75          * the collection without having to perform concurrent
>>    changes.
>>      76          * If sizes[n+1] contains a larger value than on last
>>    n-th invocation,
>>      77          * the collection will appear to have shrunk when
>>    iterated; if a
>>      78          * smaller value then the collection will appear to
>>    have grown.
>>      79          * When the last element of sizes is reached, the
>>    collection will
>>      80          * appear size-fixed.
>>      81          */
>>
>>
>>        The link to the bug:
>>        http://bugs.sun.com/__**bugdatabase/view_bug.do?bug___**id=7121314<http://bugs.sun.com/__bugdatabase/view_bug.do?bug___id=7121314>
>>
>>        <http://bugs.sun.com/**bugdatabase/view_bug.do?bug_**id=7121314<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7121314>
>> >
>>        The link to the start of the thread:
>>        http://mail.openjdk.java.net/_**_pipermail/core-libs-dev/2012-**
>> __March/009512.html<http://mail.openjdk.java.net/__pipermail/core-libs-dev/2012-__March/009512.html>
>>
>>        <http://mail.openjdk.java.net/**pipermail/core-libs-dev/2012-**
>> March/009512.html<http://mail.openjdk.java.net/pipermail/core-libs-dev/2012-March/009512.html>
>> >
>>
>>    Good idea, to repeat these links.
>>
>>    -Ulf
>>
>>
>>
>>
>> --
>> Best Regards,
>> Sean Chou
>>
>>
>
> /*
>  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
>  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>  *
>  * This code is free software; you can redistribute it and/or modify it
>  * under the terms of the GNU General Public License version 2 only, as
>  * published by the Free Software Foundation.
>  *
>  * This code is distributed in the hope that it will be useful, but WITHOUT
>  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>  * version 2 for more details (a copy is included in the LICENSE file that
>  * accompanied this code).
>  *
>  * You should have received a copy of the GNU General Public License
> version
>  * 2 along with this work; if not, write to the Free Software Foundation,
>  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
>  *
>  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
>  * or visit www.oracle.com if you need additional information or have any
>  * questions.
>  */
>
> /*
>  * @test
>  * @bug 7121314
>  * @summary AbstractCollection.toArray(T[]**) doesn't return the given
> array
>  *           in concurrent modification.
>  * @author Ulf Zibis, David Holmes
>  */
>
> import java.util.AbstractCollection;
> import java.util.Arrays;
> import java.util.Iterator;
>
> public class ToArrayTest {
>
>    static class TestCollection<E> extends AbstractCollection<E> {
>
>        private final E[] elements;
>
>
>        private int[] sizes;
>        private int nextSize;
>
>        public TestCollection(E[] elements) {
>           this.elements = elements;
>           setSizeSequence(new int[]{elements.length});
>        }
>
>        /*
>         * Sets the values that size() will return on each use. The next
>
>         * call to size will return sizes[0], then sizes[1] etc. This
>         * allows us to emulate a concurrent change to the contents of
>         * the collection without having to perform concurrent changes.
>         * If sizes[n+1] contains a larger value, the collection will
> appear to
>         * have shrunk when iterated; if a smaller value then the
>         * collection will appear to have grown when iterated
>
>         */
>        void setSizeSequence(int... sizes) {
>            this.sizes = sizes;
>            nextSize = 0;
>        }
>
>        /* can change collection's size after each invocation */
>
>        @Override
>        public int size() {
>            return sizes[nextSize == sizes.length-1 ? nextSize :
> nextSize++];
>        }
>
>        @Override
>        public Iterator<E> iterator() {
>            return new Iterator<E>() {
>
>                int pos = 0;
>                public boolean hasNext() {
>                    return pos < sizes[nextSize];
>                }
>                public E next() {
>                    return elements[pos++];
>                }
>                public void remove() {
>                    throw new UnsupportedOperationException(**"Not
> supported yet.");
>                }
>            };
>        }
>    }
>
>  static final Object[] OBJECTS = { new Object(), new Object(), new
> Object() };
>  static final TestCollection<?> CANDIDATE = new TestCollection<Object>(**
> OBJECTS);
>  static final int CAP = OBJECTS.length; // capacity of the CANDIDATE
>  static final int LAST = CAP - 1; // last possible array index
>  Object[] a;
>  Object[] res;
>
>  int last() { return a.length - 1; }
>
>  protected void test() throws Throwable {
>    // Check array type conversion
>    res = new TestCollection<>(new Object[]{"1", "2"}).toArray(new
> String[0]);
>    check(res instanceof String[]);
>    check(res.length == 2);
>    check(res[1] == "2");
>
>    // Check incompatible type of target array
>    try {
>      res = CANDIDATE.toArray(new String[CAP]);
>      check(false);
>    } catch (Throwable t) {
>      check(t instanceof ArrayStoreException);
>    }
>
>    // Check more elements than a.length
>    a = new Object[CAP-1]; // appears too small
>    res = CANDIDATE.toArray(a);
>    check(res != a);
>    check(res[LAST] != null);
>
>    // Check equal elements as a.length
>    a = new Object[CAP]; // appears to match
>    res = CANDIDATE.toArray(a);
>    check(res == a);
>    check(res[last()] != null);
>
>    // Check equal elements as a.length
>    a = new Object[CAP+1]; // appears too big
>    res = CANDIDATE.toArray(a);
>    check(res == a);
>    check(res[last()] == null);
>
>    // Check less elements than expected, but more than a.length
>    a = new Object[CAP-2]; // appears too small
>    CANDIDATE.setSizeSequence(CAP, CAP-1);
>    res = CANDIDATE.toArray(a);
>    check(res != a);
>    check(res.length == CAP-1);
>    check(res[LAST-1] != null);
>
>    // Check less elements than expected, but equal as a.length
>    a = Arrays.copyOf(OBJECTS, CAP); // appears to match
>    CANDIDATE.setSizeSequence(CAP, CAP-1);
>    res = CANDIDATE.toArray(a);
>    check(res == a);
>    check(res[last()] == null);
>
>    // Check more elements than expected and more than a.length
>    a = new Object[CAP-1]; // appears to match
>    CANDIDATE.setSizeSequence(CAP-**1, CAP);
>    res = CANDIDATE.toArray(a);
>    check(res != a);
>    check(res[LAST] != null);
>
>    // Check more elements than expected, but equal as a.length
>    a = new Object[CAP-1]; // appears to match
>    CANDIDATE.setSizeSequence(CAP-**2, CAP-1);
>    res = CANDIDATE.toArray(a);
>    check(res == a);
>    check(res[last()] != null);
>
>    // Check more elements than expected, but less than a.length
>    a = Arrays.copyOf(OBJECTS, CAP); // appears to match
>    CANDIDATE.setSizeSequence(CAP-**2, CAP-1);
>    res = CANDIDATE.toArray(a);
>    check(res == a);
>    check(res[last()] == null);
>
>    test_7121314();
>  }
>
>  /*
>   * Major target of this testcase, bug 7121314.
>   */
>  protected void test_7121314() throws Throwable {
>    // Check equal elements as a.length, but less than expected
>    a = new Object[CAP-1]; // appears too small
>    CANDIDATE.setSizeSequence(CAP, CAP-1);
>    res = CANDIDATE.toArray(a);
>    check(res == a);
>    check(res[last()] != null);
>
>    // Check less elements than a.length and less than expected
>    a = Arrays.copyOf(OBJECTS, CAP-1); // appears too small
>    CANDIDATE.setSizeSequence(CAP, CAP-2);
>    res = CANDIDATE.toArray(a);
>    check(res == a);
>    check(res[last()] == null);
>
>  }
>
>
>  public static void main(String[] args) throws Throwable {
>    ToArrayTest testcase = new ToArrayTest();
>    try { testcase.test(); } catch (Throwable t) { unexpected(t); }
>
>    System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
>    if (failed > 0) throw new Exception("Some tests failed");
>  }
>
>  private static volatile int passed = 0, failed = 0;
>  private static void pass() { passed++; }
>  private static void fail() { failed++; Thread.dumpStack(); }
>  private static void fail(String msg) { System.out.println(msg); fail(); }
>  private static void unexpected(Throwable t) { failed++;
> t.printStackTrace(); }
>
>  static void check(boolean cond) { if (cond) pass(); else fail(); }
>  static void equals(Object x, Object y) {
>
>    if (x == null ? y == null : x.equals(y)) pass();
>    else {System.out.println(x + " not equal to " + y); fail(); }}
>
> }
>
>
>


-- 
Best Regards,
Sean Chou



More information about the core-libs-dev mailing list