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

Sean Chou zhouyx at linux.vnet.ibm.com
Wed Apr 11 02:31:17 UTC 2012


Hi Charles,

     Verified. Thanks.

On Tue, Apr 10, 2012 at 2:03 PM, Charles Lee <littlee at linux.vnet.ibm.com>wrote:

> Hi Sean,
>
> The the patch has been committed @
>
> Changeset: e06ea0dd9207
> Author:    littlee
> Date:      2012-04-10 10:17 +0800
> URL:http://hg.openjdk.java.**net/jdk8/tl/jdk/rev/**e06ea0dd9207<http://hg.openjdk.java.net/jdk8/tl/jdk/rev/e06ea0dd9207>
>
>
> 7121314: Behavior mismatch between AbstractCollection.toArray(T[] ) and
> its spec
> Reviewed-by: dholmes, mduigou
> Contributed-by: Sean Zhou<zhouyx at linux.vnet.ibm.com**>, Ulf Zibis<
> ulf.zibis at gmx.de>, David Holmes<david.holmes at oracle.com**>
>
> ! src/share/classes/java/util/**AbstractCollection.java
> + test/java/util/**AbstractCollection/**ToArrayTest.java
>
> Please verified it.
>
> Thank you all for contributing and reviewing this change. Thank you Mike
> and Joe for helping my committing this patch.
>
>
> On 04/01/2012 05:24 PM, Sean Chou wrote:
>
>> Hi David,
>>
>>     I made the new webrev with your modified testcase:
>> http://cr.openjdk.java.net/~**zhouyx/7121314/webrev.04/<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<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>
>>
>>
>> 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/>
>>>> <ht**tp://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/>
>>>> <htt**p://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/<h**
>>>> ttp://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>
>>>> >
>>>>
>>>>        <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-**<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-**<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(); }}
>>>
>>> }
>>>
>>>
>>>
>>>
>>
>
> --
> Yours Charles
>
>


-- 
Best Regards,
Sean Chou



More information about the core-libs-dev mailing list