Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os.stat handle leak #73920

Closed
eryksun opened this issue Mar 6, 2017 · 7 comments
Closed

os.stat handle leak #73920

eryksun opened this issue Mar 6, 2017 · 7 comments
Labels
3.7 (EOL) end of life 3.8 only security fixes extension-modules C modules in the Modules dir OS-windows type-bug An unexpected behavior, bug, or error

Comments

@eryksun
Copy link
Contributor

eryksun commented Mar 6, 2017

BPO 29734
Nosy @pfmoore, @tjguk, @berkerpeksag, @zware, @eryksun, @zooba, @miss-islington
PRs
  • bpo-29734: nt._getfinalpathname handle leak #740
  • [3.7] bpo-29734: nt._getfinalpathname handle leak (GH-740) #11740
  • [3.7] bpo-29734: nt._getfinalpathname handle leak (GH-740) #11740
  • bpo-29734: Cleanup test_getfinalpathname_handles test #12908
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2019-02-02.21:17:48.937>
    created_at = <Date 2017-03-06.11:26:57.668>
    labels = ['extension-modules', '3.8', 'type-bug', '3.7', 'OS-windows']
    title = 'os.stat handle leak'
    updated_at = <Date 2019-04-22.15:46:50.476>
    user = 'https://github.com/eryksun'

    bugs.python.org fields:

    activity = <Date 2019-04-22.15:46:50.476>
    actor = 'berker.peksag'
    assignee = 'none'
    closed = True
    closed_date = <Date 2019-02-02.21:17:48.937>
    closer = 'steve.dower'
    components = ['Extension Modules', 'Windows']
    creation = <Date 2017-03-06.11:26:57.668>
    creator = 'eryksun'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 29734
    keywords = ['patch', 'patch']
    message_count = 7.0
    messages = ['289095', '333511', '334767', '334768', '334769', '334770', '340658']
    nosy_count = 7.0
    nosy_names = ['paul.moore', 'tim.golden', 'berker.peksag', 'zach.ware', 'eryksun', 'steve.dower', 'miss-islington']
    pr_nums = ['740', '11740', '11740', '12908']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue29734'
    versions = ['Python 3.7', 'Python 3.8']

    @eryksun
    Copy link
    Contributor Author

    eryksun commented Mar 6, 2017

    The implementation of nt._getfinalpathname leaks a File handle if calling GetFinalPathNameByHandle fails. The latter function is practically guaranteed to fail when resolving the path for a non-file-system device. It also fails when VOLUME_NAME_DOS is requested for a volume GUID path that isn't currently mounted as either a DOS drive letter or an NTFS junction. In this case requesting VOLUME_NAME_GUID should work.

    For example, when I try calling _getfinalpathname to resolve the device paths \\?\MAILSLOT, \\?\PIPE, \\?\UNC, \\?\C:, \\?\PhysicalDrive0, \\?\NUL, \\?\CONIN$, and \\?\COM1, I get the following list of leaked handles:

      0x168 File                  \Device\Mailslot
      0x16c File                  \Device\NamedPipe
      0x178 File                  \Device\Mup
      0x17c File                  \Device\HarddiskVolume2
      0x180 File                  \Device\Harddisk0\DR0
      0x18c File                  \Device\Null
      0x194 File                  \Device\ConDrv
      0x198 File                  \Device\Serial0
    

    (The above is from a context manager that checks for leaked handles using ctypes to call the PssCaptureSnapshot API, which was introduced in Windows 8.1. I think Process Snapshotting is the only Windows API that uses the kernel's ability to fork a clone of a process.)

    The reason that GetFinalPathNameByHandle fails in these cases is that the information classes it queries are typically only serviced by file systems. Other I/O devices (e.g. disk and volume devices) will fail these I/O requests. It happens that GetFinalPathNameByHandle starts with an NtQueryObject request that succeeds in these cases (it's the source of the above native NT device names), but it doesn't stop there. It continues requesting information from the device and the mount-point manager until it either has everything or a request fails.

    Also, in os__getfinalpathname_impl, I notice that it's switching from VOLUME_NAME_NT in the first call that's used to get the buffer size to VOLUME_NAME_DOS in the second call. It should use VOLUME_NAME_DOS in both cases, or better yet, add a keyword-only argument to select a different volume-name style (i.e. None, DOS, GUID, or NT).

    @eryksun eryksun added 3.7 (EOL) end of life extension-modules C modules in the Modules dir OS-windows type-bug An unexpected behavior, bug, or error labels Mar 6, 2017
    @eryksun
    Copy link
    Contributor Author

    eryksun commented Jan 12, 2019

    The os__getfinalpathname_impl handle leak and VOLUME_NAME_NT problems were fixed in another issue. However, PR 740 also includes fixes for handle leaks in os.stat, specifically in win32_xstat_impl and get_target_path.

    @eryksun eryksun added the 3.8 only security fixes label Jan 12, 2019
    @eryksun eryksun changed the title nt._getfinalpathname handle leak os.stat handle leak Jan 12, 2019
    @eryksun
    Copy link
    Contributor Author

    eryksun commented Feb 2, 2019

    Steve, can you review and merge PR 740? Mark updated it to fix the handle leaks in win32_xstat_impl as mentioned in my previous message. They're unlikely but still should be fixed. In particular, iIt's unlikely that win32_get_reparse_tag (i.e. FSCTL_GET_REPARSE_POINT) will fail, but not quite as unlikely that get_target_path (i.e. GetFinalPathNameByHandleW) will fail (e.g. it will fail if the target is on an ImDisk ramdisk).

    @zooba
    Copy link
    Member

    zooba commented Feb 2, 2019

    We certainly shouldn't be calling CloseHandle on a parameter like this anyway, so the change looks good to me.

    However, I notice that we don't necessarily preserve GetLastError() throughout here, so perhaps we ought to consider changing the return value interpretation at some point? (e.g. CloseHandle() may change it, and so we lose the actual error) That can be a future task though.

    @zooba
    Copy link
    Member

    zooba commented Feb 2, 2019

    New changeset b82bfac by Steve Dower (Mark Becwar) in branch 'master':
    bpo-29734: nt._getfinalpathname handle leak (GH-740)
    b82bfac

    @zooba zooba closed this as completed Feb 2, 2019
    @miss-islington
    Copy link
    Contributor

    New changeset 63a69ef by Miss Islington (bot) in branch '3.7':
    bpo-29734: nt._getfinalpathname handle leak (GH-740)
    63a69ef

    @berkerpeksag
    Copy link
    Member

    New changeset 6ef726a by Berker Peksag in branch 'master':
    bpo-29734: Cleanup test_getfinalpathname_handles test (GH-12908)
    6ef726a

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life 3.8 only security fixes extension-modules C modules in the Modules dir OS-windows type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    4 participants