Skip to content

Commit 95e91af

Browse files
committed
range_str: allocate temporaries on the R heap
Avoid memory leaks from potential long jumps in hash_set().
1 parent b380969 commit 95e91af

File tree

1 file changed

+5
-11
lines changed

1 file changed

+5
-11
lines changed

src/forder.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,11 @@ static void range_str(const SEXP *x, int n, uint64_t *out_min, uint64_t *out_max
348348
return;
349349
}
350350
if (anynotutf8) {
351+
void *vmax = vmaxget();
351352
SEXP ustr2 = PROTECT(allocVector(STRSXP, ustr_n));
352353
for (int i=0; i<ustr_n; i++) SET_STRING_ELT(ustr2, i, ENC2UTF8(ustr[i]));
353-
SEXP *ustr3 = malloc(sizeof(*ustr3) * ustr_n);
354-
if (!ustr3)
355-
STOP(_("Failed to alloc ustr3 when converting strings to UTF8")); // # nocov
356-
memcpy(ustr3, STRING_PTR_RO(ustr2), sizeof(SEXP) * ustr_n);
354+
SEXP *ustr3 = (SEXP *)R_alloc(sizeof(*ustr3), ustr_n);
355+
memcpy(ustr3, STRING_PTR_RO(ustr2), sizeof(*ustr3) * ustr_n);
357356
// need to reset ustr_maxlen because we need ustr_maxlen for utf8 strings
358357
ustr_maxlen = 0;
359358
for (int i=0; i<ustr_n; i++) {
@@ -368,18 +367,13 @@ static void range_str(const SEXP *x, int n, uint64_t *out_min, uint64_t *out_max
368367
hash_set(marks, ustr3[i], --o);
369368
}
370369
// now use the 1-1 mapping from ustr to ustr2 to get the ordering back into original ustr, being careful to reset tl to 0
371-
int *tl = malloc(sizeof(*tl) * ustr_n);
372-
if (!tl) {
373-
free(ustr3); // # nocov
374-
STOP(_("Failed to alloc tl when converting strings to UTF8")); // # nocov
375-
}
370+
int *tl = (int *)R_alloc(sizeof(*tl), ustr_n);
376371
const SEXP *tt = STRING_PTR_RO(ustr2);
377372
for (int i=0; i<ustr_n; i++) tl[i] = hash_lookup(marks, tt[i], 0); // fetches the o in ustr3 into tl which is ordered by ustr
378373
for (int i=0; i<ustr_n; i++) hash_set(marks, ustr3[i], 0); // reset to 0 tl of the UTF8 (and possibly non-UTF in ustr too)
379374
for (int i=0; i<ustr_n; i++) hash_set(marks, ustr[i], tl[i]); // put back the o into ustr's tl
380-
free(tl);
381-
free(ustr3);
382375
UNPROTECT(1);
376+
vmaxset(vmax);
383377
*out_min = 1;
384378
*out_max = -o; // could be less than ustr_n if there are duplicates in the utf8s
385379
} else {

0 commit comments

Comments
 (0)