Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Accessing values in received array of struct #959

Closed
calicoday opened this issue Jun 6, 2022 · 0 comments
Closed

Accessing values in received array of struct #959

calicoday opened this issue Jun 6, 2022 · 0 comments

Comments

@calicoday
Copy link

calicoday commented Jun 6, 2022

Edit 3: Solved! As I suspected, my C library was wrong and fooling me -- looping over the array to set the struct values, I was adding sizeof(Simple) to the pointer, not recalling the pointer knows it's Simple type and only needs to be incremented. Sorry for the bother.

Hi, all. I'm struggling to read the values of an array of struct malloc'd and returned by a C library. I'm using a pointer to step through the array as kojix2 mentions in their request for a read_array_of_struct #956 but it's not working for me. The first element is fine, all subsequent are gibberish. Returning the array as void * or Simple.byRef makes no difference.

I expect it's something dumb, or even that my C is wrong and misleading me, but I just can't see it. Or maybe there are platform issues I should be looking at? Maybe it's obvious to someone else? Any hints are welcome!

I'm running on a M1 2020 Macbook Pro under Big Sur with ruby 2.6.8p205 (2021-07-07 revision 67951) [arm64-darwin20]. But I get the same results on an intel 2015 Macbook Air under Mojave with ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin20].

Edit: Ah, ok, seems there are tricky snags re Ruby and arm vs x86 and what am I really even running?! Don't know if that's this but I'll have to sort it to find out.

Edit 2: Ok, I've got the gist of the arm vs x86 issue and I've further run my samples on an x86 Linux box with the same results. Back to my original theory, I must be making some dumb little mistake I can't find. Argh.

Here are my samples...

C library libpotato with:

typedef struct {
  uint32_t one;
  uint32_t two;
} Simple;

uint16_t *mk_arr(void){
  uint16_t *arr = malloc(sizeof(uint16_t) * 7);
  int j;
  // set values 2, 3, 4, 5, 6, 7, 8
  for(j=0; j < 7; j++){
    arr[j] = j + 2;
  }
  return arr;
}

Simple *mk_multi_simple(void) {
  Simple *sp = malloc(sizeof(Simple) * 3);
  int j;
  Simple *up;
  // set values [{1, 2}, {3, 4}, {5, 6}]
  for(j=0; j < 3; j++){
    up = sp + j*sizeof(Simple);
    up->one = 1 + j*2;
    up->two = 2 + j*2;
  }
  return sp;
}

void *mk_multi_simple_by_pointer(void) {
  return (void *)mk_multi_simple();
}

C test program potato.c with:

  printf("sizeof(Simple): %lu\n", sizeof(Simple));

  printf("mk_arr:\n  ");
  uint16_t *arr = mk_arr();
  for(int j=0; j < 7; j++){
    printf("%u, ", arr[j]);
  }
  printf("\n");
  
  Simple *sp = mk_multi_simple();
  Simple *up;
  printf("mk_multi_simple:\n");
  for(int j=0; j < 3; j++){
    up = sp + j*sizeof(Simple);
    printf("  %d one, two: %d, %d\n", j, up->one, up->two);
  }

results, as expected:

sizeof(Simple): 8
mk_arr:
  2, 3, 4, 5, 6, 7, 8, 
mk_multi_simple:
  0 one, two: 1, 2
  1 one, two: 3, 4
  2 one, two: 5, 6

Ruby gem potato_ffi-0.0.1.gem with:

  class Simple < FFI::Struct
    layout(
      :one, :uint32,
      :two, :uint32
    )
  end
  
  attach_function :mk_simple, [], Simple.by_ref
  attach_function :mk_multi_simple, [], Simple.by_ref
  attach_function :mk_multi_simple_by_pointer, [], :pointer

Ruby test program potato.rb with:

puts "Simple.size: #{PotatoFFI::Simple.size}"

ret = PotatoFFI::mk_arr
arrp = FFI::Pointer.new(:uint16, ret)
puts "mk_arr arr:"
puts "  " + 7.times.map{|i| arrp[i].read(FFI::TYPE_UINT16)}.join(", ")

puts "mk_multi_simple:"
ret = PotatoFFI::mk_multi_simple
puts "  (#{ret.inspect})"
3.times do |i|
  sp = PotatoFFI::Simple.new(ret.to_ptr + i * PotatoFFI::Simple.size)
  puts "  #{i} one, two: #{sp[:one]}, #{sp[:two]} (#{sp.inspect})"
end

puts "mk_multi_simple_by_pointer:"
ret = PotatoFFI::mk_multi_simple_by_pointer
puts "  (#{ret.inspect})"
3.times do |i|
  sp = PotatoFFI::Simple.new(ret + i * PotatoFFI::Simple.size)
  puts "  #{i} one, two: #{sp[:one]}, #{sp[:two]} (#{sp.inspect})"
end

results:

Simple.size: 8
mk_arr arr:
  2, 3, 4, 5, 6, 7, 8
mk_multi_simple:
  (#<PotatoFFI::Simple:0x000000012d9a0de8>)
  0 one, two: 1, 2 (#<PotatoFFI::Simple:0x000000012d9a0ac8>)
  1 one, two: 0, 2147483648 (#<PotatoFFI::Simple:0x000000012d9a06e0>)
  2 one, two: 765067289, 1 (#<PotatoFFI::Simple:0x000000012d9a0320>)
mk_multi_simple_by_pointer:
  (#<FFI::Pointer address=0x0000000138186ce0>)
  0 one, two: 1, 2 (#<PotatoFFI::Simple:0x000000012d99bb18>)
  1 one, two: 0, 2147483648 (#<PotatoFFI::Simple:0x000000012d99ad58>)
  2 one, two: 2, 2147483648 (#<PotatoFFI::Simple:0x000000012d99a830>)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant