# Undefined behaviour of ccall

**URL:** <https://discourse.julialang.org/t/undefined-behaviour-of-ccall/122496>\
**Category:** General Usage\
**Created:** [November 11, 2024, 2:16pm UTC](https://discourse.julialang.org/t/undefined-behaviour-of-ccall/122496 "2024-11-11T14:16:13Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![kmiernik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kmiernik/32/202783_2.png) [@kmiernik](https://discourse.julialang.org/u/kmiernik)\
**Post date:** [November 11, 2024, 2:16pm UTC](https://discourse.julialang.org/t/undefined-behaviour-of-ccall/122496/1 "2024-11-11T14:16:13Z")

</div>

I have been using my julia wrapper for some c-library called fasterac (for use with digital electronics ([https://faster.in2p3.fr/](https://faster.in2p3.fr/)). It has been working fine, and I processed many TB of data with it. With Julia 1.11 (and as I tested, also 1.10) I came across a weird undefined behavior. It seems that library call (faster\_file\_reader\_open) cannot access file, and instead of file pointer returns null. This happens randomly.

Here is an example in plain C

```julia
#include <stdio.h>
#include <stdlib.h>

#include "fasterac/fasterac.h"
#include "fasterac/utils.h"

int inspect(char* filename) {
    faster_file_reader_p reader; 
    faster_data_p data;

    reader = faster_file_reader_open (filename);  
    if (reader == NULL) {
        return -1;
    }

    int n = 0;
    while ((data = faster_file_reader_next (reader)) != NULL) {  
        n = n + 1;                                                
    }                                                         
    faster_file_reader_close(reader);                      
    return n;
}

int main (int argc, char** argv) {
  int good = 0;
  int bad = 0;
  for (int i = 0; i < 10000; i++) {
    int n = inspect(argv[1]);
    if (n > 0)
        good += 1;
    else
        bad += 1;
  }
  printf("Good: %d, Bad: %d \n", good, bad);
  return 0;
}

```

And an equivalent minimal example in Julia.

```julia
using Printf

function file_reader_open(filename::String)
    datafile = Vector{UInt8}(filename)
    reader = ccall((:faster_file_reader_open, "libfasterac.so"),
                   Ptr{Cvoid}, (Ptr{UInt8}, ), 
                   datafile)
    return reader
end

function file_reader_close(reader)
    void = ccall((:faster_file_reader_close, "libfasterac.so"),
                   Cvoid, (Ptr{Cvoid}, ), 
                   reader)
    return void
end

function file_reader_next(reader)
    data = ccall((:faster_file_reader_next, "libfasterac.so"),
                 Ptr{Cvoid}, (Ptr{Cvoid}, ), 
                   reader)
end

function inspect(filename)
    reader = file_reader_open(filename)
    if reader == C_NULL
        return -1
    end
    n = 0
    while ((data = file_reader_next(reader)) !== C_NULL)
            n += 1
    end
    file_reader_close(reader)
    return n
end

function main()
    bad = 0
    good = 0
    for i in 1:10000
        n = inspect("test_data.fast")
        if n < 0
            bad += 1
        else
            good += 1
        end
    end

    println("Good: $good, Bad: $bad")
end

```

While C code runs without any problem, Julia’s version has success rate about 95%. With a larger input file, the success rate goes down (to about 40%). Problem is in the line

```julia
    reader = ccall((:faster_file_reader_open, "libfasterac.so"),
                   Ptr{Cvoid}, (Ptr{UInt8}, ), 
                   datafile)

```

which returns 0 (NULL) interpreted as “error opening file”. A non-zero value is a proper pointer to the file.

In Julia 1.10 I have similar results. In Julia 1.9 everything works fine (this, and earlier versions I have been using with this wrapper extensively). What may have cause that problem?

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [November 11, 2024, 8:46pm UTC](https://discourse.julialang.org/t/undefined-behaviour-of-ccall/122496/2 "2024-11-11T20:46:22Z")

</div>

I bet what’s happening here is that your `faster_file_reader_open` needs a null-terminated string, but passing a `Ptr{UInt8}` from a vector of `UInt8`s doesn’t necessarily guarantee one. Instead, just simplify this to pass the string itself as a `Cstring`:

```julia
function file_reader_open(filename::String)
    reader = ccall((:faster_file_reader_open, "libfasterac.so"),
                   Ptr{Cvoid}, (Cstring, ), 
                   filename)
    return reader
end

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [November 11, 2024, 8:50pm UTC](https://discourse.julialang.org/t/undefined-behaviour-of-ccall/122496/3 "2024-11-11T20:50:00Z")

</div>

Also, don’t you need `GC.@preserve` for the array argument that’s being passed to the `ccall`?

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [November 11, 2024, 9:35pm UTC](https://discourse.julialang.org/t/undefined-behaviour-of-ccall/122496/4 "2024-11-11T21:35:50Z")

</div>

No, `GC.@preserve` isn’t needed if you’re _explicitly_ passing the object itself directly to `ccall`.

It’s only required if you’re working with raw pointers or the like that _implicitly_ reference objects in a way Julia can’t track.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 11, 2024, 10:23pm UTC](https://discourse.julialang.org/t/undefined-behaviour-of-ccall/122496/5 "2024-11-11T22:23:49Z")

</div>

Oh wow, I had no idea about that. This’d be good to document somewhere.

---

<div class="post-metadata">

**Author:** ![kmiernik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kmiernik/32/202783_2.png) [@kmiernik](https://discourse.julialang.org/u/kmiernik)\
**Post date:** [November 12, 2024, 6:11am UTC](https://discourse.julialang.org/t/undefined-behaviour-of-ccall/122496/6 "2024-11-12T06:11:12Z")

</div>

> [@mbauman](#):
>
> I bet what’s happening here is that your `faster_file_reader_open` needs a null-terminated string, but passing a `Ptr{UInt8}` from a vector of `UInt8`s doesn’t necessarily guarantee one. Instead, just simplify this to pass the string itself as a `Cstring`:

Of course, that was it. And now that’s obvious. Was Julia before 1.10 aligning strings in memory with extra null at the end? Interestingly, that bug never came to the light until recently.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [November 12, 2024, 6:17am UTC](https://discourse.julialang.org/t/undefined-behaviour-of-ccall/122496/7 "2024-11-12T06:17:21Z")

</div>

IIRC, `String` did (and still does) have a trailing NULL, but converting the string to a `Vector{UInt8}` doesn’t copy that into the new vector. It might be that the conversion previously aliased the memory of the `String`, which probably doesn’t happen anymore since `Memory` has become the backing store of `Vector`. That aliasing would then just happen to also be NULL-terminated.
