From cdda7ef233a7871e9f6f30165ce2bb9df98b61cb Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 26 Jul 2018 10:47:48 -0400 Subject: [PATCH 1/2] Fix overflow issue for invalid final indices. --- .../View/Utilities/YapDatabaseViewChange.m | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/YapDatabase/Extensions/View/Utilities/YapDatabaseViewChange.m b/YapDatabase/Extensions/View/Utilities/YapDatabaseViewChange.m index 0e56f3395..582b9d3f5 100644 --- a/YapDatabase/Extensions/View/Utilities/YapDatabaseViewChange.m +++ b/YapDatabase/Extensions/View/Utilities/YapDatabaseViewChange.m @@ -2160,17 +2160,24 @@ + (void)postProcessAndFilterRowChanges:(NSMutableArray *)rowChanges if ([reverse containsObject:rowChange->originalGroup]) { NSUInteger count = [originalMappings visibleCountForGroup:rowChange->originalGroup]; - double mid = (count - 1) / 2.0; - - rowChange->originalIndex = (NSUInteger)(mid - (rowChange->originalIndex - mid)); + // We treat "degenerate" indices (indices >= count) as count. + // These should never happen for "original" indices. + NSUInteger originalIndex = (rowChange->originalIndex >= count + ? count + : count - (rowChange->originalIndex + 1)); + rowChange->originalIndex = originalIndex; } if ([reverse containsObject:rowChange->finalGroup]) { NSUInteger count = [finalMappings visibleCountForGroup:rowChange->finalGroup]; - double mid = (count - 1) / 2.0; - - rowChange->finalIndex = (NSUInteger)(mid - (rowChange->finalIndex - mid)); + // We treat "degenerate" indices (indices >= count) as count. + // This can happen "final" indices for "delete" operations where + // there is no actual final index. + NSUInteger finalIndex = (rowChange->finalIndex >= count + ? count + : count - (rowChange->finalIndex + 1)); + rowChange->finalIndex = finalIndex; } } From 24c5882ac8b55e9a08baa5d43d0a43a696499691 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 2 Aug 2018 10:19:52 -0600 Subject: [PATCH 2/2] Clarify finalIndices overflow changes, add asserts. --- .../View/Utilities/YapDatabaseViewChange.m | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/YapDatabase/Extensions/View/Utilities/YapDatabaseViewChange.m b/YapDatabase/Extensions/View/Utilities/YapDatabaseViewChange.m index 582b9d3f5..a91eb8977 100644 --- a/YapDatabase/Extensions/View/Utilities/YapDatabaseViewChange.m +++ b/YapDatabase/Extensions/View/Utilities/YapDatabaseViewChange.m @@ -2153,31 +2153,30 @@ + (void)postProcessAndFilterRowChanges:(NSMutableArray *)rowChanges // 1 -> 2 // 2 -> 1 // 3 -> 0 - // - // Basically, we find the midpoint, and then move each index to the other side of the midpoint, - // but we keep its distance from the midpoint the same. - if ([reverse containsObject:rowChange->originalGroup]) { NSUInteger count = [originalMappings visibleCountForGroup:rowChange->originalGroup]; - // We treat "degenerate" indices (indices >= count) as count. - // These should never happen for "original" indices. - NSUInteger originalIndex = (rowChange->originalIndex >= count - ? count - : count - (rowChange->originalIndex + 1)); - rowChange->originalIndex = originalIndex; + NSUInteger forwardIndex = rowChange->originalIndex; + if (count < forwardIndex + 1) { + // Calculating the reverse index would overflow, so we skip it. + NSAssert(NO, @"original index is too large"); + } else { + rowChange->originalIndex = count - (forwardIndex + 1); + } } if ([reverse containsObject:rowChange->finalGroup]) { NSUInteger count = [finalMappings visibleCountForGroup:rowChange->finalGroup]; - // We treat "degenerate" indices (indices >= count) as count. - // This can happen "final" indices for "delete" operations where - // there is no actual final index. - NSUInteger finalIndex = (rowChange->finalIndex >= count - ? count - : count - (rowChange->finalIndex + 1)); - rowChange->finalIndex = finalIndex; + NSUInteger forwardIndex = rowChange->finalIndex; + if (count < forwardIndex + 1) { + // This can happen when deleting an item. + // Calculating the reverse index would overflow, so we skip it. + // When deleting a row, the finalIndex is irrelevant anyway. + NSAssert(rowChange->type == YapDatabaseViewChangeDelete, @"final index is too large"); + } else { + rowChange->finalIndex = count - (forwardIndex + 1); + } } }