From 6a9dcc255bc32040b995af99f0e737969a76b476 Mon Sep 17 00:00:00 2001 From: Richard Ross Date: Fri, 16 Oct 2015 15:27:13 -0700 Subject: [PATCH] Fix a potential deadlock that could occur when encoding for REST. We didn't actually need to hold the lock here, and if we did, another thread could have acquired these locks in another order, causing a deadlock. Should help to fix #398, #11, and a few others. --- Parse/Internal/Object/PFObjectPrivate.h | 3 ++- Parse/PFObject.m | 22 +++++++++++++++------- Parse/PFUser.m | 6 ++++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Parse/Internal/Object/PFObjectPrivate.h b/Parse/Internal/Object/PFObjectPrivate.h index 949e58911..3f3fcff1c 100644 --- a/Parse/Internal/Object/PFObjectPrivate.h +++ b/Parse/Internal/Object/PFObjectPrivate.h @@ -220,7 +220,8 @@ - (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder operationSetUUIDs:(NSArray **)operationSetUUIDs state:(PFObjectState *)state - operationSetQueue:(NSArray *)operationSetQueue; + operationSetQueue:(NSArray *)queue + deletingEventually:(BOOL)isDeletingEventually; - (void)mergeFromRESTDictionary:(NSDictionary *)object withDecoder:(PFDecoder *)decoder; diff --git a/Parse/PFObject.m b/Parse/PFObject.m index b403694d0..d6e1022bf 100644 --- a/Parse/PFObject.m +++ b/Parse/PFObject.m @@ -958,25 +958,33 @@ + (BFTask *)_migrateObjectInBackgroundFromFile:(NSString *)fileName */ - (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder operationSetUUIDs:(NSArray **)operationSetUUIDs { + NSArray *operationQueue = nil; + PFObjectState *state = nil; + BOOL deleting = NO; @synchronized (lock) { [self checkForChangesToMutableContainers]; - PFObjectState *state = self._state; - return [self RESTDictionaryWithObjectEncoder:objectEncoder - operationSetUUIDs:operationSetUUIDs - state:state - operationSetQueue:operationSetQueue]; + state = self._state; + operationQueue = [[NSArray alloc] initWithArray:operationSetQueue copyItems:YES]; + deleting = _deletingEventually; } + + return [self RESTDictionaryWithObjectEncoder:objectEncoder + operationSetUUIDs:operationSetUUIDs + state:state + operationSetQueue:operationQueue + deletingEventually:deleting]; } - (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder operationSetUUIDs:(NSArray **)operationSetUUIDs state:(PFObjectState *)state - operationSetQueue:(NSArray *)queue { + operationSetQueue:(NSArray *)queue + deletingEventually:(BOOL)isDeletingEventually { NSMutableDictionary *result = [[state dictionaryRepresentationWithObjectEncoder:objectEncoder] mutableCopy]; result[PFObjectClassNameRESTKey] = state.parseClassName; result[PFObjectCompleteRESTKey] = @(state.complete); - result[PFObjectIsDeletingEventuallyRESTKey] = @(_deletingEventually); + result[PFObjectIsDeletingEventuallyRESTKey] = @(isDeletingEventually); // TODO (hallucinogen): based on some note from Android's toRest, we'll need to put this // stuff somewhere else diff --git a/Parse/PFUser.m b/Parse/PFUser.m index d7a6eacc1..8abffd519 100644 --- a/Parse/PFUser.m +++ b/Parse/PFUser.m @@ -650,7 +650,8 @@ - (void)mergeFromRESTDictionary:(NSDictionary *)object withDecoder:(PFDecoder *) - (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder operationSetUUIDs:(NSArray **)operationSetUUIDs state:(PFObjectState *)state - operationSetQueue:(NSArray *)queue { + operationSetQueue:(NSArray *)queue + deletingEventually:(BOOL)isDeletingEventually { @synchronized (self.lock) { NSMutableArray *cleanQueue = [queue mutableCopy]; [queue enumerateObjectsUsingBlock:^(PFOperationSet *operationSet, NSUInteger idx, BOOL *stop) { @@ -665,7 +666,8 @@ - (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder return [super RESTDictionaryWithObjectEncoder:objectEncoder operationSetUUIDs:operationSetUUIDs state:state - operationSetQueue:cleanQueue]; + operationSetQueue:cleanQueue + deletingEventually:isDeletingEventually]; } }