summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'dev-libs/libxml2/files/libxml2-2.9.2-timsort.patch')
-rw-r--r--dev-libs/libxml2/files/libxml2-2.9.2-timsort.patch128
1 files changed, 128 insertions, 0 deletions
diff --git a/dev-libs/libxml2/files/libxml2-2.9.2-timsort.patch b/dev-libs/libxml2/files/libxml2-2.9.2-timsort.patch
new file mode 100644
index 000000000000..c179d47ef2db
--- /dev/null
+++ b/dev-libs/libxml2/files/libxml2-2.9.2-timsort.patch
@@ -0,0 +1,128 @@
+From 9b987f8c98763ee569bde90b5268b43474ca106c Mon Sep 17 00:00:00 2001
+From: Christopher Swenson <chris@caswenson.com>
+Date: Fri, 27 Feb 2015 14:55:49 +0800
+Subject: [PATCH] Fix timsort invariant loop re: Envisage article
+
+See http://envisage-project.eu/proving-android-java-and-python-sorting-algorithm-is-broken-and-how-to-fix-it/
+
+We use a "runLen" array of size 128, so it should be nearly impossible
+to have our implementation overflow.
+
+But in any case, the fix is relatively simple -- checking two extra
+conditions in the invariant calculation.
+
+I also took this opportunity to remove some redundancy in the
+left/right merge logic in the invariant loop.
+---
+ timsort.h | 74 +++++++++++++++++++++++++++++++++------------------------------
+ 1 file changed, 39 insertions(+), 35 deletions(-)
+
+diff --git a/timsort.h b/timsort.h
+index efa3aab..795f272 100644
+--- a/timsort.h
++++ b/timsort.h
+@@ -392,62 +392,66 @@ static void TIM_SORT_MERGE(SORT_TYPE *dst, const TIM_SORT_RUN_T *stack, const in
+
+ static int TIM_SORT_COLLAPSE(SORT_TYPE *dst, TIM_SORT_RUN_T *stack, int stack_curr, TEMP_STORAGE_T *store, const size_t size)
+ {
+- while (1)
+- {
+- int64_t A, B, C;
++ while (1) {
++ int64_t A, B, C, D;
++ int ABC, BCD, BD, CD;
++
+ /* if the stack only has one thing on it, we are done with the collapse */
+- if (stack_curr <= 1) break;
++ if (stack_curr <= 1) {
++ break;
++ }
++
+ /* if this is the last merge, just do it */
+- if ((stack_curr == 2) &&
+- (stack[0].length + stack[1].length == (int64_t) size))
+- {
++ if ((stack_curr == 2) && (stack[0].length + stack[1].length == size)) {
+ TIM_SORT_MERGE(dst, stack, stack_curr, store);
+ stack[0].length += stack[1].length;
+ stack_curr--;
+ break;
+ }
+ /* check if the invariant is off for a stack of 2 elements */
+- else if ((stack_curr == 2) && (stack[0].length <= stack[1].length))
+- {
++ else if ((stack_curr == 2) && (stack[0].length <= stack[1].length)) {
+ TIM_SORT_MERGE(dst, stack, stack_curr, store);
+ stack[0].length += stack[1].length;
+ stack_curr--;
+ break;
+- }
+- else if (stack_curr == 2)
++ } else if (stack_curr == 2) {
+ break;
++ }
+
+- A = stack[stack_curr - 3].length;
+- B = stack[stack_curr - 2].length;
+- C = stack[stack_curr - 1].length;
++ B = stack[stack_curr - 3].length;
++ C = stack[stack_curr - 2].length;
++ D = stack[stack_curr - 1].length;
+
+- /* check first invariant */
+- if (A <= B + C)
+- {
+- if (A < C)
+- {
+- TIM_SORT_MERGE(dst, stack, stack_curr - 1, store);
+- stack[stack_curr - 3].length += stack[stack_curr - 2].length;
+- stack[stack_curr - 2] = stack[stack_curr - 1];
+- stack_curr--;
+- }
+- else
+- {
+- TIM_SORT_MERGE(dst, stack, stack_curr, store);
+- stack[stack_curr - 2].length += stack[stack_curr - 1].length;
+- stack_curr--;
+- }
++ if (stack_curr >= 4) {
++ A = stack[stack_curr - 4].length;
++ ABC = (A <= B + C);
++ } else {
++ ABC = 0;
+ }
+- /* check second invariant */
+- else if (B <= C)
+- {
++
++ BCD = (B <= C + D) || ABC;
++ CD = (C <= D);
++ BD = (B < D);
++
++ /* Both invariants are good */
++ if (!BCD && !CD) {
++ break;
++ }
++
++ /* left merge */
++ if (BCD && !CD) {
++ TIM_SORT_MERGE(dst, stack, stack_curr - 1, store);
++ stack[stack_curr - 3].length += stack[stack_curr - 2].length;
++ stack[stack_curr - 2] = stack[stack_curr - 1];
++ stack_curr--;
++ } else {
++ /* right merge */
+ TIM_SORT_MERGE(dst, stack, stack_curr, store);
+ stack[stack_curr - 2].length += stack[stack_curr - 1].length;
+ stack_curr--;
+ }
+- else
+- break;
+ }
++
+ return stack_curr;
+ }
+
+--
+2.3.5
+