Skip to content

ByteQuadsCanonicalizer: ArrayIndexOutOfBoundsException in addName #548

@alpire

Description

@alpire

Fuzzing a spring boot application led to the following exception in ByteQuadsCanonicalizer.addName:

Caused by: java.lang.ArrayIndexOutOfBoundsException: 1024
        at com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer.addName(ByteQuadsCanonicalizer.java:834)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.addName(UTF8StreamJsonParser.java:2325)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.findName(UTF8StreamJsonParser.java:2198)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.parseMediumName2(UTF8StreamJsonParser.java:1760)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.parseMediumName(UTF8StreamJsonParser.java:1737)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._parseName(UTF8StreamJsonParser.java:1672)
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:727)
        at com.fasterxml.jackson.core.base.ParserMinimalBase.skipChildren(ParserMinimalBase.java:237)
        at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:817)
        at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1152)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1589)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1567)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:375)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3084)

I was able to reproduce the issue on the 2.10 branch (commit c8fe42d). While I'm not positive that the stacktrace above stems from the same root cause, it could be one explanation.

Failing unit test

   public void testQuads() {
        Random r = new Random(42);
        ByteQuadsCanonicalizer root = ByteQuadsCanonicalizer.createRoot();
        ByteQuadsCanonicalizer canon = root.makeChild(JsonFactory.Feature.collectDefaults());

        int n_collisions = 25;
        int[] collisions = new int[n_collisions];

        // generate collisions
        {
            int maybe = r.nextInt();
            int hash = canon.calcHash(maybe);
            int target = ((hash & (2048-1)) << 2);

            for(int i = 0; i < collisions.length; ) {
                maybe = r.nextInt();
                hash = canon.calcHash(maybe);
                int offset = ((hash & (2048-1)) << 2);

                if(offset == target) {
                    collisions[i++] = maybe;
                }
            }
        }

        // fill spillover area until _needRehash is true.
        for(int i = 0; i < 22 ; i++) {
            canon.addName(Integer.toString(i), collisions[i]);
        }
        // canon._needRehash is now true, since the spillover is full

        // release table to update tableinfo with canon's data
        canon.release();

        // new table pulls data from new tableinfo, that has a full spillover, but set _needRehash to false
        canon = root.makeChild(JsonFactory.Feature.collectDefaults());

        // canon._needRehash == false, so this will try to add another item to the spillover area, even though it is full
        canon.addName(Integer.toString(22), collisions[22]);
    }

Stacktrace

java.lang.ArrayIndexOutOfBoundsException: 512
        at com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer.addName(ByteQuadsCanonicalizer.java:767)
        at com.fasterxml.jackson.core.sym.TestHashCollisionChars.testQuads(TestHashCollisionChars.java:121)

Suggested Fix

_verifyNeedForRehash() should return true if the spillover area is full, even if the hash table is less than 50% full.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions