Skip to content

descriptor: enforce import visibility when linking a DescriptorPool - #428

Merged
iainmcgin merged 3 commits into
mainfrom
iain/pool-import-visibility
Sep 8, 2026
Merged

iainmcgin merged 3 commits into
mainfrom
iain/pool-import-visibility

Conversation

@iainmcgin

@iainmcgin iainmcgin commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

DescriptorPool resolved every type_name, extendee and method input/output type against one flat table of everything in the pool, so b.proto could use .a.Thing without importing a.proto and the set linked. protoc rejects that: a file sees itself, its dependency list, and whatever those re-export through import public, and nothing else.

The pool now records each message's and enum's defining file at registration, computes each new file's visible set before linking (direct and weak dependencies, then the transitive public_dependency closure, across files already in the pool and files in the set being added), and checks it at every resolve site. A reference outside the set is the new PoolError::TypeNotImported, whose message names the file to add to dependency.

A dependency that is not in the pool is still tolerated by default, so sets that strip option-only imports (google/api/annotations.proto) keep loading; only a reference into a missing or unimported file fails. LinkOptions, passed through the new DescriptorPool::decode_with_link_options or with_link_options, turns enforcement off (with_import_visibility(false)) or additionally requires every listed non-weak dependency to be present (with_required_dependencies(true)PoolError::DependencyNotFound). Two files with the same name in one set, which previously shadowed each other in the filename index, are now PoolError::DuplicateFileName.

Sets from protoc --include_imports, buf build, and codegen's embedded FILE_DESCRIPTOR_SET_BYTES carry intact dependency lists and are unaffected. Breaking for hand-built FileDescriptorProtos that reference another file without listing it, hence 0.10.0.

Closes #423.

A type_name, extendee, or method input/output type must resolve to a
definition in the referring file, a file in its dependency list, or a file
those re-export through import public; anything else is
PoolError::NotImported, matching protoc. Each message and enum records its
defining file at registration, each new file's visible set is computed once
(direct and weak deps, then the transitive public_dependency closure, across
files already in the pool and files in the set being added), and every
resolve site checks it. LinkOptions (via DescriptorPool::with_link_options)
can switch enforcement off or additionally require every listed dependency
to be present (PoolError::ImportNotFound); by default an absent, unreferenced
import is tolerated so sets that strip option-only imports still load.

Closes #423.
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

- LinkOptions follows DecodeOptions' shape: private fields, with_* setters,
  getters; DescriptorPool::decode_with_link_options is the one-call form.
- Visible sets are built per file and per pass instead of tabulated for the
  whole batch (a public-import chain made the table quadratic in the file
  count on untrusted input).
- Variants renamed TypeNotImported / DependencyNotFound; Display names the
  fix; filenames print bare like their neighbours. New DuplicateFileName
  for two same-named files in one set, which previously shadowed silently.
- Missing weak dependencies are exempt from required_dependencies, as under
  protoc.
- Docs: LinkOptions no longer steals DescriptorPool's summary line;
  add_file_descriptor_set states the cross-set rule; guide example;
  crate-root module list mentions pool/reflect; generated descriptor_pool()
  expect message says linkable.
- Tests: enum-typed cross-file reference, reference into an absent import
  (UnresolvedTypeName), weak exemption, decode_with_link_options,
  duplicate file names.
The hand-built set referenced .alpha.v1.Alpha from beta.proto without a
dependency entry, which the pool now rejects; the (cargo-spawning, ignored
by default) shared_pool_compile tests failed in CI on it.
@iainmcgin
iainmcgin marked this pull request as ready for review September 6, 2026 17:22
@iainmcgin
iainmcgin added this pull request to the merge queue Sep 8, 2026
Merged via the queue into main with commit 5725f63 Sep 8, 2026
11 checks passed
@iainmcgin
iainmcgin deleted the iain/pool-import-visibility branch September 8, 2026 15:28
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DescriptorPool resolves type names across the whole set, ignoring each file's import graph

2 participants