Skip to content

parseJSON with originTracking enabled creates broken offset/length information if the input exceeds 1024 characters #2633

@urbanfly

Description

@urbanfly

Describe the bug

When certain JSON data is parsed into an ADT, it fails with an error about length should be positive while constructing the SourceLocation.

To Reproduce

Run the following test using Rascal v0.41.2 (bundled with the Rascal VS Code extension v0.130)

data OuterData = outer(str name, str \type, list[Nested] nested_abc);
data Nested = nested(str \type, map[str, value] property__1, map[value, value] property__2);

test bool failsOnCertainJSON() {
    str input = "{
                '  \"name\": \"TESTING Adding one more character to this data causes the test to fail\",
                '  \"type\": \"type_abcd\",
                '  \"nested_abc\": [
                '    {
                '      \"type\": \"line\",
                '      \"property__1\": { \"y\": { \"value\": 2, \"absolute\": false } },
                '      \"property__2\": {}
                '    },
                '    {
                '      \"type\": \"line\",
                '      \"property__1\": { \"y\": { \"value\": 2, \"absolute\": false } },
                '      \"property__2\": {}
                '    },
                '    {
                '      \"type\": \"line\",
                '      \"property__1\": { \"y\": { \"value\": 2, \"absolute\": false } },
                '      \"property__2\": {}
                '    },
                '    {
                '      \"type\": \"line\",
                '      \"property__1\": { \"y\": { \"value\": 2, \"absolute\": false } },
                '      \"property__2\": {}
                '    },
                '    {
                '      \"type\": \"line\",
                '      \"property__1\": { \"y\": { \"value\": 2, \"absolute\": false } },
                '      \"property__2\": {}
                '    },
                '    {
                '      \"type\": \"line\",
                '      \"property__1\": { \"y\": { \"value\": 2, \"absolute\": false } },
                '      \"property__2\": {}
                '    },
                '    {
                '      \"type\": \"line\",
                '      \"property__1\": { \"y\": { \"value\": 2, \"absolute\": false } },
                '      \"property__2\": {}
                '    }
                '  ]
                '}
                '";

    // Works on any (?) data
    parsedMap = parseJSON(#map[str, value], input);
    println("Parsed JSON (Before)");
    iprintln(parsedMap);

    // Works with the data as-is
    parsedVFD = parseJSON(#OuterData, input);
    println("Parsed VisualFormData (Before)");
    iprintln(parsedVFD);

    // Insert a character in the string to test the boundary condition
    input = replaceFirst(input, "TESTING", "TESTING_");

    // Still works (expected)
    parsedMap = parseJSON(#map[str, value], input);
    println("Parsed JSON (After)");
    iprintln(parsedMap);

    // Fails when the original data above is increased by even one character (e.g. the name, or changing a 2 to 20, or even adding a meaningless space anywhere)
    parsedVFD = parseJSON(#OuterData, input);
    println("Parsed VisualFormData (After)");
    iprintln(parsedVFD);

    return true;
}

Expected behavior

The JSON is parsed into the ADT, obviously :)

Stack traces

Java("IllegalArgumentException","length should be positive")
 at io.usethesource.vallang.impl.primitive.SourceLocationValues.newSourceLocation(|unknown:///SourceLocationValues.java|(0,0,<58,0>,<58,0>))
 at io.usethesource.vallang.impl.primitive.AbstractPrimitiveValueFactory.sourceLocation(|unknown:///AbstractPrimitiveValueFactory.java|(0,0,<211,0>,<211,0>))
 at io.usethesource.vallang.impl.fields.AbstractValueFactoryAdapter.sourceLocation(|unknown:///AbstractValueFactoryAdapter.java|(0,0,<177,0>,<177,0>))
 at org.rascalmpl.library.lang.json.internal.JsonValueReader$ExpectedTypeDispatcher.visitObjectAsAbstractData(|unknown:///JsonValueReader.java|(0,0,<693,0>,<693,0>))
 at org.rascalmpl.library.lang.json.internal.JsonValueReader$ExpectedTypeDispatcher.visitAbstractData(|unknown:///JsonValueReader.java|(0,0,<718,0>,<718,0>))
 at org.rascalmpl.library.lang.json.internal.JsonValueReader$ExpectedTypeDispatcher.visitAbstractData(|unknown:///JsonValueReader.java|(0,0,<76,0>,<76,0>))
 at io.usethesource.vallang.type.AbstractDataType.accept(|unknown:///AbstractDataType.java|(0,0,<418,0>,<418,0>))
 at org.rascalmpl.library.lang.json.internal.JsonValueReader$ExpectedTypeDispatcher.visitList(|unknown:///JsonValueReader.java|(0,0,<845,0>,<845,0>))
 at org.rascalmpl.library.lang.json.internal.JsonValueReader$ExpectedTypeDispatcher.visitList(|unknown:///JsonValueReader.java|(0,0,<76,0>,<76,0>))
 at io.usethesource.vallang.type.ListType.accept(|unknown:///ListType.java|(0,0,<240,0>,<240,0>))
 at org.rascalmpl.library.lang.json.internal.JsonValueReader$ExpectedTypeDispatcher.visitObjectAsAbstractData(|unknown:///JsonValueReader.java|(0,0,<637,0>,<637,0>))
 at org.rascalmpl.library.lang.json.internal.JsonValueReader$ExpectedTypeDispatcher.visitAbstractData(|unknown:///JsonValueReader.java|(0,0,<718,0>,<718,0>))
 at org.rascalmpl.library.lang.json.internal.JsonValueReader$ExpectedTypeDispatcher.visitAbstractData(|unknown:///JsonValueReader.java|(0,0,<76,0>,<76,0>))
 at io.usethesource.vallang.type.AbstractDataType.accept(|unknown:///AbstractDataType.java|(0,0,<418,0>,<418,0>))
 at org.rascalmpl.library.lang.json.internal.JsonValueReader.read(|unknown:///JsonValueReader.java|(0,0,<1028,0>,<1028,0>))
 at org.rascalmpl.library.lang.json.IO.parseJSON(|unknown:///IO.java|(0,0,<103,0>,<103,0>))
 at parseJSON(|std:///lang/json/IO.rsc|(7724,5,<138,27>,<138,32>))

Additional context

This test passes with Rascal v0.40.x (bundled with VS Code ext. v0.12.2)

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions