Skip to content

Commit fe3b225

Browse files
authored
Fix conflicting checks for stop point in arc.mm:emptyPool() (#382)
* Fix conflicting checks for stop point in arc.mm:emptyPool() * Guard against releasing bogus objects behind the current autorelease pool while looping to the stopping point * Comment fix-up
1 parent ecef7f1 commit fe3b225

File tree

1 file changed

+45
-27
lines changed

1 file changed

+45
-27
lines changed

arc.mm

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -155,57 +155,75 @@ - (void)release;
155155

156156
/**
157157
* Empties objects from the autorelease pool, stating at the head of the list
158-
* specified by pool and continuing until it reaches the stop point. If the stop point is NULL then
158+
* specified by pool and continuing until it reaches the stop point. If the stop
159+
* point is NULL then all pools are cleared.
159160
*/
160-
static void emptyPool(struct arc_tls *tls, void *stop)
161+
static void emptyPool(struct arc_tls *tls, void *stopAt)
161162
{
163+
/* Clear all pools by default. */
162164
struct arc_autorelease_pool *stopPool = NULL;
163-
if (NULL != stop)
165+
void *oldPool;
166+
167+
/* Are we clearing up to a given object? */
168+
if (stopAt != NULL)
164169
{
165170
stopPool = tls->pool;
166-
while (1)
171+
172+
/* Find pool in which object to stop at is located. */
173+
while (stopPool != NULL)
167174
{
168-
// Invalid stop location
169-
if (NULL == stopPool)
170-
{
171-
return;
172-
}
173-
// NULL is the placeholder for the top-level pool
174-
if (NULL == stop && stopPool->previous == NULL)
175-
{
176-
break;
177-
}
178-
// Stop location was found in this pool
179-
if ((stop >= stopPool->pool) && (stop < &stopPool->pool[POOL_SIZE]))
175+
if (stopAt >= (void *)stopPool->pool &&
176+
stopAt < (void *)&stopPool->pool[POOL_SIZE])
180177
{
181178
break;
182179
}
180+
183181
stopPool = stopPool->previous;
184182
}
183+
184+
/* Invalid pointer, quit. */
185+
if (stopPool == NULL)
186+
{
187+
return;
188+
}
185189
}
186-
do {
190+
191+
do
192+
{
193+
/* Clear all pools up to the stop pool. */
187194
while (tls->pool != stopPool)
188195
{
189196
while (tls->pool->insert > tls->pool->pool)
190197
{
191-
tls->pool->insert--;
192-
// This may autorelease some other objects, so we have to work in
193-
// the case where the autorelease pool is extended during a -release.
198+
--tls->pool->insert;
194199
release(*tls->pool->insert);
195200
}
196-
void *old = tls->pool;
201+
202+
oldPool = tls->pool;
197203
tls->pool = tls->pool->previous;
198-
free(old);
204+
free(oldPool);
199205
}
200-
if (NULL == tls->pool) break;
201-
while ((stop == NULL || (tls->pool->insert > stop)) &&
202-
(tls->pool->insert > tls->pool->pool))
206+
207+
/* If we cleared them all, quit. */
208+
if (tls->pool == NULL)
203209
{
204-
tls->pool->insert--;
210+
return;
211+
}
212+
213+
/*
214+
* Release objects down to the stopping point. If a new pool is
215+
* pushed, never release below the pool's base.
216+
*/
217+
while (tls->pool->insert > (id *)stopAt &&
218+
tls->pool->insert > tls->pool->pool)
219+
{
220+
--tls->pool->insert;
205221
release(*tls->pool->insert);
206222
}
223+
224+
/* Be sure that releasing objects did not push any new pools. */
207225
} while (tls->pool != stopPool);
208-
//fprintf(stderr, "New insert: %p. Stop: %p\n", tls->pool->insert, stop);
226+
/* fprintf(stderr, "New insert: %p. Stop: %p\n", tls->pool->insert, stop); */
209227
}
210228

211229
#ifdef arc_tls_store

0 commit comments

Comments
 (0)