Author: julianfoad
Date: Mon Dec 30 15:42:17 2019
New Revision: 1872118

URL: http://svn.apache.org/viewvc?rev=1872118&view=rev
Log:
Avoid aborting on assertion failure in the area of mergeinfo calculations.

Instead, raise a catchable assertion error.

If an error occurs in svn_rangelist_merge2(), produce a more detailed error
message to aid in debugging.

Introduce and use 'svn_sort__array_insert2()' which checks its inputs.  The
old version of this function was aborting on out-of-range inputs.  Introduce
and use 'svn_sort__array_delete2()' likewise, as similar issues may show up
here too.  The old version of this function was ignoring calls with
out-of-range inputs.  The old versions of both functions are still in use
elsewhere in the Subversion libraries.

For issue #4840, "Merge assertion failure in svn_sort__array_insert".

* subversion/include/private/svn_sorts_private.h,
  subversion/libsvn_subr/sorts.c
  (svn_sort__array_insert2,
   svn_sort__array_delete2): New.

* subversion/libsvn_client/merge.c
  (slice_remaining_ranges,
   insert_child_to_merge): Allow returning an error.
  Everywhere: use svn_sort__array_insert2() and svn_sort__array_delete2().

* subversion/libsvn_subr/mergeinfo.c
  (adjust_remaining_ranges): Allow returning an error.
  (dual_dump): Replace this old debug helper...
  (rangelist_to_string_debug): ... with this new one.
  (svn_rangelist_merge2): Extract the body of this function into a local
    'rangelist_merge2', leaving the original as an error-checking
    wrapper. If an error occurs, report its inputs.
  (rangelist_is_sorted): New.
  Everywhere: use svn_sort__array_insert2() and svn_sort__array_delete2().

* subversion/tests/libsvn_subr/mergeinfo-test.c
  (test_rangelist_merge_random_non_validated_inputs): Expect assertion
    failures; ignore them.
  (test_funcs): Expect that test to pass now.

Modified:
    subversion/trunk/subversion/include/private/svn_sorts_private.h
    subversion/trunk/subversion/libsvn_client/merge.c
    subversion/trunk/subversion/libsvn_subr/mergeinfo.c
    subversion/trunk/subversion/libsvn_subr/sorts.c
    subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c

Modified: subversion/trunk/subversion/include/private/svn_sorts_private.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_sorts_private.h?rev=1872118&r1=1872117&r2=1872118&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_sorts_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_sorts_private.h Mon Dec 30 
15:42:17 2019
@@ -127,6 +127,16 @@ svn_sort__array_insert(apr_array_header_
                        const void *new_element,
                        int insert_index);
 
+/* Like svn_sort__array_insert() but raise an error if @a insert_index
+ * is less than 0 or greater than the length of the array.
+ *
+ * @note Private. For use by Subversion's own code only.
+ */
+svn_error_t *
+svn_sort__array_insert2(apr_array_header_t *array,
+                        const void *new_element,
+                        int insert_index);
+
 
 /* Remove @a elements_to_delete elements starting at @a delete_index from the
  * array @a arr. If @a delete_index is not a valid element of @a arr,
@@ -141,6 +151,16 @@ svn_sort__array_delete(apr_array_header_
                        int delete_index,
                        int elements_to_delete);
 
+/* Like svn_sort__array_delete() but raise an error if attempting
+ * to delete a range of elements that goes out of bounds of the array.
+ *
+ * @note Private. For use by Subversion's own code only.
+ */
+svn_error_t *
+svn_sort__array_delete2(apr_array_header_t *arr,
+                        int delete_index,
+                        int elements_to_delete);
+
 /* Reverse the order of elements in @a array, in place.
  *
  * @note Private. For use by Subversion's own code only.

Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1872118&r1=1872117&r2=1872118&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Mon Dec 30 15:42:17 2019
@@ -5975,7 +5975,7 @@ get_most_inclusive_rev(const apr_array_h
    remaining_ranges is inclusive of END_REV, Slice the first range in
    to two at END_REV. All the allocations are persistent and allocated
    from POOL. */
-static void
+static svn_error_t *
 slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo,
                        svn_boolean_t is_rollback, svn_revnum_t end_rev,
                        apr_pool_t *pool)
