From 48fb652d83b2c80d3e1861889484a5a5e57a1065 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 23 Jul 2018 17:13:52 -0400 Subject: [PATCH] Merge branch 'charlesmchen/unknownObjectVsNPE' --- SignalServiceKit/src/Contacts/TSThread.m | 37 ++++++++++++-------- SignalServiceKit/src/Storage/OWSStorage.m | 42 ++++++++++++++++++----- 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/SignalServiceKit/src/Contacts/TSThread.m b/SignalServiceKit/src/Contacts/TSThread.m index a8504165c..187eb2206 100644 --- a/SignalServiceKit/src/Contacts/TSThread.m +++ b/SignalServiceKit/src/Contacts/TSThread.m @@ -97,12 +97,24 @@ NS_ASSUME_NONNULL_BEGIN NSMutableArray *interactionIds = [NSMutableArray new]; YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName]; OWSAssert(interactionsByThread); - [interactionsByThread - enumerateKeysInGroup:self.uniqueId - usingBlock:^( - NSString *_Nonnull collection, NSString *_Nonnull key, NSUInteger index, BOOL *_Nonnull stop) { - [interactionIds addObject:key]; - }]; + __block BOOL didDetectCorruption = NO; + [interactionsByThread enumerateKeysInGroup:self.uniqueId + usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) { + if (![key isKindOfClass:[NSString class]] || key.length < 1) { + OWSProdLogAndFail(@"%@ invalid key in thread interactions: %@, %@.", + self.logTag, + key, + [key class]); + didDetectCorruption = YES; + return; + } + [interactionIds addObject:key]; + }]; + + if (didDetectCorruption) { + DDLogWarn(@"%@ incrementing version of: %@", self.logTag, TSMessageDatabaseViewExtensionName); + [OWSPrimaryStorage incrementVersionOfDatabaseExtension:TSMessageDatabaseViewExtensionName]; + } for (NSString *interactionId in interactionIds) { // We need to fetch each interaction, since [TSInteraction removeWithTransaction:] does important work. @@ -157,13 +169,8 @@ NS_ASSUME_NONNULL_BEGIN usingBlock:(void (^)(TSInteraction *interaction, YapDatabaseReadTransaction *transaction))block { - void (^interactionBlock)(NSString *, NSString *, id, id, NSUInteger, BOOL *) = ^void(NSString *_Nonnull collection, - NSString *_Nonnull key, - id _Nonnull object, - id _Nonnull metadata, - NSUInteger index, - BOOL *_Nonnull stop) { - + void (^interactionBlock)(NSString *, NSString *, id, id, NSUInteger, BOOL *) = ^void( + NSString *collection, NSString *key, id _Nonnull object, id _Nonnull metadata, NSUInteger index, BOOL *stop) { TSInteraction *interaction = object; block(interaction, transaction); }; @@ -194,7 +201,7 @@ NS_ASSUME_NONNULL_BEGIN - (NSArray *)allInteractions { NSMutableArray *interactions = [NSMutableArray new]; - [self enumerateInteractionsUsingBlock:^(TSInteraction *_Nonnull interaction) { + [self enumerateInteractionsUsingBlock:^(TSInteraction *interaction) { [interactions addObject:interaction]; }]; @@ -219,7 +226,7 @@ NS_ASSUME_NONNULL_BEGIN - (NSUInteger)numberOfInteractions { __block NSUInteger count; - [[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { + [[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) { YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName]; count = [interactionsByThread numberOfItemsInGroup:self.uniqueId]; }]; diff --git a/SignalServiceKit/src/Storage/OWSStorage.m b/SignalServiceKit/src/Storage/OWSStorage.m index 459e10606..c7f589c17 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.m +++ b/SignalServiceKit/src/Storage/OWSStorage.m @@ -192,7 +192,7 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ #pragma mark - -@interface OWSUnknownDBObject : NSObject +@interface OWSUnknownDBObject : TSYapDatabaseObject @end @@ -205,17 +205,42 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ */ @implementation OWSUnknownDBObject -- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder +- (void)encodeWithCoder:(NSCoder *)aCoder { - // We return self instead of, e.g. nil, to avoid a crash when YapDB enumerates - // all old objects when building a DB extension. + OWSProdLogAndFail(@"%@ Tried to save object from unknown collection", self.logTag); + + return [super encodeWithCoder:aCoder]; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (!self) { + return self; + } + return self; } -- (void)encodeWithCoder:(NSCoder *)aCoder +- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { - OWSRaiseException( - @"OWSStorageExceptionName_SaveToUnknownCollection", @"Tried to save object from unknown collection"); + OWSProdLogAndFail(@"%@ Tried to save unknown object", self.logTag); + + // No-op. +} + +- (void)touchWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSProdLogAndFail(@"%@ Tried to touch unknown object", self.logTag); + + // No-op. +} + +- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSProdLogAndFail(@"%@ Tried to remove unknown object", self.logTag); + + // No-op. } @end @@ -457,7 +482,8 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ return ^id(NSString __unused *collection, NSString __unused *key, NSData *data) { if (!data || data.length <= 0) { - return nil; + OWSProdLogAndFail(@"%@ can't deserialize null object: %@", self.logTag, collection); + return [OWSUnknownDBObject new]; } @try {