Skip to content

Commit

Permalink
pythongh-119690: Adds Unicode support for named pipes in _winapi
Browse files Browse the repository at this point in the history
  • Loading branch information
zooba committed May 29, 2024
1 parent cd11ff1 commit e8ff1cf
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 28 deletions.
11 changes: 11 additions & 0 deletions Lib/test/audit-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,17 @@ def hook(event, args):
sys.monitoring.register_callback(1, 1, None)


def test_winapi_createnamedpipe(pipe_name):
import _winapi

def hook(event, args):
if event == "_winapi.CreateNamedPipe":
print(event, args)

sys.addaudithook(hook)
_winapi.CreateNamedPipe(pipe_name, _winapi.PIPE_ACCESS_DUPLEX, 8, 2, 0, 0, 0, 0)


if __name__ == "__main__":
from test.support import suppress_msvcrt_asserts

Expand Down
14 changes: 14 additions & 0 deletions Lib/test/test_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,20 @@ def test_sys_monitoring_register_callback(self):

self.assertEqual(actual, expected)

def test_winapi_createnamedpipe(self):
winapi = import_helper.import_module("_winapi")

pipe_name = r"\\.\pipe\LOCAL\test_winapi_createnamed_pipe"
returncode, events, stderr = self.run_python("test_winapi_createnamedpipe", pipe_name)
if returncode:
self.fail(stderr)

if support.verbose:
print(*events, sep='\n')
actual = [(ev[0], ev[2]) for ev in events]
expected = [("_winapi.CreateNamedPipe", f"({pipe_name!r}, 3, 8)")]

self.assertEqual(actual, expected)

if __name__ == "__main__":
unittest.main()
34 changes: 34 additions & 0 deletions Lib/test/test_winapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,37 @@ def test_getshortpathname(self):

# Should contain "PROGRA~" but we can't predict the number
self.assertIsNotNone(re.match(r".\:\\PROGRA~\d", actual.upper()), actual)

def test_namedpipe(self):
# Deliberately complex name to flush out encoding errors
pipe_name = os.urandom(64).replace(b'\0', b'.').decode('latin-1')
pipe_name = rf"\\.\pipe\LOCAL\{pipe_name}"

# Pipe does not exist, so this raises
with self.assertRaises(FileNotFoundError):
_winapi.WaitNamedPipe(pipe_name, 0)

pipe = _winapi.CreateNamedPipe(
pipe_name,
_winapi.PIPE_ACCESS_DUPLEX,
8, # 8=PIPE_REJECT_REMOTE_CLIENTS
2, # two instances available
32, 32, 0, 0)
self.addCleanup(_winapi.CloseHandle, pipe)

# Pipe instance is available, so this passes
_winapi.WaitNamedPipe(pipe_name, 0)

with open(pipe_name, 'w+b') as pipe2:
# No instances available, so this times out
# (WinError 121 does not get mapped to TimeoutError)
with self.assertRaises(OSError):
_winapi.WaitNamedPipe(pipe_name, 0)

_winapi.WriteFile(pipe, b'testdata')
self.assertEqual(b'testdata', pipe2.read(8))

self.assertEqual((b'', 0), _winapi.PeekNamedPipe(pipe, 8)[:2])
pipe2.write(b'testdata')
pipe2.flush()
self.assertEqual((b'testdata', 8), _winapi.PeekNamedPipe(pipe, 8)[:2])
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adds Unicode support and fixes audit events for ``_winapi.CreateNamedPipe``.
37 changes: 18 additions & 19 deletions Modules/_winapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ create_converter('LPCVOID', '" F_POINTER "')
create_converter('BOOL', 'i') # F_BOOL used previously (always 'i')
create_converter('DWORD', 'k') # F_DWORD is always "k" (which is much shorter)
create_converter('LPCTSTR', 's')
create_converter('UINT', 'I') # F_UINT used previously (always 'I')
class LPCWSTR_converter(Py_UNICODE_converter):
Expand Down Expand Up @@ -259,7 +258,7 @@ class LPVOID_return_converter(CReturnConverter):
data.return_conversion.append(
'return_value = HANDLE_TO_PYNUM(_return_value);\n')
[python start generated code]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=ef52a757a1830d92]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=da0a4db751936ee7]*/

#include "clinic/_winapi.c.h"