@@ -6005,10 +6005,12 @@ slice_remaining_ranges(apr_array_header_
               split_range2->start = end_rev;
               APR_ARRAY_IDX(child->remaining_ranges, 0,
                             svn_merge_range_t *) = split_range1;
-              svn_sort__array_insert(child->remaining_ranges, &split_range2, 
1);
+              SVN_ERR(svn_sort__array_insert2(child->remaining_ranges,
+                                              &split_range2, 1));
             }
         }
     }
+  return SVN_NO_ERROR;
 }
 
 /* Helper for do_directory_merge().
@@ -6130,7 +6132,7 @@ get_child_with_mergeinfo(const apr_array
        out of order and then sort afterwards. (One caller is doing a qsort
        after calling this anyway.)
  */
-static void
+static svn_error_t *
 insert_child_to_merge(apr_array_header_t *children_with_mergeinfo,
                       const svn_client__merge_path_t *insert_element,
                       apr_pool_t *pool)
@@ -6144,7 +6146,9 @@ insert_child_to_merge(apr_array_header_t
                                   compare_merge_path_t_as_paths);
 
   new_element = svn_client__merge_path_dup(insert_element, pool);
-  svn_sort__array_insert(children_with_mergeinfo, &new_element, insert_index);
+  SVN_ERR(svn_sort__array_insert2(children_with_mergeinfo,
+                                  &new_element, insert_index));
+  return SVN_NO_ERROR;
 }
 
 /* Helper for get_mergeinfo_paths().
@@ -6205,7 +6209,7 @@ insert_parent_and_sibs_of_sw_absent_del_
       parent->missing_child = child->absent;
       parent->switched_child = child->switched;
       /* Insert PARENT into CHILDREN_WITH_MERGEINFO. */
-      insert_child_to_merge(children_with_mergeinfo, parent, pool);
+      SVN_ERR(insert_child_to_merge(children_with_mergeinfo, parent, pool));
       /* Increment for loop index so we don't process the inserted element. */
       (*curr_index)++;
     } /*(parent == NULL) */
@@ -6242,8 +6246,8 @@ insert_parent_and_sibs_of_sw_absent_del_
 
           sibling_of_missing = svn_client__merge_path_create(child_abspath,
                                                              pool);
-          insert_child_to_merge(children_with_mergeinfo, sibling_of_missing,
-                                pool);
+          SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                        sibling_of_missing, pool));
         }
     }
 
@@ -6584,8 +6588,8 @@ get_mergeinfo_paths(apr_array_header_t *
                svn_client__merge_path_t *switched_child =
                  svn_client__merge_path_create(wc_path, result_pool);
                switched_child->switched = TRUE;
-               insert_child_to_merge(children_with_mergeinfo, switched_child,
-                                     result_pool);
+               SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                             switched_child, result_pool));
              }
         }
     }
@@ -6637,8 +6641,8 @@ get_mergeinfo_paths(apr_array_header_t *
             }
 
           if (new_shallow_child)
-            insert_child_to_merge(children_with_mergeinfo, shallow_child,
-                                  result_pool);
+            SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                          shallow_child, result_pool));
        }
     }
 
@@ -6667,8 +6671,8 @@ get_mergeinfo_paths(apr_array_header_t *
                svn_client__merge_path_t *absent_child =
                  svn_client__merge_path_create(wc_path, result_pool);
                absent_child->absent = TRUE;
-               insert_child_to_merge(children_with_mergeinfo, absent_child,
-                                     result_pool);
+               SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                             absent_child, result_pool));
              }
         }
     }
@@ -6681,8 +6685,8 @@ get_mergeinfo_paths(apr_array_header_t *
       svn_client__merge_path_t *target_child =
         svn_client__merge_path_create(target->abspath,
                                       result_pool);
-      insert_child_to_merge(children_with_mergeinfo, target_child,
-                            result_pool);
+      SVN_ERR(insert_child_to_merge(children_with_mergeinfo, target_child,
+                                    result_pool));
     }
 
   /* Case 8: Path is an immediate *directory* child of
@@ -6725,8 +6729,8 @@ get_mergeinfo_paths(apr_array_header_t *
                       && depth == svn_depth_immediates)
                     immediate_child->immediate_child_dir = TRUE;
 
-                  insert_child_to_merge(children_with_mergeinfo,
-                                        immediate_child, result_pool);
+                  SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                                immediate_child, result_pool));
                 }
             }
         }
@@ -6818,9 +6822,9 @@ get_mergeinfo_paths(apr_array_header_t *
                   child_of_noninheritable =
                     svn_client__merge_path_create(child_abspath, result_pool);
                   child_of_noninheritable->child_of_noninheritable = TRUE;
-                  insert_child_to_merge(children_with_mergeinfo,
-                                        child_of_noninheritable,
-                                        result_pool);
+                  SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                                child_of_noninheritable,
+                                                result_pool));
                   if (!dry_run && same_repos)
                     {
                       svn_mergeinfo_t mergeinfo;
@@ -7244,7 +7248,7 @@ normalize_merge_sources_internal(apr_arr
                   new_segment->path = original_repos_relpath;
                   new_segment->range_start = original_revision;
                   new_segment->range_end = original_revision;
-                  svn_sort__array_insert(segments, &new_segment, 0);
+                  SVN_ERR(svn_sort__array_insert2(segments, &new_segment, 0));
                 }
             }
         }
@@ -7978,7 +7982,8 @@ process_children_with_new_mergeinfo(merg
               /* Set the path's remaining_ranges equal to its parent's. */
               new_child->remaining_ranges = svn_rangelist_dup(
                  parent->remaining_ranges, pool);
-              insert_child_to_merge(children_with_mergeinfo, new_child, pool);
+              SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                            new_child, pool));
             }
         }
     }
@@ -9510,8 +9515,9 @@ do_mergeinfo_aware_dir_merge(svn_mergein
 
               svn_pool_clear(iterpool);
 
-              slice_remaining_ranges(children_with_mergeinfo,
-                                     is_rollback, end_rev, scratch_pool);
+              SVN_ERR(slice_remaining_ranges(children_with_mergeinfo,
+                                             is_rollback, end_rev,
+                                             scratch_pool));
 
               /* Reset variables that must be reset for every drive */
               merge_b->notify_begin.last_abspath = NULL;

Modified: subversion/trunk/subversion/libsvn_subr/mergeinfo.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/mergeinfo.c?rev=1872118&r1=1872117&r2=1872118&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/trunk/subversion/libsvn_subr/mergeinfo.c Mon Dec 30 15:42:17 2019
@@ -44,8 +44,9 @@
 /* Return TRUE iff the forward revision range FIRST wholly contains the
  * forward revision range SECOND and (if CONSIDER_INHERITANCE is TRUE) has
  * the same inheritability. */
-static svn_boolean_t
-range_contains(const svn_merge_range_t *first, const svn_merge_range_t *second,
+static svn_error_t *
+range_contains(svn_boolean_t *result,
+               const svn_merge_range_t *first, const svn_merge_range_t *second,
                svn_boolean_t consider_inheritance);
 
 
@@ -834,7 +835,7 @@ svn_mergeinfo_parse(svn_mergeinfo_t *mer
    element is equal to the start rev of the younger element.
 
    Any new elements inserted into RANGELIST are allocated in  RESULT_POOL.*/
-static void
+static svn_error_t *
 adjust_remaining_ranges(svn_rangelist_t *rangelist,
                         int *range_index,
                         apr_pool_t *result_pool)
@@ -845,7 +846,7 @@ adjust_remaining_ranges(svn_rangelist_t
   svn_merge_range_t *modified_range;
 
   if (*range_index >= rangelist->nelts)
-    return;
+    return SVN_NO_ERROR;
 
   starting_index = *range_index + 1;
   modified_range = APR_ARRAY_IDX(rangelist, *range_index, svn_merge_range_t *);
@@ -919,10 +920,11 @@ adjust_remaining_ranges(svn_rangelist_t
               new_modified_range->inheritable = FALSE;
               modified_range->end = next_range->start;
               (*range_index) += 2 + elements_to_delete;
-              svn_sort__array_insert(rangelist, &new_modified_range,
-                                     *range_index);
+              SVN_ERR(svn_sort__array_insert2(rangelist, &new_modified_range,
+                                              *range_index));
               /* Recurse with the new range. */
-              adjust_remaining_ranges(rangelist, range_index, result_pool);
+              SVN_ERR(adjust_remaining_ranges(rangelist, range_index,
+                                              result_pool));
               break;
             }
         }
@@ -975,31 +977,35 @@ adjust_remaining_ranges(svn_rangelist_t
     }
 
   if (elements_to_delete)
-    svn_sort__array_delete(rangelist, starting_index, elements_to_delete);
+    SVN_ERR(svn_sort__array_delete2(rangelist, starting_index,
+                                    elements_to_delete));
+
+  return SVN_NO_ERROR;
 }
 
-#if 0 /* Temporary debug helper code */
-static svn_error_t *
-dual_dump(const char *prefix,
-  const svn_rangelist_t *rangelist,
-  const svn_rangelist_t *changes,
-  apr_pool_t *scratch_pool)
+static const char *
+rangelist_to_string_debug(const svn_rangelist_t *rl,
+                          apr_pool_t *pool)
 {
-  svn_string_t *rls, *chg;
-
-  SVN_ERR(svn_rangelist_to_string(&rls, rangelist, scratch_pool));
-  SVN_ERR(svn_rangelist_to_string(&chg, changes, scratch_pool));
+  svn_string_t *rls;
+  svn_error_t *err;
 
-  SVN_DBG(("%s: %s / %s", prefix, rls->data, chg->data));
-  return SVN_NO_ERROR;
+  err = svn_rangelist_to_string(&rls, rl, pool);
+  if (err)
+    {
+      char *s = apr_psprintf(pool, _("<bad rangelist [%d ranges]: %s>"),
+                             rl->nelts, err->message);
+      svn_error_clear(err);
+      return s;
+    }
+  return rls->data;
 }
-#endif
 
-svn_error_t *
-svn_rangelist_merge2(svn_rangelist_t *rangelist,
-                     const svn_rangelist_t *chg,
-                     apr_pool_t *result_pool,
-                     apr_pool_t *scratch_pool)
+static svn_error_t *
+rangelist_merge2(svn_rangelist_t *rangelist,
+                 const svn_rangelist_t *chg,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
 {
   svn_rangelist_t *changes;
   int i = 0;
@@ -1016,6 +1022,7 @@ svn_rangelist_merge2(svn_rangelist_t *ra
       svn_merge_range_t *range;
       svn_merge_range_t *change =
         APR_ARRAY_IDX(changes, j, svn_merge_range_t *);
+      svn_boolean_t change_contains_range, range_contains_change;
       int res;
 
       range = (i < rangelist->nelts)
@@ -1027,7 +1034,7 @@ svn_rangelist_merge2(svn_rangelist_t *ra
           /* No overlap, nor adjoin, copy change to result range */
           svn_merge_range_t *chg_copy = svn_merge_range_dup(change,
                                                             result_pool);
-          svn_sort__array_insert(rangelist, &chg_copy, i++);
+          SVN_ERR(svn_sort__array_insert2(rangelist, &chg_copy, i++));
           continue;
         }
       else if ((change->start > range->end)
@@ -1040,10 +1047,12 @@ svn_rangelist_merge2(svn_rangelist_t *ra
           continue;
         }
 
+      SVN_ERR(range_contains(&change_contains_range, change, range, FALSE));
+      SVN_ERR(range_contains(&range_contains_change, range, change, FALSE));
       if (change->start < range->start
           && range->inheritable != change->inheritable
-          && ! (change->inheritable && range_contains(change, range, FALSE))
-          && ! (range->inheritable && range_contains(range, change, FALSE)))
+          && ! (change->inheritable && change_contains_range)
+          && ! (range->inheritable && range_contains_change))
         {
           /* Can't fold change into existing range.
              Insert new range before range */
@@ -1057,7 +1066,7 @@ svn_rangelist_merge2(svn_rangelist_t *ra
           else
             range->start = change->end;
 
-          svn_sort__array_insert(rangelist, &chg_copy, i++);
+          SVN_ERR(svn_sort__array_insert2(rangelist, &chg_copy, i++));
 
           change->start = chg_copy->end;
           if (change->start >= change->end)
@@ -1092,7 +1101,7 @@ svn_rangelist_merge2(svn_rangelist_t *ra
                   /* RANGE and CHANGE have the same inheritability so
                      RANGE expands to absord CHANGE. */
                   range->end = change->end;
-                  adjust_remaining_ranges(rangelist, &i, result_pool);
+                  SVN_ERR(adjust_remaining_ranges(rangelist, &i, result_pool));
                   continue;
                 }
               else
@@ -1132,7 +1141,8 @@ svn_rangelist_merge2(svn_rangelist_t *ra
                         svn_merge_range_dup(range, result_pool);
                       range_copy->end = change->start;
                       range->start = change->start;
-                      svn_sort__array_insert(rangelist, &range_copy, i++);
+                      SVN_ERR(svn_sort__array_insert2(rangelist,
+                                                      &range_copy, i++));
                       j--;
                       continue;
                     }
@@ -1181,7 +1191,8 @@ svn_rangelist_merge2(svn_rangelist_t *ra
                       /* ...but if RANGE is expanded ensure that we don't
                          violate any rangelist invariants. */
                       range->end = change->end;
-                      adjust_remaining_ranges(rangelist, &i, result_pool);
+                      SVN_ERR(adjust_remaining_ranges(rangelist,
+                                                      &i, result_pool));
                     }
                   continue;
                 }
@@ -1237,7 +1248,8 @@ svn_rangelist_merge2(svn_rangelist_t *ra
                           range->start = change->start;
                           range->end = change->end;
                           range->inheritable = TRUE;
-                          svn_sort__array_insert(rangelist, &range_copy, ++i);
+                          SVN_ERR(svn_sort__array_insert2(rangelist,
+                                                          &range_copy, ++i));
                           continue;
                         }
                     }
@@ -1255,7 +1267,8 @@ svn_rangelist_merge2(svn_rangelist_t *ra
                       range_copy->end = change->end;
                       range_copy->inheritable = TRUE;
                       range->start = change->end;
-                      svn_sort__array_insert(rangelist, &range_copy, i++);
+                      SVN_ERR(svn_sort__array_insert2(rangelist,
+                                                      &range_copy, i++));
                       continue;
                     }
                 }
@@ -1265,40 +1278,98 @@ svn_rangelist_merge2(svn_rangelist_t *ra
     }
 
 #ifdef SVN_DEBUG
-  SVN_ERR_ASSERT(svn_rangelist__is_canonical(rangelist));
+  /*SVN_ERR_ASSERT(svn_rangelist__is_canonical(rangelist));*/
 #endif
 
   return SVN_NO_ERROR;
 }
 
-/* Return TRUE iff the forward revision ranges FIRST and SECOND overlap and
- * (if CONSIDER_INHERITANCE is TRUE) have the same inheritability. */
 static svn_boolean_t
-range_intersect(const svn_merge_range_t *first, const svn_merge_range_t 
*second,
+rangelist_is_sorted(const svn_rangelist_t *rangelist)
+{
+  int i;
+
+  for (i = 1; i < rangelist->nelts; i++)
+    {
+      const svn_merge_range_t *lastrange
+        = APR_ARRAY_IDX(rangelist, i-1, svn_merge_range_t *);
+      const svn_merge_range_t *thisrange
+        = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+
+      if (svn_sort_compare_ranges(&lastrange, &thisrange) > 0)
+        return FALSE;
+    }
+  return TRUE;
+}
+
+svn_error_t *
+svn_rangelist_merge2(svn_rangelist_t *rangelist,
+                     const svn_rangelist_t *chg,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  svn_rangelist_t *rangelist_orig = svn_rangelist_dup(rangelist, scratch_pool);
+  svn_error_t *err;
+
+  SVN_ERR_ASSERT(rangelist_is_sorted(rangelist));
+  SVN_ERR_ASSERT(rangelist_is_sorted(chg));
+
+  err = svn_error_trace(rangelist_merge2(rangelist, chg, result_pool,
+                                         scratch_pool));
+  if (err)
+    {
+      err = svn_error_createf(SVN_ERR_ASSERTION_FAIL, err,
+              "svn_rangelist_merge2( %s / %s ): internal error",
+              rangelist_to_string_debug(rangelist_orig, scratch_pool),
+              rangelist_to_string_debug(chg, scratch_pool));
+    }
+  else if (! svn_rangelist__is_canonical(rangelist)
+           && svn_rangelist__is_canonical(rangelist_orig)
+           && svn_rangelist__is_canonical(chg))
+    {
+      err = svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
+              "svn_rangelist_merge2( %s / %s ): canonical inputs, "
+              "non-canonical result ( %s )",
+              rangelist_to_string_debug(rangelist_orig, scratch_pool),
+              rangelist_to_string_debug(chg, scratch_pool),
+              rangelist_to_string_debug(rangelist, scratch_pool));
+    }
+
+  return err;
+}
+
+/* Set *RESULT to TRUE iff the forward revision ranges FIRST and SECOND overlap
+ * and (if CONSIDER_INHERITANCE is TRUE) have the same inheritability. */
+static svn_error_t *
+range_intersect(svn_boolean_t *result,
+                const svn_merge_range_t *first, const svn_merge_range_t 
*second,
                 svn_boolean_t consider_inheritance)
 {
-  SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(first));
-  SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(second));
+  SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(first));
+  SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(second));
 
-  return (first->start + 1 <= second->end)
-    && (second->start + 1 <= first->end)
-    && (!consider_inheritance
-        || (!(first->inheritable) == !(second->inheritable)));
+  *result = (first->start + 1 <= second->end)
+            && (second->start + 1 <= first->end)
+            && (!consider_inheritance
+                || (!(first->inheritable) == !(second->inheritable)));
+  return SVN_NO_ERROR;
 }
 
-/* Return TRUE iff the forward revision range FIRST wholly contains the
+/* Set *RESULT to TRUE iff the forward revision range FIRST wholly contains the
  * forward revision range SECOND and (if CONSIDER_INHERITANCE is TRUE) has
  * the same inheritability. */
-static svn_boolean_t
-range_contains(const svn_merge_range_t *first, const svn_merge_range_t *second,
+static svn_error_t *
+range_contains(svn_boolean_t *result,
+               const svn_merge_range_t *first, const svn_merge_range_t *second,
                svn_boolean_t consider_inheritance)
 {
-  SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(first));
-  SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(second));
+  SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(first));
+  SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(second));
 
-  return (first->start <= second->start) && (second->end <= first->end)
-    && (!consider_inheritance
-        || (!(first->inheritable) == !(second->inheritable)));
+  *result = (first->start <= second->start) && (second->end <= first->end)
+            && (!consider_inheritance
+                || (!(first->inheritable) == !(second->inheritable)));
+  return SVN_NO_ERROR;
 }
 
 /* Swap start and end fields of RANGE. */
@@ -1417,6 +1488,7 @@ rangelist_intersect_or_remove(svn_rangel
   while (i1 < rangelist1->nelts && i2 < rangelist2->nelts)
     {
       svn_merge_range_t *elt1, *elt2;
+      svn_boolean_t elt1_contains_elt2, elt1_intersects_elt2;
 
       elt1 = APR_ARRAY_IDX(rangelist1, i1, svn_merge_range_t *);
 
@@ -1432,6 +1504,10 @@ rangelist_intersect_or_remove(svn_rangel
 
       elt2 = &working_elt2;
 
+      SVN_ERR(range_contains(&elt1_contains_elt2,
+                             elt1, elt2, consider_inheritance));
+      SVN_ERR(range_intersect(&elt1_intersects_elt2,
+                              elt1, elt2, consider_inheritance));
       /* If the rangelist2 range is contained completely in the
          rangelist1, we increment the rangelist2.
          If the ranges intersect, and match exactly, we increment both
@@ -1440,7 +1516,7 @@ rangelist_intersect_or_remove(svn_rangel
          the removal of rangelist1 from rangelist2, and possibly change
          the rangelist2 to the remaining portion of the right part of
          the removal, to test against. */
-      if (range_contains(elt1, elt2, consider_inheritance))
+      if (elt1_contains_elt2)
         {
           if (!do_remove)
             {
@@ -1461,7 +1537,7 @@ rangelist_intersect_or_remove(svn_rangel
           if (elt2->start == elt1->start && elt2->end == elt1->end)
             i1++;
         }
-      else if (range_intersect(elt1, elt2, consider_inheritance))
+      else if (elt1_intersects_elt2)
         {
           if (elt2->start < elt1->start)
             {

Modified: subversion/trunk/subversion/libsvn_subr/sorts.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/sorts.c?rev=1872118&r1=1872117&r2=1872118&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/sorts.c (original)
+++ subversion/trunk/subversion/libsvn_subr/sorts.c Mon Dec 30 15:42:17 2019
@@ -34,6 +34,8 @@
 #include "svn_error.h"
 #include "private/svn_sorts_private.h"
 
+#include "svn_private_config.h"
+
 
 
 /*** svn_sort__hash() ***/
@@ -324,6 +326,20 @@ svn_sort__array_insert(apr_array_header_
   memcpy(new_position, new_element, array->elt_size);
 }
 
+svn_error_t *
+svn_sort__array_insert2(apr_array_header_t *array,
+                        const void *new_element,
+                        int insert_index)
+{
+  if (insert_index < 0 || insert_index > array->nelts)
+    return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+                             _("svn_sort__array_insert2: Attempted insert "
+                               "at index %d in array length %d"),
+                             insert_index, array->nelts);
+  svn_sort__array_insert(array, new_element, insert_index);
+  return SVN_NO_ERROR;
+}
+
 void
 svn_sort__array_delete(apr_array_header_t *arr,
                        int delete_index,
@@ -349,6 +365,23 @@ svn_sort__array_delete(apr_array_header_
     }
 }
 
+svn_error_t *
+svn_sort__array_delete2(apr_array_header_t *arr,
+                        int delete_index,
+                        int elements_to_delete)
+{
+  if (!(delete_index >= 0
+        && delete_index < arr->nelts
+        && elements_to_delete > 0
+        && (arr->nelts - delete_index) >= elements_to_delete))
+    return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+                             _("svn_sort__array_delete2: Attempted delete "
+                               "at index %d, %d elements, in array length %d"),
+                             delete_index, elements_to_delete, arr->nelts);
+  svn_sort__array_delete(arr, delete_index, elements_to_delete);
+  return SVN_NO_ERROR;
+}
+
 void
 svn_sort__array_reverse(apr_array_header_t *array,
                         apr_pool_t *scratch_pool)

Modified: subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c?rev=1872118&r1=1872117&r2=1872118&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c Mon Dec 30 
15:42:17 2019
@@ -2118,11 +2118,15 @@ test_rangelist_merge_random_semi_c_input
   return SVN_NO_ERROR;
 }
 
+/* Test svn_rangelist_merge2() with random non-validated inputs.
+ *
+ * Unlike the tests with valid inputs, this test expects many assertion
+ * failures.  We don't care about those.  All we care about is that it does
+ * not crash. */
 static svn_error_t *
 test_rangelist_merge_random_non_validated_inputs(apr_pool_t *pool)
 {
   apr_pool_t *iterpool = svn_pool_create(pool);
-  svn_boolean_t pass = TRUE;
   int ix, iy;
 
   for (ix = 0; ix < 300; ix++)
@@ -2143,18 +2147,11 @@ test_rangelist_merge_random_non_validate
         err = rangelist_merge_random_inputs(rlx, rly, iterpool);
         if (err)
           {
-            printf("testcase FAIL: %s / %s\n",
-                   rangelist_to_string(rlx, iterpool),
-                   rangelist_to_string(rly, iterpool));
-            svn_handle_error(err, stdout, FALSE);
             svn_error_clear(err);
-            pass = FALSE;
           }
       }
    }
 
-  if (!pass)
-    return svn_error_create(SVN_ERR_TEST_FAILED, NULL, NULL);
   return SVN_NO_ERROR;
 }
 
@@ -2211,8 +2208,8 @@ static struct svn_test_descriptor_t test
                     "test rangelist merge random canonical inputs"),
     SVN_TEST_XFAIL2(test_rangelist_merge_random_semi_c_inputs,
                     "test rangelist merge random semi-c inputs"),
-    SVN_TEST_XFAIL2(test_rangelist_merge_random_non_validated_inputs,
-                    "test rangelist merge random non-validated inputs"),
+    SVN_TEST_PASS2(test_rangelist_merge_random_non_validated_inputs,
+                   "test rangelist merge random non-validated inputs"),
     SVN_TEST_NULL
   };
 


Reply via email to