Opened 22 months ago

Last modified 22 months ago

#34294 closed Bug

File locking fails if argtypes redefined — at Version 1

Reported by: Simon Sawicki Owned by: nobody
Component: File uploads/storage Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Simon Sawicki)

django.core.files.locks uses ctypes.windll.kernel32 which is a global instance. If other code redefines windll.kernel32.LockFileEx.argtypes the function fails with an error.

import ctypes
import ctypes.wintypes

from django.core.files import locks


class OVERLAPPED(ctypes.Structure):
    _fields_ = [
        ("Internal", ctypes.wintypes.LPVOID),
        ("InternalHigh", ctypes.wintypes.LPVOID),
        ("Offset", ctypes.wintypes.DWORD),
        ("OffsetHigh", ctypes.wintypes.DWORD),
        ("hEvent", ctypes.wintypes.HANDLE),
    ]


ctypes.windll.kernel32.LockFileEx.argtypes = [
    ctypes.wintypes.HANDLE,
    ctypes.wintypes.DWORD,
    ctypes.wintypes.DWORD,
    ctypes.wintypes.DWORD,
    ctypes.wintypes.DWORD,
    ctypes.wintypes.DWORD,
]

with open("./file", "w") as f:
    locks.lock(f, locks.LOCK_EX)

Possible patch:

  • django/core/files/locks.py

    diff --git a/django/core/files/locks.py b/django/core/files/locks.py
    index 5752b08a69..c0f471f87d 100644
    a b if os.name == "nt":  
    3232        POINTER,
    3333        Structure,
    3434        Union,
     35        WinDLL,
    3536        byref,
    3637        c_int64,
    3738        c_ulong,
    3839        c_void_p,
    3940        sizeof,
    40         windll,
    4141    )
    4242    from ctypes.wintypes import BOOL, DWORD, HANDLE
    4343
    if os.name == "nt":  
    7373    LPOVERLAPPED = POINTER(OVERLAPPED)
    7474
    7575    # --- Define function prototypes for extra safety ---
    76     LockFileEx = windll.kernel32.LockFileEx
     76    kernel32 = WinDLL("kernel32")
     77    LockFileEx = kernel32.LockFileEx
    7778    LockFileEx.restype = BOOL
    7879    LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED]
    79     UnlockFileEx = windll.kernel32.UnlockFileEx
     80    UnlockFileEx = kernel32.UnlockFileEx
    8081    UnlockFileEx.restype = BOOL
    8182    UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED]
    8283
  • tests/files/tests.py

    diff --git a/tests/files/tests.py b/tests/files/tests.py
    index b3478d2732..d0e633cb7a 100644
    a b class FileTests(unittest.TestCase):  
    200200            self.assertIs(locks.unlock(f1), True)
    201201            self.assertIs(locks.unlock(f2), True)
    202202
     203    @unittest.skipIf(os.name != "nt", "File locking usees WinDLL on windows only")     
     204    def test_local_windll(self):
     205        import ctypes
     206        import ctypes.wintypes
     207
     208        old_argtypes = ctypes.windll.kernel32.LockFileEx.argtypes
     209        try:
     210            ctypes.windll.kernel32.LockFileEx.argtypes = [
     211                ctypes.wintypes.HANDLE,
     212                ctypes.wintypes.DWORD,
     213                ctypes.wintypes.DWORD,
     214                ctypes.wintypes.DWORD,
     215                ctypes.wintypes.DWORD,
     216                ctypes.wintypes.DWORD,
     217            ]
     218            file_path = Path(__file__).parent / "test.png"
     219            with open(file_path) as file:
     220                try:
     221                    locks.lock(file, locks.LOCK_EX)
     222                except Exception:
     223                    self.fail("Locking raised exception with changed argtypes")
     224                else:
     225                    locks.unlock(file)
     226        finally:
     227            ctypes.windll.kernel32.LockFileEx.argtypes = old_argtypes
     228
    203229
    204230class NoNameFileTestCase(unittest.TestCase):
    205231    """

Change History (1)

comment:1 by Simon Sawicki, 22 months ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top