Skip to content

Reading an empty JSON array allocates a random length FORTRAN array #276

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
andreafdaf opened this issue Mar 30, 2017 · 4 comments
Closed
Assignees

Comments

@andreafdaf
Copy link

andreafdaf commented Mar 30, 2017

Hello! First of all thanks a lot for this library, you're saving my life!

Now let's come to the issue, this is an example code:

program array_test
    use json_module
    implicit none

    integer,dimension(:), allocatable :: integerArray1
    integer,dimension(:), allocatable :: integerArray2
    integer,dimension(:), allocatable :: integerArray3
    integer,dimension(:), allocatable :: integerArray4
    type(json_file) :: json
    logical :: found

    call json%initialize()
    if (json%failed()) then
        call exit(1)
    end if

    call json%load_from_string('{"values": [], "values2": [], "values3": [], "values4": []}')
    if (json%failed()) then
        call exit(2)
    else
        call json%print_file()
        if (json%failed()) then
            call exit(3)
        end if

        call json%get('values', integerArray1, found)
        if (json%failed()) then
            call exit(4)
        end if
        if (found) then
            print *, integerArray1(:)
            print *, size(integerArray1)
        end if


        call json%get('values2', integerArray2, found)
        if (json%failed()) then
            call exit(4)
        end if
        if (found) then
            print *, integerArray2(:)
            print *, size(integerArray2)
        end if


        call json%get('values3', integerArray3, found)
        if (json%failed()) then
            call exit(4)
        end if
        if (found) then
            print *, integerArray3(:)
            print *, size(integerArray3)
        end if


        call json%get('values4', integerArray4, found)
        if (json%failed()) then
            call exit(4)
        end if
        if (found) then
            print *, integerArray4(:)
            print *, size(integerArray4)
        end if

        call json%destroy()
        if (json%failed()) then
            call exit(5)
        end if
    end if
end program array_test

and the output is:

{
  "values": [],
  "values2": [],
  "values3": [],
  "values4": []
}
           1
 -1957320307
           1
           2

Since I'm reading those values from a DB I cannot know how long those arrays will be, so there is no check I can do to work it out...

built using: build.sh
OS: x86_64 Ubuntu 16.04
compile command: gfortran -funderscoring -O0 -g -Wall -c -fmessage-length=0 -o "array_test.o" "../array_test.f90"
link command: gfortran -L"/home/andrea/workspace/strutture-energia/fortran-test" -o "array-test" ./array_test.o -ljsonfortran
gfortran -v output:

Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.4' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) 
@jacobwilliams
Copy link
Owner

I think because the arrays are empty in JSON, they are coming back from the get routines unallocated. So, I think you are getting garbage values (probably with different compiler settings, it would crash).

You could check if they are allocated using something like:

   if (.not. allocated(integerArray1)) then
       write(*,*) 'integerArray1 is empty!' 
   end if

For this case, I wonder if I should have the routine return the vector allocated, but with 0 length? Is that possible in Fortran? (I've never tried it)

Also, because you are using the found argument, you should check that instead of json%failed (found will clear any exceptions that may have happened). So:

        call json%get('values4', integerArray4, found)
        if (found) then
            print *, integerArray4(:)
            print *, size(integerArray4)
        else
            call exit(4)
        end if

@andreafdaf
Copy link
Author

andreafdaf commented Mar 30, 2017

Hi! Thanks for such a quick reply!

I think you're right, checking for allocation is the way to go and works perfectly 👍

As for the 0-length array, well... I'm not a Fortran guy so from other languages perspective I find it useful to have the difference: this JSON value doesn't exist VS this JSON value is an array with 0 length

I just tried on gfortran and compiling this works fine and prints 0:

    integer,dimension(0) :: arrayNull
    print *, size(arrayNull)

But I don't know about other compilers

And thanks for the tip ✌️

@jacobwilliams
Copy link
Owner

I'll look into the 0-length array thing and see if that is standard...

@jacobwilliams
Copy link
Owner

According to "Modern Fortran Explained", zero-sized arrays are allowed. So, I think I'll make that change to the code. I agree, it corresponds better to the JSON [] array, rather than having to always check if it is allocated.

jacobwilliams added a commit that referenced this issue Apr 2, 2017
@jacobwilliams jacobwilliams self-assigned this Apr 2, 2017
jacobwilliams added a commit that referenced this issue Apr 2, 2017
* When reading an empty JSON array it is now returned as an allocated array with zero length.
Fixes #276

* fixed unicode issues in last commit.
# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

2 participants