GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — ntpath.realpath() mishandles filenames that resemble drives · Issue #102475 · python/cpython

ntpath.realpath() mishandles filenames that resemble drives #102475

New issue
Copy link
New issue
Copy link
Closed
Closed
ntpath.realpath() mishandles filenames that resemble drives#102475
Copy link
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixes3.16new features, bugs and security fixesnew features, bugs and security fixesOS-windowsstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@barneygale
barneygale
opened on Mar 6, 2023
Issue body actions

The realpath() docs say:

If strict is False, the path is resolved as far as possible and any remainder is appended without checking whether it exists.

Note the word "appended". In fact, realpath() uses os.path.join() to join the path segments, and as we all know/love, os.path.join() supports resetting the drive or root, thus discarding prior parts. As a result:

>>> os.path.realpath('c:/a:b')
'a:b'  # should be 'c:/a:b'

Linked PRs

  • gh-102475: Fix os.path.realpath() for names which look like a drive #155399
  • [3.15] gh-102475: Fix os.path.realpath() for names which look like a drive (GH-155399) #156593
  • [3.14] gh-102475: Fix os.path.realpath() for names which look like a drive (GH-155399) #156594
  • [3.13] gh-102475: Fix os.path.realpath() for names which look like a drive (GH-155399) #156595

Activity

