Skip to content

Commit 808cf66

Browse files
committed
Attempting to protect against memory leaks when an invalid JSON file is parsed. Added a new test case with an invalid file.
1 parent e636f96 commit 808cf66

File tree

3 files changed

+47
-39
lines changed

3 files changed

+47
-39
lines changed

files/invalid2.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"notes": "This is an invalid JSON file, used to test error handling.",
3+
"version": {
4+
"major": 2,
5+
"minor": 0,
6+
"patch": 0,

src/json_example.f90

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ program json_test
7070
call test_3()
7171
call test_4()
7272
call test_5()
73-
call test_6()
73+
74+
call test_6() !these are attempting to read invalid json files
7475

7576
!call memory_leak_test()
7677

@@ -87,24 +88,33 @@ subroutine test_6()
8788
!**************************************************************
8889
implicit none
8990

90-
type(json_file) :: json
91+
type(json_file) :: json
92+
integer :: i
93+
94+
character(len=*),dimension(2),parameter :: files = ['invalid.json ',&
95+
'invalid2.json']
9196

9297
write(*,'(A)') ''
9398
write(*,'(A)') '================================='
94-
write(*,'(A)') ' EXAMPLE 6 : invalid JSON file '
99+
write(*,'(A)') ' EXAMPLE 6 : invalid JSON files'
95100
write(*,'(A)') '================================='
96101
write(*,'(A)') ''
97102

98-
! parse the json file:
99-
write(*,'(A)') 'load file...'
100-
call json%load_file(filename = dir//'invalid.json')
101-
if (json_failed()) then
102-
call print_error_message()
103-
end if
104-
105-
! clean up
106-
call json%destroy()
103+
do i=1,2
104+
105+
! parse the json file:
106+
write(*,'(A)') ''
107+
write(*,'(A)') 'load file: '//trim(files(i))
108+
write(*,'(A)') ''
109+
call json%load_file(filename = dir//trim(files(i)))
110+
if (json_failed()) then
111+
call print_error_message()
112+
end if
113+
! clean up
114+
call json%destroy()
107115

116+
end do
117+
108118
!**************************************************************
109119
end subroutine test_6
110120
!**************************************************************
@@ -641,7 +651,7 @@ subroutine test_1()
641651

642652
!call json%get('data(2)', p)
643653
!call json_update(p,'real',[1.0_wp, 2.0_wp, 3.0_wp],found) !don't have one like this yet...
644-
654+
645655
write(*,'(A)') ''
646656
write(*,'(A)') 'printing the modified structure...'
647657
call json%print_file()

src/json_module.f90

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4098,21 +4098,21 @@ recursive subroutine parse_object(unit, parent)
40984098
if (eof) then
40994099
call throw_exception('Error in parse_object:'//&
41004100
' Unexpected end of file while parsing start of object.')
4101-
call cleanup()
41024101
return
41034102
else if ('}' == c) then
41044103
! end of an empty object
4105-
call cleanup()
41064104
return
41074105
else if ('"' == c) then
41084106
call json_value_create(pair)
41094107
call parse_string(unit, tmp) !write to a tmp variable because of
41104108
pair % name = tmp ! a bug in 4.9 gfortran compiler.
41114109
deallocate(tmp)
4112-
if (exception_thrown) return
4110+
if (exception_thrown) then
4111+
call json_destroy(pair)
4112+
return
4113+
end if
41134114
else
41144115
call throw_exception('Error in parse_object: Expecting string: "'//c//'"')
4115-
call cleanup()
41164116
return
41174117
end if
41184118

@@ -4121,52 +4121,41 @@ recursive subroutine parse_object(unit, parent)
41214121
if (eof) then
41224122
call throw_exception('Error in parse_object:'//&
41234123
' Unexpected end of file while parsing object member.')
4124-
call cleanup()
41254124
return
41264125
else if (':' == c) then
41274126
! parse the value
41284127
call parse_value(unit, pair)
4129-
if (exception_thrown) return
4130-
call json_value_add(parent, pair)
4128+
if (exception_thrown) then
4129+
call json_destroy(pair)
4130+
return
4131+
else
4132+
call json_value_add(parent, pair)
4133+
end if
41314134
else
41324135
call throw_exception('Error in parse_object:'//&
41334136
' Expecting : and then a value: '//c)
4134-
call cleanup()
41354137
return
41364138
end if
41374139

41384140
! another possible pair
41394141
c = pop_char(unit, eof = eof, skip_ws = .true.)
41404142
if (eof) then
4141-
call cleanup()
4143+
call throw_exception('Error in parse_object: '//&
4144+
'End of file encountered when parsing an object')
41424145
return
41434146
else if (',' == c) then
41444147
! read the next member
41454148
call parse_object(unit = unit, parent = parent)
41464149
else if ('}' == c) then
4147-
call cleanup()
4150+
! end of object
41484151
return
41494152
else
41504153
call throw_exception('Error in parse_object: Expecting end of object: '//c)
4151-
call cleanup()
41524154
return
41534155
end if
41544156

4155-
call cleanup()
4156-
41574157
end if
41584158

4159-
contains
4160-
4161-
!cleanup routine:
4162-
subroutine cleanup()
4163-
4164-
implicit none
4165-
4166-
if (associated(pair)) nullify(pair)
4167-
4168-
end subroutine cleanup
4169-
41704159
end subroutine parse_object
41714160
!*****************************************************************************************
41724161

@@ -4200,8 +4189,11 @@ subroutine parse_array(unit, array)
42004189
nullify(element)
42014190
call json_value_create(element)
42024191
call parse_value(unit, element)
4203-
if (exception_thrown) exit
4204-
4192+
if (exception_thrown) then
4193+
if (associated(element)) call json_destroy(element)
4194+
exit
4195+
end if
4196+
42054197
! parse value will disassociate an empty array value
42064198
if (associated(element)) call json_value_add(array, element)
42074199

0 commit comments

Comments
 (0)