Dereferencing Ptr{Ptr{Int32}}

Hi I’m using the
Julia C interface to call a function from my dll
Everything works fine

Until I try to dereference it

first_row = unsafe_load(result_ptr)
firsr_num = unsafe_load(first_row)
#=
The matrix form is something like this 3x3
[ [ 1 0 0 ] [ 0 0 0 ] [0 0 0] ] 
=#
-> 1

This is okay, but if I want to iterate over result_ptr, the code will crash.
I think it is something like accessing NULL, after the first time dereferencing result_ptr it goes out of scope, I guess. So iteration can not be continued.
for example calling after the above example first_row = unsafe_load(result_ptr+1) will crash the program.
My question is, how should I iterate over result_ptr?

You probably should do unsafe_load(result_ptr, 2) rather than unsafe_load(result_ptr + 1). Julia doesn’t do pointer arithmetic like C does.

1 Like

If this is an actual Matrix and not an array of pointers, you could also use unsafe_wrap on the pointer so you don’t have to deal with pointers in your julia code.

Thanks, but it is not what I want at all
this is what the dereferenced result must be:

2 0 0
0 0 2
1 0 0

but trying this

for i in 1:3
    int_ptr = unsafe_load(result_ptr,1)
    for j in 1:3
        value = unsafe_load(int_ptr,j)
        println(value)
    end
end

but the this is how it does it: when i=1 , unsafe_load(int_ptr,3) should be int[0][2] but it is int[1][1].
But when i=3, unsafe_load(int_ptr,1) it is correct.!
This shows that it only works properly for the first element of each row.

it is not

this is what I got for the iteration:

2 0 2
0 0 462174787
1 0 453865397

as you can see even the last indices are garbage values

I made a typo here: (it is i not 1)

for i in 1:3
    int_ptr = unsafe_load(result_ptr,i)
    for j in 1:3
        value = unsafe_load(int_ptr,j)
        println(value)
    end
end

That’s quite an odd reaction to a suggestion that lets you avoid a hard crash.

But only you know how your data looks, so we can’t help you with more than the obvious mistakes.

2 Likes

the interesting behavior was that when you try to access out of the bound element it crashes! I have no idea why the returning values have garbage values.
memory scan shows values are true values! it is only the Julia that is behaving strangely.

yeah Thanks for that, But that was not my Question,

Apologies for missing that you have an array of pointers - could you share a complete example, so that we can see the code crash on our machines?

The crash problem was solved thanks to

GunnarFarneback

but My main question remains unsolved.
How to dereference a Ptr{Ptr{Int32}}?
How do you extract all elements from it?
this is the DLL function signature:

int** Answer(int**);

how do you deal with that one?
I want to learn how to dereference nested pointers properly.

Your latest code looks good to me. If I create some artificial data it gives the expected results.

julia> x1 = Int32[0, 1, 2]; x2 = Int32[2, 3, 3]; x3 = Int32[2, 1, 1];

julia> data = [pointer(x1), pointer(x2), pointer(x3)];

julia> result_ptr = pointer(data)
Ptr{Ptr{Int32}} @0x00007aa6ae7f6e30

julia> for i in 1:3
           int_ptr = unsafe_load(result_ptr,i)
           for j in 1:3
               value = unsafe_load(int_ptr,j)
               println(value)
           end
       end
0
1
2
2
3
3
2
1
1

Apparently the data you get from your dll is somehow different but I have no way of guessing in what way. Maybe you can share what you found in your memory scan?

1 Like

I tested the following on Linux.

Created lib.c:

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

int** new_array() {
    int** array = malloc(sizeof(int*) * 4);
    for (int i = 0; i < 4; i++) {
        array[i] = malloc(sizeof(int) * 5);
        for (int j = 0; j < 5; j++) {
            array[i][j] = 4 * i + j;
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }
    return array;
}

Compiled with gcc -shared -o lib.so -fPIC lib.c.

I tried two options:

function new_array_wrap()
    ptr = ccall((:new_array, "./lib.so"), Ptr{Ptr{Int32}}, ())
    ptr_arr = unsafe_wrap(Array, ptr, 4)
    return [unsafe_wrap(Array, p, 5) for p in ptr_arr]
end

function new_array_load()
    ptr = ccall((:new_array, "./lib.so"), Ptr{Ptr{Int32}}, ())
    array = Array{Int32}(undef, 4, 5)
    for i in 1:4
        ptr_arr = unsafe_load(ptr, i)
        for j in 1:5
            array[i, j] = unsafe_load(ptr_arr, j)
        end
    end
    return array
end

I am getting:

julia> new_array_wrap()
0 1 2 3 4
4 5 6 7 8
8 9 10 11 12
12 13 14 15 16
4-element Vector{Vector{Int32}}:
 [0, 1, 2, 3, 4]
 [4, 5, 6, 7, 8]
 [8, 9, 10, 11, 12]
 [12, 13, 14, 15, 16]

julia> new_array_load()
0 1 2 3 4
4 5 6 7 8
8 9 10 11 12
12 13 14 15 16
4×5 Matrix{Int32}:
  0   1   2   3   4
  4   5   6   7   8
  8   9  10  11  12
 12  13  14  15  16

unsafe_wrap might not be suitable for you (check the documentation). Also, this example does not free the memory, which you should do.

1 Like

Sadly I can’t do anything with the DLL since I’m on Linux.

1 Like

yes that worked on my machine too!
But I’m also doing allocation which requiresint**

int** Answer(int**);

maybe the problem is here:

a = fill(0,(3,3))
a[3,1]=1
array_of_int_pointers = Array{Ptr{Cint}}(undef, 3,3)

for i in 1:3, j in 1:3
    array_of_int_pointers[i, j] = Libc.malloc(Csize_t(sizeof(Cint)))
    unsafe_store!(array_of_int_pointers[i, j],a[i,j])
    
end

also here free is not needed, after the program has closed, memory will reclaim by Windows.

(post deleted by author)

Just for those who don’t know, IdaPro is a disassembling/binary inspection tool, commonly used for reverse engineering.

Personally, I’d be extremely suspicious of some random DLL/.so that I’m asked to download to verify a problem. Can you not share a minimal C example that we can compile ourselves?

3 Likes

I don’t have time to dig deeper into this, but if I did my approach would be to print out every relevant address and memory content from the C program immediately before the return from the function. Then I would compare those to the pointer addresses and dereferenced values in Julia to pinpoint exactly where things diverge. In my experience this usually resolves matters in one way or another, though not always pointing to the problem I thought I had.

Thanks for your efforts. Pointers are valid. I wonder if this is a Windows-specific problem.
because I only had this issue with Julia, tried that C code in C#, python and they were all fine. also, the compiler is MSVC not gcc or Clang.cl.exe /LD source.c .
I was surprised to see many Linux users here, because of buggy Nvidia drivers they had to deal with.