ObjFW  Diff

Differences From Artifact [6a15e61b81]:

To Artifact [99568ccb12]:

  • File src/runtime/autorelease.m — part of check-in [e7f4f80e23] at 2020-01-24 03:03:32 on branch trunk — 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. (user: js, size: 3222) [annotate] [blame] [check-ins using] [more...]


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;
}