Skip to content

Conversation

@hasufell
Copy link
Member

@hasufell hasufell commented Jan 29, 2026

When passing a path like "F:/foo/bar" on windows
(both '/' and '\' are valid path separators on windows) we'll get garbage output like so:

mkPathNative "F:/foo/bar"
"F:/foo/bar"
unPathNative "F:/foo/bar"
"F:foo\bar"

...effectively turning an absolute path into a relative path ("F:foo\bar" on windows is the directory "foo\bar" relative to the current working directory on drive F).

This is because Posix and Windows splitDirectories behave differently:

System.FilePath.Posix.splitDirectories $ "F:/foo/bar"
["F:","foo","bar"]
System.FilePath.Windows.splitDirectories $ "F:/foo/bar"
["F:/","foo","bar"]

When joining paths on windows, the filepath library does not assume a trailing path separator after the drive (here "F:"). This is because as described above, "F:foo" is a valid relative filepath.

When passing a path like "F:/foo/bar" on windows
(both '/' and '\' are valid path separators on windows)
we'll get garbage output like so:

> mkPathNative "F:/foo/bar"
"F:/foo/bar"
> unPathNative "F:/foo/bar"
"F:foo\\bar"

...effectively turning an absolute path into a relative path
("F:foo\\bar" on windows is the directory "foo\\bar"
relative to the current working directory on drive F).

This is because Posix and Windows splitDirectories behave differently:

> System.FilePath.Posix.splitDirectories $ "F:/foo/bar"
["F:","foo","bar"]
> System.FilePath.Windows.splitDirectories $ "F:/foo/bar"
["F:/","foo","bar"]

When joining paths on windows, the filepath library does not
assume a trailing path separator after the drive (here "F:").
This is because as described above, "F:foo" is valid relative
filepath.
@hasufell
Copy link
Member Author

hasufell commented Jan 29, 2026

To trigger the bug on windows: cabal --remote-repo-cache F:/build/packages update.

Resulting in:

Exception fromAbsoluteFilePath: not an absolute path:
F:build\packages\hackage.haskell.org\rooC8E3.json
CallStack (from HasCallStack):
error, called at src\Hackage\Security\Util\Path.hs:279:31 in
hackage-security-0.6.2.6-inplace:Hackage.Security.Util.Path when using mirror
http://hackage.haskell.org/

@hasufell
Copy link
Member Author

Discussion:

  • please don't use these splitPath/joinPath tricks... they're not there to do proper normalization
  • my patch drops the implicit semi-normalization (we just replace the path separators now)... that means there may be duplicate path separators... I think that's ok, but someone more familiar with the codebase would have to double check whether the code anywhere assumes that there are no duplicate path separators
  • if we really want normalisation, then we need to normalise first and THEN replace the path separators with forward slashes

@hasufell
Copy link
Member Author

@andreabedini ran into this bug while working on stable-haskell/ghc#135

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