Next
  1. barneygale
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    OS-windows
    3.11only security fixesonly security fixes
    3.10 (EOL)end of lifeend of life
    3.12only security fixesonly security fixes
    on Mar 6, 2023
  2. barneygale
    added a commit that references this issue on Mar 6, 2023

    Remove test case affected by pythonGH-102475.

    e6f11d4
  3. kostyafarber commented on Mar 18, 2023

    @kostyafarber
    kostyafarber
    on Mar 18, 2023
    Contributor
    More actions

    Any ideas on how to go about fixing this one? Keen to work on it but it seems (with regards to the linked issue) there are other things related to those to sort out first?

  4. barneygale commented on Mar 19, 2023

    @barneygale
    barneygale
    on Mar 19, 2023
    ContributorAuthor
    More actions

    Thanks for taking a look!

    Essentially: ntpath.realpath() should not call ntpath.join() internally. Instead, it should use a more naive form of joining, like sep.join() or simply head + sep + tail. Care must be taken not to double up slashes. A small utility function may be warranted.

    I suspect the main problematic case is here:

    cpython/Lib/ntpath.py

    Line 697 in ccb5af7

    tail = join(name, tail) if tail else name

    ... but there are other usages of join() which will need some thought.

    Reacted by Kostya Farber and Serhiy Storchaka
  5. kostyafarber commented on Mar 19, 2023

    @kostyafarber
    kostyafarber
    on Mar 19, 2023
    Contributor
    More actions

    Thanks for the detailed explanation. I'll have a go at it.

    Reacted by Barney Gale
  6. eryksun commented on Mar 19, 2023

    @eryksun
    eryksun
    on Mar 19, 2023
    Contributor
    More actions

    Any ideas on how to go about fixing this one?

    Define a custom join() function inside of ntpath._getfinalpathname_nonstrict(). It can be simplified since it only joins two paths, the second of which is a simple relative path. For example:

            if isinstance(path, bytes):        
                tail = b''
                sep = b'\\'
            else:
                tail = ''
                sep = '\\'
    
            def join(path, tail):
                if path[-1:] == sep or not tail:
                    return path + tail
                return path + sep + tail

    Use this function for all of the four join() calls in _getfinalpathname_nonstrict().

    Reacted by Barney Gale and Kostya Farber
  7. eryksun commented on Mar 19, 2023

    @eryksun
    eryksun
    on Mar 19, 2023
    Contributor
    More actions

    Use this function for all of the four join() calls in _getfinalpathname_nonstrict().

    I said four join() calls instead of 3 because I was counting the following as well:

    cpython/Lib/ntpath.py

    Lines 695 to 696 in 4d1f033

    if path and not name:
    return path + tail

    The working directory on a non-existing drive should be the root path. For example, the following result is wrong:

    >>> ntpath.exists('Z:')
    False
    >>> ntpath.realpath('Z:spam')
    'Z:spam'
  8. barneygale commented on Mar 19, 2023

    @barneygale
    barneygale
    on Mar 19, 2023
    ContributorAuthor
    More actions

    Eryk, is that function necessary in all four cases? I wonder if we can guarantee that path does or does not end with a separator in any of them.

  9. kostyafarber commented on Mar 19, 2023

    @kostyafarber
    kostyafarber
    on Mar 19, 2023
    Contributor
    More actions

    Any ideas on how to go about fixing this one?

    Define a custom join() function inside of ntpath._getfinalpathname_nonstrict(). It can be simplified since it only joins two paths, the second of which is a simple relative path. For example:

            if isinstance(path, bytes):        
    
                tail = b''
    
                sep = b'\\'
    
            else:
    
                tail = ''
    
                sep = '\\'
    
    
    
            def join(path, tail):
    
                if path[-1:] == sep or not tail:
    
                    return path + tail
    
                return path + sep + tail

    Use this function for all of the four join() calls in _getfinalpathname_nonstrict().

    You've done all the work for me!

  10. eryksun commented on Mar 19, 2023

    @eryksun
    eryksun
    on Mar 19, 2023
    Contributor
    More actions

    The issue also needs tests in "Lib/test_ntpath.py".

    is that function necessary in all four cases? I wonder if we can guarantee that path does or does not end with a separator in any of them.

    The result from nt._getfinalpathname() or nt.readlink() may or may not end with a separator. For prepending to tail, since name comes from ntpath.split(), it should never contain a backslash. However, tail could be empty, so we would need tail = (name + sep + tail) if tail else name, as opposed to tail = join(name, tail). I'd rather keep the check for an empty tail in join().

    Reacted by Barney Gale
  11. johns1c commented on Sep 13, 2023

    @johns1c
    johns1c
    on Sep 13, 2023
    More actions

    Is os.path.join just wrong?

    Is there a proper definition of a "canonical" path for Windows?

    If not should the Python community create a definition? It will have to takes account of namespaces, drive letters, mount points, case sensitivity etc .

    I think that one rule should be that If p2 is the result os.path.realpath( p1 ) then if a thing exists or can be created using path p2 it will be the same as that created / accessed via path p1.

    I also think that os.path.realpath( 'c:/aa.b' ) should give a similar result to os.path.realpath( 'c:/a.b' )

    p.s. see also some of the comments on issue #100162

  12. 3 remaining items

  13. serhiy-storchaka
    added
    3.13only security fixesonly security fixes
    3.14bugs and security fixesbugs and security fixes
    3.15bugs and security fixesbugs and security fixes
    3.16new features, bugs and security fixesnew features, bugs and security fixes
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    and removed
    3.10 (EOL)end of lifeend of life
    3.11only security fixesonly security fixes
    3.12only security fixesonly security fixes
    on Aug 8, 2026
  14. serhiy-storchaka
    added a commit that references this issue on Aug 29, 2026

    gh-102475: Fix os.path.realpath() for names which look like a drive (G…

    0c38e05
  15. serhiy-storchaka
    closed this as completedon Aug 29, 2026
  16. github-project-automation
    moved this from Todo to Done in OS issues 💻on Aug 29, 2026
  17. serhiy-storchaka
    added 2 commits that reference this issue on Aug 29, 2026

    [3.13] gh-102475: Fix os.path.realpath() for names which look like a …

    34573c1

    [3.14] gh-102475: Fix os.path.realpath() for names which look like a …

    162c47c
  18. clin1234
    added a commit that references this issue on Sep 12, 2026

    pythongh-102475: Fix os.path.realpath() for names which look like a d…

    3b3db2b
  19. serhiy-storchaka
    added a commit that references this issue on Oct 10, 2026

    [3.15] gh-102475: Fix os.path.realpath() for names which look like a …

    6531b40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixes3.16new features, bugs and security fixesnew features, bugs and security fixesOS-windowsstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    • OS issues 💻
      Status
      Done
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.