Skip to content

Commit 9c4abca

Browse files
authored
Avoid overflow in to_string for -huge(1)-1 (#667)
1 parent f98f3d3 commit 9c4abca

File tree

2 files changed

+60
-15
lines changed

2 files changed

+60
-15
lines changed

src/stdlib_strings_to_string.fypp

+15-14
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ contains
1313
${t1}$, intent(in) :: value
1414
character(len=*), intent(in), optional :: format
1515
character(len=:), allocatable :: string
16-
16+
1717
character(len=buffer_len) :: buffer
1818
integer :: stat
1919

@@ -43,30 +43,31 @@ contains
4343
#:for k1, t1 in INT_KINDS_TYPES
4444
!> Represent an integer of kind ${k1}$ as character sequence.
4545
pure module function to_string_1_${t1[0]}$_${k1}$(value) result(string)
46-
${t1}$, intent(in) :: value
46+
integer, parameter :: ik = ${k1}$
47+
integer(ik), intent(in) :: value
4748
character(len=:), allocatable :: string
4849
integer, parameter :: buffer_len = range(value)+2
4950
character(len=buffer_len) :: buffer
5051
integer :: pos
51-
${t1}$ :: n
52-
character(len=1), parameter :: numbers(0:9) = &
53-
["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
52+
integer(ik) :: n
53+
character(len=1), parameter :: numbers(-9:0) = &
54+
["9", "8", "7", "6", "5", "4", "3", "2", "1", "0"]
5455

55-
if (value == 0_${k1}$) then
56+
if (value == 0_ik) then
5657
string = numbers(0)
5758
return
5859
end if
5960

60-
n = abs(value)
61+
n = sign(value, -1_ik)
6162
buffer = ""
62-
6363
pos = buffer_len + 1
64-
do while (n > 0_${k1}$)
64+
do while (n < 0_ik)
6565
pos = pos - 1
66-
buffer(pos:pos) = numbers(mod(n, 10_${k1}$))
67-
n = n/10_${k1}$
66+
buffer(pos:pos) = numbers(mod(n, 10_ik))
67+
n = n/10_ik
6868
end do
69-
if (value < 0_${k1}$) then
69+
70+
if (value < 0_ik) then
7071
pos = pos - 1
7172
buffer(pos:pos) = '-'
7273
end if
@@ -78,7 +79,7 @@ contains
7879
${t1}$, intent(in) :: value
7980
character(len=*), intent(in) :: format
8081
character(len=:), allocatable :: string
81-
82+
8283
character(len=buffer_len) :: buffer
8384
integer :: stat
8485

@@ -106,7 +107,7 @@ contains
106107
${t1}$, intent(in) :: value
107108
character(len=*), intent(in) :: format
108109
character(len=:), allocatable :: string
109-
110+
110111
character(len=buffer_len) :: buffer
111112
integer :: stat
112113

src/tests/string/test_string_to_string.f90

+45-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ subroutine collect_string_to_string(testsuite)
1818
new_unittest("to_string-complex", test_to_string_complex), &
1919
new_unittest("to_string-integer", test_to_string_integer), &
2020
new_unittest("to_string-logical", test_to_string_logical), &
21-
new_unittest("to_string-real", test_to_string_real) &
21+
new_unittest("to_string-real", test_to_string_real), &
22+
new_unittest("to_string-limit-i1", test_string_i1), &
23+
new_unittest("to_string-limit-i2", test_string_i2), &
24+
new_unittest("to_string-limit-i4", test_string_i4), &
25+
new_unittest("to_string-limit-i8", test_string_i8) &
2226
]
2327
end subroutine collect_string_to_string
2428

@@ -146,6 +150,46 @@ subroutine test_to_string_logical(error)
146150
end subroutine test_to_string_logical
147151

148152

153+
subroutine test_string_i1(error)
154+
use stdlib_kinds, only : i1 => int8
155+
156+
!> Error handling
157+
type(error_type), allocatable, intent(out) :: error
158+
159+
call check(error, to_string(-huge(1_i1) - 1_i1), "-128")
160+
end subroutine test_string_i1
161+
162+
163+
subroutine test_string_i2(error)
164+
use stdlib_kinds, only : i2 => int16
165+
166+
!> Error handling
167+
type(error_type), allocatable, intent(out) :: error
168+
169+
call check(error, to_string(-huge(1_i2) - 1_i2), "-32768")
170+
end subroutine test_string_i2
171+
172+
173+
subroutine test_string_i4(error)
174+
use stdlib_kinds, only : i4 => int32
175+
176+
!> Error handling
177+
type(error_type), allocatable, intent(out) :: error
178+
179+
call check(error, to_string(-huge(1_i4) - 1_i4), "-2147483648")
180+
end subroutine test_string_i4
181+
182+
183+
subroutine test_string_i8(error)
184+
use stdlib_kinds, only : i8 => int64
185+
186+
!> Error handling
187+
type(error_type), allocatable, intent(out) :: error
188+
189+
call check(error, to_string(-huge(1_i8) - 1_i8), "-9223372036854775808")
190+
end subroutine test_string_i8
191+
192+
149193
end module test_string_to_string
150194

151195

0 commit comments

Comments
 (0)