Skip to content

openapi: circular \$ref and recursive YAML anchors crash the compiler with a fatal stack overflow #12

Description

@OmarAlJarrah

Summary

Compiling a document whose schema graph contains a reference cycle with no concrete node — a schema that $refs itself, a $ref cycle A → B → A, or a self-referential YAML anchor — sends the loader into unbounded recursion and the process dies with fatal error: stack overflow (exit 2). Because a stack overflow is a Go runtime fatal error rather than a recoverable panic, the loader's recover cannot trap it, so the crash escapes to the caller.

Legitimate recursive schemas (a property that $refs its enclosing schema, e.g. a linked-list Node) compile correctly — only degenerate cycles that never reach a concrete schema node crash.

A related, less severe case in the same area: a whitespace-only document makes the parser panic with unknown node kind. That one is a recoverable panic and is straightforward to trap; it is included here because it belongs to the same "loader must survive degenerate input" concern.

Reproduction

Each of these crashes the compiler with fatal error: stack overflow:

Self-reference:

openapi: 3.1.0
info: {title: t, version: '1'}
paths: {}
components:
  schemas:
    A:
      $ref: '#/components/schemas/A'

Recursive YAML anchor:

openapi: 3.1.0
info: {title: t, version: '1'}
paths: {}
x-a: &a [*a]

Root cause

Reference resolution (compilers/openapi/load.go, around the ResolveAllReferences call) and the underlying YAML/reference walk traverse the reference/anchor graph without a visited-set or depth bound, so a cycle recurses until the goroutine stack is exhausted. The loader's recover only wraps the initial unmarshal, and a fatal stack overflow is not recoverable in any case.

Expected

The compiler must never crash the process on any parseable input. A reference or anchor cycle should be detected before or during resolution and reported as an unresolved/cyclic-reference diagnostic, leaving the rest of the pipeline to continue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions