Skip to content

Commit 791d57e

Browse files
authored
Merge pull request swiftlang#2764 from readdle/win-thread-specific
[Windows] CFThreadSpecific implementation allows access to deallocated value
2 parents ffbc021 + 511f6c9 commit 791d57e

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

CoreFoundation/Base.subproj/CFPlatform.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,8 +1390,22 @@ CF_PRIVATE int asprintf(char **ret, const char *format, ...) {
13901390
extern void swift_retain(void *);
13911391
extern void swift_release(void *);
13921392

1393+
#if TARGET_OS_WIN32
1394+
typedef struct _CFThreadSpecificData {
1395+
CFTypeRef value;
1396+
_CFThreadSpecificKey key;
1397+
} _CFThreadSpecificData;
1398+
#endif
1399+
13931400
static void _CFThreadSpecificDestructor(void *ctx) {
1401+
#if TARGET_OS_WIN32
1402+
_CFThreadSpecificData *data = (_CFThreadSpecificData *)ctx;
1403+
FlsSetValue(data->key, NULL);
1404+
swift_release(data->value);
1405+
free(data);
1406+
#else
13941407
swift_release(ctx);
1408+
#endif
13951409
}
13961410

13971411
_CFThreadSpecificKey _CFThreadSpecificKeyCreate() {
@@ -1406,18 +1420,36 @@ _CFThreadSpecificKey _CFThreadSpecificKeyCreate() {
14061420

14071421
CFTypeRef _Nullable _CFThreadSpecificGet(_CFThreadSpecificKey key) {
14081422
#if TARGET_OS_WIN32
1409-
return (CFTypeRef)FlsGetValue(key);
1423+
_CFThreadSpecificData *data = (_CFThreadSpecificData *)FlsGetValue(key);
1424+
if (data == NULL) {
1425+
return NULL;
1426+
}
1427+
return data->value;
14101428
#else
14111429
return (CFTypeRef)pthread_getspecific(key);
14121430
#endif
14131431
}
14141432

14151433
void _CFThreadSpecificSet(_CFThreadSpecificKey key, CFTypeRef _Nullable value) {
1434+
// Intentionally not calling `swift_release` for previous value.
1435+
// OperationQueue uses these API (through NSThreadSpecific), and balances
1436+
// retain count manually.
14161437
#if TARGET_OS_WIN32
1438+
free(FlsGetValue(key));
1439+
1440+
_CFThreadSpecificData *data = NULL;
14171441
if (value != NULL) {
1442+
data = malloc(sizeof(_CFThreadSpecificData));
1443+
if (!data) {
1444+
HALT_MSG("Out of memory");
1445+
}
1446+
data->value = value;
1447+
data->key = key;
1448+
14181449
swift_retain((void *)value);
14191450
}
1420-
FlsSetValue(key, value);
1451+
1452+
FlsSetValue(key, data);
14211453
#else
14221454
if (value != NULL) {
14231455
swift_retain((void *)value);

Tests/Foundation/Tests/TestNotificationQueue.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,5 +229,12 @@ class TestNotificationQueue : XCTestCase {
229229
bgThread.start()
230230

231231
waitForExpectations(timeout: 0.2)
232+
233+
// There is a small time gap between "e.fulfill()"
234+
// and actuall thread termination.
235+
// We need a little delay to allow bgThread actually die.
236+
// Callers of this function are assuming thread is
237+
// deallocated after call.
238+
Thread.sleep(forTimeInterval: 0.05)
232239
}
233240
}

0 commit comments

Comments
 (0)