Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug in UnifiedSet$ChainedBucket.removeLongChain() method #30

Closed
vincentvialard opened this issue Dec 1, 2015 · 0 comments
Closed

Bug in UnifiedSet$ChainedBucket.removeLongChain() method #30

vincentvialard opened this issue Dec 1, 2015 · 0 comments

Comments

@vincentvialard
Copy link

Hi there,

a problem with the computation of our hashkeys generated very frequent collisions, and thus bigger buckets. We then had an exception using UnifiedSet.retainAll().

I had a look at the code and found the problem: if i>3 then ChainedBucket.remove(i) calls removeLongChain(i-3), but the switch statement in removeLongChain throws an exception if i-3 > 3. Removing an object in the third chained bucket is thus not possible. It surely did not occur until now, because such heavy collisions are unlikely to happen.

Here is a "minimal change" fix:

        private void removeLongChain(ChainedBucket oldBucket, int i)
        {
            do
            {
                ChainedBucket bucket = (ChainedBucket) oldBucket.three;
                switch (i)
                {
                    case 0:
                        bucket.zero = bucket.removeLast(0);
                        return;
                    case 1:
                        bucket.one = bucket.removeLast(1);
                        return;
                    case 2:
                        bucket.two = bucket.removeLast(2);
                        return;
                    case 3:
                        if (bucket.three instanceof ChainedBucket)
                        {
                            i -= 3;
                            oldBucket = bucket;
                            continue;
                        }
                        bucket.three = null;
                        return;
                    default:
// new code starts here (similar to case 3)
                        if (bucket.three instanceof ChainedBucket)
                        {
                            i -= 3;
                            oldBucket = bucket;
                            continue;
                        }
// new code ends here
                        throw new AssertionError();
                }
            }
            while (true);
        }

Here is a small exemple that reproduces the problem (using some of the strings wth colliding hash from issue #26):

package de.derivo;

import com.gs.collections.impl.set.mutable.UnifiedSet;

import java.util.Set;

public class Main {

    static final String[] COLLISIONS = new String[] {
            "\u9103\ufffe",
            "\u9104\uffdf",
            "\u9105\uffc0",
            "\u9106\uffa1",
            "\u9107\uff82",
            "\u9108\uff63",
            "\u9109\uff44",
            "\u910a\uff25",
            "\u910b\uff06",
            "\u910c\ufee7"
    };

    final static int COUNT = 9;

    public static void main(String[] args) {
        Set<String> stringSet = new UnifiedSet<>();
        Set<String> stringSet2 = new UnifiedSet<>();

        for (int i = 0; i < COUNT; i++) {
            stringSet.add(COLLISIONS[i]);
        }
        for (int i = 0; i < COUNT-2; i++) {
            stringSet2.add(COLLISIONS[i]);
        }
        stringSet.retainAll(stringSet2);
    }
}

Thanks for the great collections, I hope this helps!

Vincent.

@vincentvialard vincentvialard changed the title Bug in UnifiedSet$ChainedBucket.remove() method Bug in UnifiedSet$ChainedBucket.removeLongChain() method Dec 1, 2015
@itohro itohro closed this as completed in 4fd18e9 Dec 22, 2015
itohro added a commit that referenced this issue Dec 22, 2015
Fixes #30.

git-svn-id: svn+ssh://gscollections.svn.services.gs.com/svnroot/gscollections-svn/trunk@918 d5c9223b-1aff-41ac-aadd-f810b4a99ac4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant