Skip to content

Keep ExtensionDiscovery::sort() consistent for extensions under unknown profile directories - #1035

Closed
mglaman wants to merge 1 commit into
mainfrom
audit/1c-latent-fixes
Closed

Keep ExtensionDiscovery::sort() consistent for extensions under unknown profile directories#1035
mglaman wants to merge 1 commit into
mainfrom
audit/1c-latent-fixes

Conversation

@mglaman

@mglaman mglaman commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Part 4 of 10 in the legacy-code audit stack (on top of #1034). Hardening in ExtensionDiscovery::sort(), split out of the original latent-fixes PR so it can be reviewed on its own. The remaining dead-code cleanups moved to the next PR in the stack.

What changed

An extension under a profiles/ directory that does not match any known profile directory fell through the else branch in sort() without a matching entry in the $origins and $profiles arrays. array_multisort() then threw ValueError: Array sizes are inconsistent. The extension now gets ORIGIN_PROFILE with no profile weight, so every key is present in both arrays.

Is this reachable?

Not through scan() today. filterByProfileDirectories() runs first and drops the same extensions using the same predicate, so users cannot hit this in practice. sort() is protected on a non-final class, though, and it should not depend on a sibling method having already filtered its input. Reviewed as hardening, not as a user-visible crash fix. No release note needed.

Testing

New ExtensionDiscoveryTest calls sort() through a subclass with an extension under an unknown profile directory. It fails on main with the ValueError and passes with this change. Full suite, self-analysis, and phpcs are green.

🤖 Generated with Claude Code

@mglaman
mglaman force-pushed the audit/1b-include-hardening branch from 5bc7d7d to a178ab7 Compare August 5, 2026 17:15
@mglaman
mglaman force-pushed the audit/1c-latent-fixes branch from bd2e6fc to 8c90f35 Compare August 5, 2026 17:15
@mglaman
mglaman force-pushed the audit/1b-include-hardening branch from a178ab7 to 20e6baf Compare August 5, 2026 19:13
@mglaman
mglaman force-pushed the audit/1c-latent-fixes branch from 8c90f35 to 33d7c0f Compare August 5, 2026 19:13
Base automatically changed from audit/1b-include-hardening to main August 5, 2026 19:33
@mglaman
mglaman force-pushed the audit/1c-latent-fixes branch from 33d7c0f to f7189dd Compare August 5, 2026 19:33
@mglaman
mglaman marked this pull request as ready for review August 5, 2026 19:34
…wn profile directories

Extensions under a profiles/ directory that does not match a known profile
left holes in the origins and profiles arrays, so array_multisort() threw a
ValueError on unequal sizes. scan() filters these out before sorting, but
sort() is protected and must not rely on that.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@mglaman
mglaman force-pushed the audit/1c-latent-fixes branch from f7189dd to 8e322eb Compare September 8, 2026 17:42
@mglaman mglaman changed the title Fix latent bugs surfaced by the legacy-code audit Keep ExtensionDiscovery::sort() consistent for extensions under unknown profile directories Sep 8, 2026
@mglaman

mglaman commented Sep 8, 2026

Copy link
Copy Markdown
Owner Author

Closing without merging.

This class is a copy of \Drupal\Core\Extension\ExtensionDiscovery with the bootstrap dependencies removed. Core's sort() has the same fall-through in its else branch, and in both core and this copy filterByProfileDirectories() runs first with the same predicate, so no caller can reach it through scan(). Patching it here would invent a precedence for unmatched profile extensions that core does not define and make every future re-sync carry the divergence. Keeping parity with core is the smaller change.

Review findings on this PR turned up two real quirks in our own code, neither user-visible: the profile directory list in DrupalAutoloader is keyed by profile name so sort() weights are strings, and the constructor's default profile directory is an absolute path that can never match. Both are tracked as follow-ups outside this stack.

The dead-code cleanups that were split out of this PR continue in #1042, now rebased directly onto main.

@mglaman mglaman closed this Sep 8, 2026
@mglaman
mglaman deleted the audit/1c-latent-fixes branch September 9, 2026 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant