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

LXM.Pure GC bug #6

Closed
bagnalla opened this issue Feb 25, 2024 · 2 comments
Closed

LXM.Pure GC bug #6

bagnalla opened this issue Feb 25, 2024 · 2 comments

Comments

@bagnalla
Copy link

Hi, I've been using the LXM.Pure interface and have encountered some strange/erroneous behavior (described in detail here).

Basically, the sequence of random values produced by the PRNG is sometimes incorrect, and this happens when the GC runs a minor collection. After some experimentation, I managed to fix the example linked above in my local environment by changing pringo_LXM_copy and pringo_LXM_init_unboxed from

CAMLprim value pringo_LXM_copy(value v)
{
  value res = caml_alloc_small(Wsizeof(struct LXM_state), Abstract_tag);
  memcpy(LXM_val(res), LXM_val(v), sizeof(struct LXM_state));
  return res;
}

CAMLprim value pringo_LXM_init_unboxed(uint64_t i1, uint64_t i2,
                                       uint64_t i3, uint64_t i4)
{
  value v = caml_alloc_small(Wsizeof(struct LXM_state), Abstract_tag);
  struct LXM_state * st = LXM_val(v);
  st->a = i1 | 1;    /* must be odd */
  st->x[0] = i2 != 0 ? i2 : 1; /* must be nonzero */
  st->x[1] = i3 != 0 ? i3 : 2; /* must be nonzero */
  st->s = i4;
  return v;
}

to

CAMLprim value pringo_LXM_copy(value v)
{
  CAMLparam1(v);
  value res = caml_alloc_small(Wsizeof(struct LXM_state), Abstract_tag);
  memcpy(LXM_val(res), LXM_val(v), sizeof(struct LXM_state));
  CAMLreturn(res);
}

CAMLprim value pringo_LXM_init_unboxed(uint64_t i1, uint64_t i2,
                                       uint64_t i3, uint64_t i4)
{
  CAMLparam0();
  CAMLlocal1(v);
  v = caml_alloc_small(Wsizeof(struct LXM_state), Abstract_tag);
  struct LXM_state * st = LXM_val(v);
  st->a = i1 | 1;    /* must be odd */
  st->x[0] = i2 != 0 ? i2 : 1; /* must be nonzero */
  st->x[1] = i3 != 0 ? i3 : 2; /* must be nonzero */
  st->s = i4;
  CAMLreturn(v);
}

I don't fully understand what the problem is, but it seems that maybe the original versions of these functions do not properly register the objects they create with the GC/runtime, so those objects end up getting garbled after the GC runs (perhaps being written over by subsequent allocations?).

I also noticed that the OCaml stdlib Random module uses the same LXM implementation, but it does all of its allocations on the OCaml side so I don't think it should suffer from this problem.

Side note: setting OCAMLRUNPARAM='v=0x02' to print minor collection messages seems to not work on OCaml 5.1.1... I don't know if I'm doing something wrong or if that's a bug that should be reported on the main OCaml repo.

-- Alex

@xavierleroy
Copy link
Owner

I agree this is a bug. I'll fix it in a few weeks, when I have more time for library maintenance. Thanks for your feedback.

@xavierleroy
Copy link
Owner

xavierleroy commented Mar 27, 2024

pringo_LXM_init_unboxed doesn't need a root registration, but pringo_LXM_copy definitely does !

Fixed as proposed by commit b94865d

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

2 participants