|
3 | 3 |
|
4 | 4 | import gc |
5 | 5 | import os, sys, errno |
| 6 | +import itertools |
6 | 7 | import threading |
7 | 8 | import unittest |
8 | 9 | from platform import machine, win32_edition |
@@ -318,6 +319,37 @@ def run(self): |
318 | 319 | DeleteKey(HKEY_CURRENT_USER, test_key_name+'\\changing_value') |
319 | 320 | DeleteKey(HKEY_CURRENT_USER, test_key_name) |
320 | 321 |
|
| 322 | + def test_queryvalueex_race_condition(self): |
| 323 | + # gh-142282: QueryValueEx could read garbage buffer under race |
| 324 | + # condition when another thread changes the value size |
| 325 | + done = False |
| 326 | + ready = threading.Event() |
| 327 | + values = [b'ham', b'spam'] |
| 328 | + |
| 329 | + class WriterThread(threading.Thread): |
| 330 | + def run(self): |
| 331 | + with CreateKey(HKEY_CURRENT_USER, test_key_name) as key: |
| 332 | + values_iter = itertools.cycle(values) |
| 333 | + while not done: |
| 334 | + val = next(values_iter) |
| 335 | + SetValueEx(key, 'test_value', 0, REG_BINARY, val) |
| 336 | + ready.set() |
| 337 | + |
| 338 | + thread = WriterThread() |
| 339 | + thread.start() |
| 340 | + try: |
| 341 | + ready.wait() |
| 342 | + with CreateKey(HKEY_CURRENT_USER, test_key_name) as key: |
| 343 | + for _ in range(1000): |
| 344 | + result, typ = QueryValueEx(key, 'test_value') |
| 345 | + # The result must be one of the written values, |
| 346 | + # not garbage data from uninitialized buffer |
| 347 | + self.assertIn(result, values) |
| 348 | + finally: |
| 349 | + done = True |
| 350 | + thread.join() |
| 351 | + DeleteKey(HKEY_CURRENT_USER, test_key_name) |
| 352 | + |
321 | 353 | def test_long_key(self): |
322 | 354 | # Issue2810, in 2.6 and 3.1 when the key name was exactly 256 |
323 | 355 | # characters, EnumKey raised "WindowsError: More data is |
|
0 commit comments