Skip to content

Commit 52f8694

Browse files
committed
add test that can catch overflow with naive mid index calculation
1 parent 44d9804 commit 52f8694

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

src/stdlib_selection.fypp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ contains
9191
end if
9292

9393
do while(.true.)
94-
mid = l + (r-l)/2_ip ! Deliberate integer division
94+
mid = l + ((r-l)/2_ip) ! Avoid (l+r)/2 which can cause overflow
9595

9696
call medianOf3(a, l, mid, r)
9797
call swap(a(l), a(mid))
@@ -207,7 +207,7 @@ contains
207207
end if
208208

209209
do while(.true.)
210-
mid = l + (r-l)/2_ip ! Deliberate integer division
210+
mid = l + ((r-l)/2_ip) ! Avoid (l+r)/2 which can cause overflow
211211

212212
call arg_medianOf3(a, indx, l, mid, r)
213213
call swap(indx(l), indx(mid))

src/tests/selection/test_selection.fypp

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,18 @@ contains
4747
subroutine ${name}$(error)
4848
type(error_type), allocatable, intent(out) :: error
4949

50-
${inttype}$, parameter :: N = 10, Nreps = 2, Nm = 8
51-
${inttype}$, parameter :: Nr = min(HUGE(N)/2_int64, 25_int64) ! < HUGE(N)
50+
integer, parameter :: ip = ${intkind}$
51+
${inttype}$, parameter :: N = 10, Nm = 8
52+
${inttype}$, parameter :: near_huge = HUGE(N) - 1_ip ! Segfaults without the -1_ip
53+
${inttype}$, parameter :: Nreps = 2 ! Number of repetitions of random sampling
54+
${inttype}$, parameter :: Nr = 25_ip ! Size of random array, must be < HUGE(N)
5255

5356
${arraytype}$ :: x(N), x_copy(N), mat(Nm), mat_copy(Nm), len1(1), len2(2), &
5457
kth_smallest, random_vals(Nr), one = 1
5558
${inttype}$ :: i, p, up_rank, down_rank, mid_rank
5659
real(dp) :: random_doubles(Nr) ! Deliberately double precision for all cases
5760
logical :: test1, test2, test3
58-
integer, parameter :: ip = ${intkind}$
61+
${arraytype}$, allocatable :: long_array(:)
5962

6063
! x contains the numbers 1**2, 2**2, .... 10**2, with mixed-up order
6164
x = (/( i**2, i=1, size(x, kind=ip) )/)
@@ -88,6 +91,19 @@ contains
8891
if(allocated(error)) return
8992
end do
9093

94+
! The test below can catch overflow in naive calculation of the middle index, like discussed here:
95+
! https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html
96+
! But don't do it if near_huge is large, to avoid allocating a big array and slowing the tests
97+
if(near_huge < 200) then
98+
allocate(long_array(near_huge))
99+
long_array = 0 * one
100+
long_array(1:3) = one
101+
call select(long_array, near_huge - 2_ip, kth_smallest)
102+
call check( error, (kth_smallest == one), " ${name}$: designed to catch overflow in middle index")
103+
if(allocated(error)) return
104+
deallocate(long_array)
105+
end if
106+
91107
! Simple tests
92108
mat = one * [3, 2, 7, 4, 5, 1, 4, -1]
93109
mat_copy = mat
@@ -213,9 +229,11 @@ contains
213229
subroutine ${name}$(error)
214230
type(error_type), allocatable, intent(out) :: error
215231

216-
${inttype}$, parameter :: N = 10, Nreps = 2, Nm = 8
217-
${inttype}$, parameter :: Nr = min(HUGE(N)/2_int64, 25_int64) ! < HUGE(N)
218232
integer, parameter :: ip = ${intkind}$
233+
${inttype}$, parameter :: N = 10, Nm = 8
234+
${inttype}$, parameter :: near_huge = HUGE(N) - 1_ip ! Segfaults without the -1_ip
235+
${inttype}$, parameter :: Nreps = 2 ! Number of repetitions of random sampling
236+
${inttype}$, parameter :: Nr = 25_ip ! Size of random array, must be < HUGE(N)
219237

220238
${arraytype}$ :: x(N), mat(Nm), len1(1), len2(2), random_vals(Nr), one=1
221239

@@ -224,6 +242,8 @@ contains
224242
real(dp) :: random_doubles(Nr) ! Deliberately double precision for all cases
225243
integer(ip) :: i, j, p, up_rank, down_rank, mid_rank, kth_smallest
226244
logical :: test1, test2, test3
245+
${arraytype}$, allocatable :: long_array(:)
246+
${inttype}$, allocatable :: long_array_index(:)
227247

228248
! Make x contain 1**2, 2**2, .... 10**2, but mix up the order
229249
x = (/( i**2, i=1, size(x, kind=ip) )/)
@@ -258,6 +278,21 @@ contains
258278
if(allocated(error)) return
259279
end do
260280

281+
! The test below would catch overflow in naive calculation of the middle index, like discussed here:
282+
! https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html
283+
! But don't do it if near_huge is large, to avoid allocating a big array and slowing the tests
284+
if(near_huge < 200) then
285+
allocate(long_array(near_huge))
286+
allocate(long_array_index(near_huge))
287+
long_array = 0 * one
288+
long_array(1:3) = one
289+
long_array_index = (/( i, i = 1_ip, size(long_array, kind=ip) )/)
290+
call arg_select(long_array, long_array_index, near_huge - 2_ip, kth_smallest)
291+
call check( error, (kth_smallest < 4), " ${name}$: designed to catch overflow in middle index")
292+
if(allocated(error)) return
293+
deallocate(long_array, long_array_index)
294+
end if
295+
261296
! Simple tests
262297
mat = one * [3, 2, 7, 4, 5, 1, 4, -1]
263298
indx_mat = (/( i, i = 1, size(mat, kind=ip) )/)

0 commit comments

Comments
 (0)