ObjFW  Check-in [e7f4f80e23]

Overview
Comment:runtime: Correctly handle AR pool push during pop

Getting a pointer and increasing it until we reach the top pointer does
not work: Releasing an object can temporarily create new autorelease
pools, which can trigger resizing of "objects" using realloc, which can
move it to a different address, which will then lead to continuing to
iterate on a now invalid pointer.

This is now solved by using an index into "objects" instead. Since we're
now indexing for the pop, let's use indexes everywhere, as they're more
readable anyway.

While debugging this, I noticed that the last pool is popped quite
frequently, only for a new pool to be pushed immediately again. This
resulted in a free followed by a malloc every time. Instead, keep the
pool, but let OFThread explicitly say when to free everything.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e7f4f80e2313fb6294ed2e0a210e4fefc5dab9f4c93fa71b04313e52451f1e82
User & Date: js on 2020-01-24 03:03:32
Other Links: manifest | tags
Context
2020-01-25
20:04
tlskey.m: Use hashtable from runtime on AmigaOS check-in: 49aee5736e user: js tags: trunk
2020-01-24
03:03
runtime: Correctly handle AR pool push during pop check-in: e7f4f80e23 user: js tags: trunk
2020-01-19
15:37
OFHTTPClient: Fix type mismatch on Windows check-in: 5256e9acaf user: js tags: trunk
Changes

Modified src/OFThread.h from [ccaa08b8db] to [4c0a8350b3].

69
70
71
72
73
74
75

76

77
78
79
80
81
82
83
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85







+

+







	of_thread_t _thread;
	of_thread_attr_t _attr;
	enum of_thread_running {
		OF_THREAD_NOT_RUNNING,
		OF_THREAD_RUNNING,
		OF_THREAD_WAITING_FOR_JOIN
	} _running;
# ifndef OF_OBJFW_RUNTIME
	void *_pool;
# endif
# ifdef OF_HAVE_BLOCKS
	of_thread_block_t _Nullable _threadBlock;
# endif
	jmp_buf _exitEnv;
	id _returnValue;
	bool _supportsSockets;
	OFRunLoop *_Nullable _runLoop;

Modified src/OFThread.m from [82882ba976] to [5a3f2982c0].

103
104
105
106
107
108
109

110

111
112
113
114
115
116
117
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119







+

+







	OFThread *thread = (OFThread *)object;
	OFString *name;

	if (!of_tlskey_set(threadSelfKey, thread))
		@throw [OFInitializationFailedException
		    exceptionWithClass: thread.class];

#ifndef OF_OBJFW_RUNTIME
	thread->_pool = objc_autoreleasePoolPush();
#endif

	name = thread.name;
	if (name != nil)
		of_thread_set_name(
		    [name cStringWithEncoding: [OFLocale encoding]]);
	else
		of_thread_set_name(object_getClassName(thread));
134
135
136
137
138
139
140



141

142
143
144
145
146
147
148
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154







+
+
+

+







		else
# endif
			thread->_returnValue = [[thread main] retain];
	}

	[thread handleTermination];

#ifdef OF_OBJFW_RUNTIME
	objc_autoreleasePoolPop((void *)(uintptr_t)-1);
#else
	objc_autoreleasePoolPop(thread->_pool);
#endif

#if defined(OF_AMIGAOS) && defined(OF_HAVE_SOCKETS)
	if (thread.supportsSockets)
		of_socket_deinit();
#endif

	thread->_running = OF_THREAD_WAITING_FOR_JOIN;

Modified src/runtime/autorelease.m from [6a15e61b81] to [99568ccb12].

25
26
27
28
29
30
31
32
33


34
35

36
37
38
39


40
41
42
43
44
45
46

47
48
49
50
51
52
53
54
55

56
57
58
59
60

61
62
63
64

65
66
67
68

69


70
71
72
73
74








75





76


77
78

79
80
81

82





83
84
85
86

87
88
89
90
91
92
93
94
95
96

97

98
99

100
101
102



103
104

105
106
107
108
109
110
111
112
113
114
115
116
117


118
119
120
121

122
123

124
125

126
127

128
129
130
131

132
133
134
135
25
26
27
28
29
30
31


32
33
34

35
36
37


38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54

55

56



57
58
59
60

61
62
63

64
65
66
67
68





69
70
71
72
73
74
75
76
77
78
79
80
81
82

83
84
85

86
87

88
89

90
91
92
93
94
95
96
97

98

99
100
101
102
103
104
105

106
107

108
109
110
111



112
113
114


115

116











117
118
119
120
121

122
123

124


125


126

127
128

129
130
131
132
133







-
-
+
+

-
+


-
-
+
+






-
+








-
+
-

-
-
-
+



-
+


-

+

+
+
-
-
-
-
-
+
+
+
+
+
+
+
+

+
+
+
+
+
-
+
+

