Skip to content

Recursive Ref Causes "String index out of range" #141

@jawaff

Description

@jawaff

Version

I'm using 4.5.11 of the vertx-openapi library, which off course transitively depends on vertx-json-schema.

Context

I have openapi files that have $refs to separate json schema files (using draft 4 currently), which are provided to the OpenAPIContract::fromContract by way of the additionalContractFiles argument. That's kind of unrelated, but the important detail is that I have an OpenAPI file with a $ref to a schema that defines a tree structure. That tree schema for the sake of simplicity can be reduced to the following to cause an exception:

type: object
properties:
  children:
    type: array
      $ref: '#'

The exception in question is this:

Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: 0
	at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:47)
	at java.base/java.lang.String.charAt(String.java:693)
	at io.vertx.json.schema.impl.JsonRef.resolveUri(JsonRef.java:326)
	at io.vertx.json.schema.impl.JsonRef.resolve(JsonRef.java:211)
	at io.vertx.json.schema.impl.JsonRef.resolveUri(JsonRef.java:338)
	at io.vertx.json.schema.impl.JsonRef.resolve(JsonRef.java:211)
	at io.vertx.json.schema.impl.JsonRef.resolveUri(JsonRef.java:338)
	at io.vertx.json.schema.impl.JsonRef.resolve(JsonRef.java:211)
	at io.vertx.json.schema.impl.SchemaRepositoryImpl.resolve(SchemaRepositoryImpl.java:243)
	at io.vertx.openapi.contract.OpenAPIVersion.lambda$resolve$4(OpenAPIVersion.java:110)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$4(ContextImpl.java:192)
	at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:270)
	at io.vertx.core.impl.ContextImpl$1.execute(ContextImpl.java:221)
	at io.vertx.core.impl.WorkerTask.run(WorkerTask.java:56)
	at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:81)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)

Do you have a reproducer?

I do not have a reproducer, but the problem is pretty obvious if you look at the JsonRef::resolveUri function. There is no isEmpty check on the path before accessing the first character.

Steps to reproduce

Look at this if statement and try to tell me that there's a guarantee that path will always be nonempty. If you have a $ref: '#', then the parts array is going to initialized as ["#", ""] and you'll run into the exception above at the linked if statement because the second element is empty.

The temporary solution to fix this was to change my ref to $ref: '#/'. It provides the same behavior as the '#' by itself, but just the pound symbol should be supported and I'm not sure why the existing tests aren't triggering the same exception that I'm running into.

Solutions

There seems to be multiple solutions to fix this, but in the end a pound symbol by itself should just trigger anchors.get(prefix); in the end to retrieve the current schema. Both solutions below should result in the same behavior and both changes are to the JsonRef::resolveUri function.

Option 1:

We could make hashPresent set to false when the passed uri is "#".

    final boolean hashPresent = parts.length == 2 && parts[1] != null && !parts[1].isEmpty();

Option 2:

We could add a safety check before accessing the first character of the path.

    if (hashPresent && !path.isEmpty() && path.charAt(0) != '/') {

Extra

  • Anything that can be relevant such as OS version, JVM version

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions