Skip to content

Resource.GetEObject recurses unboundedly on unresolvable fragments (StackOverflowException) #80

Description

@samatstariongroup

Context

Found while validating ECoreNetto 7.0.9 against the Eclipse Capella 7.0 metamodel for STARIONGROUP/capella4net#2. Reproduction harness: validation/EcoreValidation on the capella4net GH2 branch (run without --workarounds).

Problem

Resource.GetEObject(string) recurses unboundedly on any fragment it cannot resolve, killing the process with an uncatchable StackOverflowException:

Stack overflow.
   at ECoreNetto.Resource.Resource.GetEObject(System.String)
   at ECoreNetto.Resource.Resource.GetEObject(System.String)
   ... (thousands of frames)

Mechanism in 7.0.9: on a cache miss for a fragment whose file part contains .ecore, the method resolves the file part against its own directory, finds (or creates) the resource, and calls resource.GetEObject(uriFragment) with the unchanged fragment. If the target resource also misses its cache (see the file-name/package-name key mismatch issue) it re-derives the same resource — itself or a peer — and delegates again with the same input. Nothing ever changes between iterations, so it loops until the stack dies.

Two concrete triggers observed with the Capella metamodel:

  1. Self-delegation: B.GetEObject("B.ecore#//X") misses the cache, resolves B.ecore to itself, delegates to itself.
  2. Ping-pong via broken eOpposite fragments (EStructuralFeature::ctx.ecore#//SystemAnalysis/allocatingLogicalArchitectures, see the eOpposite issue).

Note: the development branch already guards resource == this (returns null), which covers trigger 1 but not delegation cycles between distinct resources, and 7.0.9 on NuGet has no guard at all.

Suggested direction

  • When delegating to another resource, strip the file part and pass the local fragment so the callee takes the cache path, not the delegation path.
  • Treat any delegation that would re-enter with an unchanged (resource, fragment) pair as unresolvable: record a Diagnostic and return null instead of recursing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions