@@ -388,11 +388,25 @@ cdef class Splitter:
388
388
& left_indices_buffer[offset_in_buffers[thread_idx]],
389
389
sizeof(unsigned int ) * left_counts[thread_idx]
390
390
)
391
- memcpy(
392
- & sample_indices[right_offset[thread_idx]],
393
- & right_indices_buffer[offset_in_buffers[thread_idx]],
394
- sizeof(unsigned int ) * right_counts[thread_idx]
395
- )
391
+ if right_counts[thread_idx] > 0 :
392
+ # If we're splitting the rightmost node of the tree, i.e. the
393
+ # rightmost node in the partition array, and if n_threads >= 2, one
394
+ # might have right_counts[-1] = 0 and right_offset[-1] = len(sample_indices)
395
+ # leading to evaluating
396
+ #
397
+ # &sample_indices[right_offset[-1]] = &samples_indices[n_samples_at_node]
398
+ # = &partition[n_samples_in_tree]
399
+ #
400
+ # which is an out-of-bounds read access that can cause a segmentation fault.
401
+ # When boundscheck=True, removing this check produces this exception:
402
+ #
403
+ # IndexError: Out of bounds on buffer access
404
+ #
405
+ memcpy(
406
+ & sample_indices[right_offset[thread_idx]],
407
+ & right_indices_buffer[offset_in_buffers[thread_idx]],
408
+ sizeof(unsigned int ) * right_counts[thread_idx]
409
+ )
396
410
397
411
return (sample_indices[:right_child_position],
398
412
sample_indices[right_child_position:],
@@ -839,7 +853,7 @@ cdef class Splitter:
839
853
# other category. The low-support categories will always be mapped to
840
854
# the right child. We scan the sorted categories array from left to
841
855
# right and from right to left, and we stop at the middle.
842
-
856
+
843
857
# Considering ordered categories A B C D, with E being a low-support
844
858
# category: A B C D
845
859
# ^
0 commit comments