Permalink
Browse files

PR#7568: address potential GC issue with caml_format_float

- add a caml_alloc_sprintf_ function taking a pointer to the format
  string as first argument

- in caml_format_float, register the OCaml format string as a GC root
  and pass it to this new caml_alloc_sprintf_
  • Loading branch information...
oandrieu committed Jan 27, 2017
1 parent 8ab0ac0 commit 6b56448fcf1d41886e09137a29a7dcc029abe1cb
Showing with 43 additions and 19 deletions.
  1. +1 −0 byterun/caml/alloc.h
  2. +4 −3 byterun/floats.c
  3. +38 −16 byterun/str.c
View
@@ -41,6 +41,7 @@ CAMLextern value caml_copy_nativeint (intnat); /* defined in [ints.c] */
CAMLextern value caml_alloc_array (value (*funct) (char const *),
char const ** array);
CAMLextern value caml_alloc_sprintf(const char * format, ...);
CAMLextern value caml_alloc_sprintf_(const char ** format, ...);
CAMLextern value caml_alloc_with_profinfo (mlsize_t, tag_t, intnat);
CAMLextern value caml_alloc_small_with_my_or_given_profinfo (
View
@@ -81,13 +81,14 @@ CAMLexport value caml_copy_double(double d)
CAMLprim value caml_format_float(value fmt, value arg)
{
value res;
CAMLparam2(fmt, arg);
CAMLlocal1(res);
double d = Double_val(arg);
#ifdef HAS_BROKEN_PRINTF
if (isfinite(d)) {
#endif
res = caml_alloc_sprintf(String_val(fmt), d);
res = caml_alloc_sprintf_((const char **) &fmt, d);
#ifdef HAS_BROKEN_PRINTF
} else {
if (isnan(d)) {
@@ -100,7 +101,7 @@ CAMLprim value caml_format_float(value fmt, value arg)
}
}
#endif
return res;
CAMLreturn(res);
}
CAMLprim value caml_hexstring_of_float(value arg, value vprec, value vstyle)
View
@@ -377,22 +377,44 @@ CAMLprim value caml_bitvect_test(value bv, value n)
return Val_int(Byte_u(bv, pos >> 3) & (1 << (pos & 7)));
}
static value caml_alloc_vsprintf(const char ** format, va_list args);
CAMLexport value caml_alloc_sprintf(const char * format, ...)
{
va_list args;
va_list ap;
value r;
va_start(ap, format);
r = caml_alloc_vsprintf(&format, ap);
va_end(ap);
return r;
}
CAMLexport value caml_alloc_sprintf_(const char ** format, ...)
{
va_list ap;
value r;
va_start(ap, format);
r = caml_alloc_vsprintf(format, ap);
va_end(ap);
return r;
}
static value caml_alloc_vsprintf(const char ** format, va_list args)
{
va_list args_cpy;
char buf[64];
int n;
value res;
#if !defined(_WIN32) || defined(_UCRT)
/* C99-compliant implementation */
va_start(args, format);
va_copy(args_cpy, args);
/* "vsnprintf(dest, sz, format, args)" writes at most "sz" characters
into "dest", including the terminating '\0'.
It returns the number of characters of the formatted string,
excluding the terminating '\0'. */
n = vsnprintf(buf, sizeof(buf), format, args);
va_end(args);
n = vsnprintf(buf, sizeof(buf), *format, args_cpy);
va_end(args_cpy);
/* Allocate a Caml string with length "n" as computed by vsnprintf. */
res = caml_alloc_string(n);
if (n < sizeof(buf)) {
@@ -403,22 +425,22 @@ CAMLexport value caml_alloc_sprintf(const char * format, ...)
/* Re-do the formatting, outputting directly in the Caml string.
Note that caml_alloc_string left room for a '\0' at position n,
so the size passed to vsnprintf is n+1. */
va_start(args, format);
vsnprintf(String_val(res), n + 1, format, args);
va_end(args);
va_copy(args_cpy, args);
vsnprintf(String_val(res), n + 1, *format, args_cpy);
va_end(args_cpy);
}
return res;
#else
/* Implementation specific to the Microsoft CRT library */
va_start(args, format);
va_copy(args_cpy, args);
/* "_vsnprintf(dest, sz, format, args)" writes at most "sz" characters
into "dest". Let "len" be the number of characters of the formatted
string.
If "len" < "sz", a null terminator was appended, and "len" is returned.
If "len" == "sz", no null termination, and "len" is returned.
If "len" > "sz", a negative value is returned. */
n = _vsnprintf(buf, sizeof(buf), format, args);
va_end(args);
n = _vsnprintf(buf, sizeof(buf), *format, args_cpy);
va_end(args_cpy);
if (n >= 0 && n <= sizeof(buf)) {
/* All output characters were written to buf.
"n" is the actual length of the output.
@@ -427,16 +449,16 @@ CAMLexport value caml_alloc_sprintf(const char * format, ...)
memcpy(String_val(res), buf, n);
} else {
/* Determine actual length of output, excluding final '\0' */
va_start(args, format);
n = _vscprintf(format, args);
va_end(args);
va_copy(args_cpy, args);
n = _vscprintf(*format, args_cpy);
va_end(args_cpy);
res = caml_alloc_string(n);
/* Re-do the formatting, outputting directly in the Caml string.
Note that caml_alloc_string left room for a '\0' at position n,
so the size passed to _vsnprintf is n+1. */
va_start(args, format);
_vsnprintf(String_val(res), n + 1, format, args);
va_end(args);
va_copy(args_cpy, args);
_vsnprintf(String_val(res), n + 1, *format, args_cpy);
va_end(args_cpy);
}
return res;
#endif

0 comments on commit 6b56448

Please sign in to comment.