-
+

-

+
-
+
+
+
+
+



-
+
-







-

+
-
+


+
-
-
-
+
+
+
-
-
+
-

-
-
-
-
-
-
-
-
-
-
-
+
+



-
+

-
+
-
-
+
-
-
+
-


-
+





#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
# import "tlskey.h"
#endif

#if defined(OF_HAVE_COMPILER_TLS)
static thread_local id *objects = NULL;
static thread_local id *top = NULL;
static thread_local size_t size = 0;
static thread_local uintptr_t count = 0;
static thread_local uintptr_t size = 0;
#elif defined(OF_HAVE_THREADS)
static of_tlskey_t objectsKey, topKey, sizeKey;
static of_tlskey_t objectsKey, countKey, sizeKey;
#else
static id *objects = NULL;
static id *top = NULL;
static size_t size = 0;
static uintptr_t count = 0;
static uintptr_t size = 0;
#endif

#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
OF_CONSTRUCTOR()
{
	OF_ENSURE(of_tlskey_new(&objectsKey));
	OF_ENSURE(of_tlskey_new(&topKey));
	OF_ENSURE(of_tlskey_new(&countKey));
	OF_ENSURE(of_tlskey_new(&sizeKey));
}
#endif

void *
objc_autoreleasePoolPush()
{
#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
	id *top = of_tlskey_get(topKey);
	uintptr_t count = (uintptr_t)of_tlskey_get(countKey);
	id *objects = of_tlskey_get(objectsKey);
#endif
	ptrdiff_t offset = top - objects;

	return (void *)offset;
	return (void *)count;
}

void
objc_autoreleasePoolPop(void *offset)
objc_autoreleasePoolPop(void *pool)
{
#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
	id *top = of_tlskey_get(topKey);
	id *objects = of_tlskey_get(objectsKey);
	uintptr_t count = (uintptr_t)of_tlskey_get(countKey);
#endif
	uintptr_t idx = (uintptr_t)pool;
	bool freeMem = false;
	id *pool = objects + (ptrdiff_t)offset;
	id *iter;

	for (iter = pool; iter < top; iter++)
		[*iter release];

	if (idx == (uintptr_t)-1) {
		idx++;
		freeMem = true;
	}

	for (uintptr_t i = idx; i < count; i++) {
		[objects[i] release];

#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
		objects = of_tlskey_get(objectsKey);
		count = (uintptr_t)of_tlskey_get(countKey);
#endif
	}
	top = pool;

	count = idx;

	if (top == objects) {
	if (freeMem) {
		free(objects);

		objects = NULL;
#if defined(OF_HAVE_COMPILER_TLS) || !defined(OF_HAVE_THREADS)
		top = NULL;
		size = 0;
#else
		OF_ENSURE(of_tlskey_set(objectsKey, objects));
		OF_ENSURE(of_tlskey_set(sizeKey, (void *)0));
#endif
	}

#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
	OF_ENSURE(of_tlskey_set(topKey, top));
	OF_ENSURE(of_tlskey_set(countKey, (void *)count));
	OF_ENSURE(of_tlskey_set(objectsKey, objects));
#endif
}

id
_objc_rootAutorelease(id object)
{
#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
	id *top = of_tlskey_get(topKey);
	id *objects = of_tlskey_get(objectsKey);
	uintptr_t count = (uintptr_t)of_tlskey_get(countKey);
	size_t size = (size_t)(uintptr_t)of_tlskey_get(sizeKey);
	uintptr_t size = (uintptr_t)of_tlskey_get(sizeKey);
#endif

	if (count >= size) {
	if (objects == NULL) {
		size = 16 * sizeof(id);

		if (size == 0)
			size = 16;
		else
		OF_ENSURE((objects = malloc(size)) != NULL);

			size *= 2;
		top = objects;

#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
		OF_ENSURE(of_tlskey_set(objectsKey, objects));
		OF_ENSURE(of_tlskey_set(sizeKey, (void *)(uintptr_t)size));
#endif
	}

	if ((uintptr_t)top >= (uintptr_t)objects + size) {
		ptrdiff_t diff = top - objects;

		size *= 2;
		OF_ENSURE((objects = realloc(objects, size)) != NULL);
		OF_ENSURE((objects =
		    realloc(objects, size * sizeof(id))) != NULL);

#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
		OF_ENSURE(of_tlskey_set(objectsKey, objects));
		OF_ENSURE(of_tlskey_set(sizeKey, (void *)(uintptr_t)size));
		OF_ENSURE(of_tlskey_set(sizeKey, (void *)size));
#endif

	}
		top = objects + diff;
	}


	*top = object;
	objects[count++] = object;
	top++;

#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
	OF_ENSURE(of_tlskey_set(topKey, top));
	OF_ENSURE(of_tlskey_set(countKey, (void *)count));
#endif

	return object;
}