Expand Down Expand Up @@ -530,7 +529,7 @@ _winapi_CreateFile_impl(PyObject *module, LPCWSTR file_name,
{
HANDLE handle;

if (PySys_Audit("_winapi.CreateFile", "uIIII",
if (PySys_Audit("_winapi.CreateFile", "ukkkk",
file_name, desired_access, share_mode,
creation_disposition, flags_and_attributes) < 0) {
return INVALID_HANDLE_VALUE;
Expand Down Expand Up @@ -777,7 +776,7 @@ _winapi_CreateMutexW_impl(PyObject *module,
/*[clinic input]
_winapi.CreateNamedPipe -> HANDLE
name: LPCTSTR
name: LPCWSTR
open_mode: DWORD
pipe_mode: DWORD
max_instances: DWORD
Expand All @@ -789,25 +788,25 @@ _winapi.CreateNamedPipe -> HANDLE
[clinic start generated code]*/

static HANDLE
_winapi_CreateNamedPipe_impl(PyObject *module, LPCTSTR name, DWORD open_mode,
_winapi_CreateNamedPipe_impl(PyObject *module, LPCWSTR name, DWORD open_mode,
DWORD pipe_mode, DWORD max_instances,
DWORD out_buffer_size, DWORD in_buffer_size,
DWORD default_timeout,
LPSECURITY_ATTRIBUTES security_attributes)
/*[clinic end generated code: output=80f8c07346a94fbc input=5a73530b84d8bc37]*/
/*[clinic end generated code: output=7d6fde93227680ba input=5bd4e4a55639ee02]*/
{
HANDLE handle;

if (PySys_Audit("_winapi.CreateNamedPipe", "uII",
if (PySys_Audit("_winapi.CreateNamedPipe", "ukk",
name, open_mode, pipe_mode) < 0) {
return INVALID_HANDLE_VALUE;
}

Py_BEGIN_ALLOW_THREADS
handle = CreateNamedPipe(name, open_mode, pipe_mode,
max_instances, out_buffer_size,
in_buffer_size, default_timeout,
security_attributes);
handle = CreateNamedPipeW(name, open_mode, pipe_mode,
max_instances, out_buffer_size,
in_buffer_size, default_timeout,
security_attributes);
Py_END_ALLOW_THREADS

if (handle == INVALID_HANDLE_VALUE)
Expand Down Expand Up @@ -1790,7 +1789,7 @@ _winapi_OpenEventW_impl(PyObject *module, DWORD desired_access,
{
HANDLE handle;

if (PySys_Audit("_winapi.OpenEventW", "Iu", desired_access, name) < 0) {
if (PySys_Audit("_winapi.OpenEventW", "ku", desired_access, name) < 0) {
return INVALID_HANDLE_VALUE;
}

Expand Down Expand Up @@ -1821,7 +1820,7 @@ _winapi_OpenMutexW_impl(PyObject *module, DWORD desired_access,
{
HANDLE handle;

if (PySys_Audit("_winapi.OpenMutexW", "Iu", desired_access, name) < 0) {
if (PySys_Audit("_winapi.OpenMutexW", "ku", desired_access, name) < 0) {
return INVALID_HANDLE_VALUE;
}

Expand Down Expand Up @@ -1882,7 +1881,7 @@ _winapi_OpenProcess_impl(PyObject *module, DWORD desired_access,
{
HANDLE handle;

if (PySys_Audit("_winapi.OpenProcess", "II",
if (PySys_Audit("_winapi.OpenProcess", "kk",
process_id, desired_access) < 0) {
return INVALID_HANDLE_VALUE;
}
Expand Down Expand Up @@ -2236,19 +2235,19 @@ _winapi_VirtualQuerySize_impl(PyObject *module, LPCVOID address)
/*[clinic input]
_winapi.WaitNamedPipe
name: LPCTSTR
name: LPCWSTR
timeout: DWORD
/
[clinic start generated code]*/

static PyObject *
_winapi_WaitNamedPipe_impl(PyObject *module, LPCTSTR name, DWORD timeout)
/*[clinic end generated code: output=c2866f4439b1fe38 input=36fc781291b1862c]*/
_winapi_WaitNamedPipe_impl(PyObject *module, LPCWSTR name, DWORD timeout)
/*[clinic end generated code: output=e161e2e630b3e9c2 input=099a4746544488fa]*/
{
BOOL success;

Py_BEGIN_ALLOW_THREADS
success = WaitNamedPipe(name, timeout);
success = WaitNamedPipeW(name, timeout);
Py_END_ALLOW_THREADS

if (!success)
Expand Down Expand Up @@ -2917,7 +2916,7 @@ _winapi_CopyFile2_impl(PyObject *module, LPCWSTR existing_file_name,
HRESULT hr;
COPYFILE2_EXTENDED_PARAMETERS params = { sizeof(COPYFILE2_EXTENDED_PARAMETERS) };

if (PySys_Audit("_winapi.CopyFile2", "uuI",
if (PySys_Audit("_winapi.CopyFile2", "uuk",
existing_file_name, new_file_name, flags) < 0) {
return NULL;
}
Expand Down
24 changes: 15 additions & 9 deletions Modules/clinic/_winapi.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e8ff1cf

Please sign in to comment.