How to populate immutable string in C stubs?

While chasing the root cause of initialization discards 'const' qualifier from pointer target type I adjusted OCaml to pass -Werror=discarded-qualifiers in global CFLAGS. As a result a large number of packages started to fail.

The common pattern is code like this:

value = caml_alloc_string(len);
memcpy(String_val(value), srcptr, len);

There are a number of different patterns in the various projects to populate the allocated memory. I wonder what the prefered way is to get a non-const C pointer.
Is there a need to use either String_val() or Bytes_val() API?
Is &Byte(value,0) a valid way to obtain a non-const pointer?

I found patterns like this, all of them seem to be valid, depending on the prototype of fn() :

fn(&Byte(value, 0), srcptr, len);
fn(Bytes_val(value), srcptr, len);
fn((ptrtype*)String_val(value), srcptr, len);
fn(&Byte_u(value, 0), srcptr, len);
fn(&Byte(String_val(value), 0), srcptr, len);

Since OCaml 4.06 caml_alloc_initialized_string() exists, but most projects try to support older OCaml versions.

I think the following three idioms are fine:

fn(&Byte(value, 0), srcptr, len);
fn(Bytes_val(value), srcptr, len);
fn(&Byte_u(value, 0), srcptr, len);

The last two give an unsigned char * and the first one a char *.

The following feels wrong to me:

fn(&Byte(String_val(value), 0), srcptr, len);

Morally, the Byte macro expects an OCaml value as first argument, not a const char * as returned by String_val.

1 Like