You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Path canonicalization strips only one trailing separator: "/home/user/a//" stays "/home/user/a/" and IsChildOf("/home/user/a") returns true #308
SemanticPath.MakeCanonical removes at most one trailing directory separator. A path written with a doubled trailing separator keeps one, so it is not equal to the same directory written without it. The containment check then treats it as a child of itself.
Where
Semantics.Paths/SemanticPath.cs:118-147: if (canonical.EndsWith(separator) && …) canonical = canonical[..^separator.Length];. This runs once and does not loop. The XML doc above it says "Removes trailing directory separators".
These were reproduced against the built library on Linux, .NET 10:
vara=AbsoluteDirectoryPath.Create("/home/user/a//");// canonical: "/home/user/a/"varb=AbsoluteDirectoryPath.Create("/home/user/a");// canonical: "/home/user/a"a==b// falsea.IsChildOf(b)// true: a directory reported as inside itself
Doubled separators are common in paths built by string concatenation (dir + "/" + sub where dir already ends in /). Code that uses IsChildOf to guard against acting on the root of a tree, or to detect recursion, gets the wrong answer.
Suggested fix
In MakeCanonical, trim all trailing separators, stopping at the root (/ or C:\). For example, TrimEnd(separator) and then restore the root if the result became empty or C:.
Optionally, make PathContainment ignore a trailing separator on the child before comparing lengths, so it is robust on its own.
Add tests: "/a//" equals "/a", IsChildOf is false for that pair, and "//" still canonicalizes to the root.
Priority: Medium. "/a//" is not equal to "/a", and IsChildOf reports a directory as inside itself. Doubled separators are common in paths built by concatenation, and IsChildOf is typically used as a safety guard (root protection, recursion detection).
Area / suggested assignee:Semantics.Paths/SemanticPath.csMakeCanonical, and Utilities/PathContainment.cs. @matt-edmondson.
Notes: When trimming, preserve the root (/, C:\). Making PathContainment ignore a trailing separator on the child as well is worthwhile defence in depth.
Activity
matt-edmondson commentedon Sep 28, 2026
Triage
"/a//"is not equal to"/a", andIsChildOfreports a directory as inside itself. Doubled separators are common in paths built by concatenation, andIsChildOfis typically used as a safety guard (root protection, recursion detection).Semantics.Paths/SemanticPath.csMakeCanonical, andUtilities/PathContainment.cs. @matt-edmondson.RelativeDirectoryPath.Normalizedrops a leading..), which is also in path canonicalization./,C:\). MakingPathContainmentignore a trailing separator on the child as well is worthwhile defence in depth.Generated by Claude Code
[patch] Strip every trailing separator when canonicalizing a path