Skip to content

Commit 5b1be6e

Browse files
authored
Fix pywin32.CredEnumerate implementation for ctypes backend (#117)
* Fix pywin32.CredEnumerate implementation for ctypes backend * Do not show traceback when an access violation is expected * Use more recent action steps * Fix github workflow lint step * Fix cffi backend on 32bit * build and upload html report
1 parent 3a7313b commit 5b1be6e

File tree

4 files changed

+57
-30
lines changed

4 files changed

+57
-30
lines changed

.github/workflows/test.yml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
coverage run -m haas -v win32ctypes
3232
pip install --upgrade cffi
3333
coverage run -m haas -v win32ctypes
34-
env:
34+
env:
3535
PYTHONFAULTHANDLER: 1
3636
- name: Set up Python ${{ matrix.python-version }}
3737
uses: actions/setup-python@v4
@@ -48,18 +48,22 @@ jobs:
4848
coverage run -p -m haas -v win32ctypes
4949
pip install --upgrade cffi
5050
coverage run -p -m haas -v win32ctypes
51-
env:
51+
env:
5252
PYTHONFAULTHANDLER: 1
53-
- uses: actions/upload-artifact@v2
53+
- name: Generate coverage report
54+
run: |
55+
coverage combine
56+
coverage html
57+
- uses: actions/upload-artifact@v3
5458
with:
5559
name: Upload Coverage info
56-
path: .coverage*
60+
path: htmlcov/*
5761
code-lint:
5862
runs-on: ubuntu-latest
5963
steps:
60-
- uses: actions/checkout@v2
64+
- uses: actions/checkout@v3
6165
- name: Set up Python 3.8
62-
uses: actions/setup-python@v2
66+
uses: actions/setup-python@v4
6367
with:
6468
python-version: 3.8
6569
- name: Install flake8

win32ctypes/core/ctypes/_authentication.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,6 @@ def credential2dict(creds):
9595
return credential
9696

9797

98-
def _CredEnumerate(Filter, Flags, Count, pppCredential):
99-
filter_ = LPCWSTR(Filter)
100-
_BaseCredEnumerate(filter_, Flags, Count, pppCredential)
101-
102-
10398
_CredWrite = function_factory(
10499
dlls.advapi32.CredWriteW,
105100
[PCREDENTIAL, DWORD],
@@ -118,7 +113,7 @@ def _CredEnumerate(Filter, Flags, Count, pppCredential):
118113
BOOL,
119114
check_false_factory("CredDelete"))
120115

121-
_BaseCredEnumerate = function_factory(
116+
_CredEnumerate = function_factory(
122117
dlls.advapi32.CredEnumerateW,
123118
[LPCWSTR, DWORD, POINTER(DWORD), PPPCREDENTIAL],
124119
BOOL,

win32ctypes/pywin32/win32cred.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -114,25 +114,32 @@ def CredEnumerate(Filter=None, Flags=0):
114114
with _pywin32error():
115115
if _backend == 'cffi':
116116
pcount = _common.PDWORD()
117-
pppcreds = _authentication.PPPCREDENTIAL()
118-
_authentication._CredEnumerate(Filter, Flags, pcount, pppcreds)
117+
pppcredential = _authentication.PPPCREDENTIAL()
118+
_authentication._CredEnumerate(
119+
Filter, Flags, pcount, pppcredential)
119120
count = pcount[0]
120-
pcreds = _common.dereference(
121-
_common.ffi.cast(f"PCREDENTIAL*[{count}]", pppcreds))
121+
data = _common.dereference(
122+
_common.ffi.cast(f"PCREDENTIAL*[{count}]", pppcredential))
123+
memory = _common.dereference(pppcredential)
122124
else:
123125
import ctypes
124126
count = _authentication.DWORD()
125-
# Create a mutable pointer variable
126-
mem = ctypes.create_string_buffer(1)
127-
pppcreds = _common.cast(
128-
mem, _authentication.PPPCREDENTIAL)
127+
pcredential = _authentication.PCREDENTIAL()
128+
ppcredential = ctypes.pointer(pcredential)
129+
pppcredential = ctypes.pointer(ppcredential)
129130
_authentication._CredEnumerate(
130-
Filter, Flags, _common.byreference(count), pppcreds)
131+
Filter, Flags, _common.byreference(count), pppcredential)
131132
count = count.value
132-
pcreds = _common.dereference(_common.dereference(pppcreds))
133+
data = _common.dereference(
134+
_common.cast(
135+
ppcredential,
136+
_common.POINTER(_authentication.PCREDENTIAL*count)))
137+
memory = pcredential
133138
try:
134-
return [
135-
_authentication.credential2dict(pcreds[i])
136-
for i in range(count)]
139+
result = []
140+
for i in range(count):
141+
credential = _common.dereference(data[i])
142+
result.append(_authentication.credential2dict(credential))
143+
return result
137144
finally:
138-
_authentication._CredFree(pcreds)
145+
_authentication._CredFree(memory)

win32ctypes/tests/test_win32api.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
import contextlib
1212
import tempfile
1313
import shutil
14+
import faulthandler
1415

1516
import win32api
1617

18+
1719
from win32ctypes import pywin32
1820
from win32ctypes.pywin32.pywintypes import error
1921

@@ -49,6 +51,22 @@ def resource_update(self, module, library=sys.executable):
4951
finally:
5052
module.EndUpdateResource(handle, False)
5153

54+
@contextlib.contextmanager
55+
def nofaulthandler(self):
56+
""" Disable the faulthander
57+
58+
Use this function to avoid poluting the output with errors
59+
When it is known that an access violation is expected.
60+
61+
"""
62+
enabled = faulthandler.is_enabled()
63+
faulthandler.disable()
64+
try:
65+
yield
66+
finally:
67+
if enabled:
68+
faulthandler.enable()
69+
5270
def test_load_library_ex(self):
5371
with self.load_library(win32api) as expected:
5472
with self.load_library(self.module) as handle:
@@ -63,7 +81,8 @@ def test_free_library(self):
6381
self.assertNotEqual(self.module.FreeLibrary(handle), 0)
6482

6583
with self.assertRaises(error):
66-
self.module.FreeLibrary(-3)
84+
with self.nofaulthandler():
85+
self.module.FreeLibrary(-3)
6786

6887
def test_enum_resource_types(self):
6988
with self.load_library(win32api, u'shell32.dll') as handle:
@@ -75,7 +94,8 @@ def test_enum_resource_types(self):
7594
self.assertEqual(resource_types, expected)
7695

7796
with self.assertRaises(error):
78-
self.module.EnumResourceTypes(-3)
97+
with self.nofaulthandler():
98+
self.module.EnumResourceTypes(-3)
7999

80100
def test_enum_resource_names(self):
81101
with self.load_library(win32api, u'shell32.dll') as handle:
@@ -138,8 +158,9 @@ def test_load_resource(self):
138158
self.assertEqual(resource, expected)
139159

140160
with self.assertRaises(error):
141-
self.module.LoadResource(
142-
handle, resource_type, resource_name, 12435)
161+
with self.nofaulthandler():
162+
self.module.LoadResource(
163+
handle, resource_type, resource_name, 12435)
143164

144165
def test_get_tick_count(self):
145166
self.assertGreater(self.module.GetTickCount(), 0.0)

0 commit comments

Comments
 (0)