Skip to content

Commit d28cce9

Browse files
Avoid memcpy() of empty vector (#6911)
* Avoid memcpy() of empty vector * in getidcols() too * Add a test case Distilled from the `melt()` call here: https://github.com/gdemin/expss/blob/d498caf72a9938ac71b9e06fd61485cd0347d607/tests/testthat/test_subtotal.R#L161-L166
1 parent a08c1bc commit d28cce9

File tree

2 files changed

+13
-8
lines changed

2 files changed

+13
-8
lines changed

inst/tests/tests.Rraw

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21129,3 +21129,8 @@ test(2311.2, nlevels(DT$V1), 2L) # used to be 3
2112921129
# avoid translateChar*() in OpenMP threads, #6883
2113021130
DF = list(rep(iconv("\uf8", from = "UTF-8", to = "latin1"), 2e6))
2113121131
test(2312, fwrite(DF, nullfile(), encoding = "UTF-8", nThread = 2L), NULL)
21132+
21133+
# avoid memcpy of 0-length inputs
21134+
test(2313,
21135+
melt(data.table(a=numeric(), b=numeric(), c=numeric()), id.vars=c('a', 'b')),
21136+
data.table(a=numeric(), b=numeric(), variable=factor(levels='c'), value=numeric()))

src/fmelt.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -552,23 +552,23 @@ SEXP getvaluecols(SEXP DT, SEXP dtnames, Rboolean valfactor, Rboolean verbose, s
552552
//TODO complex value type: case CPLXSXP: { } break;
553553
case REALSXP : {
554554
double *dtarget = REAL(target);
555-
const double *dthiscol = REAL(thiscol);
555+
const double *dthiscol = REAL_RO(thiscol);
556556
if (data->narm) {
557557
for (int k=0; k<thislen; ++k)
558558
dtarget[counter + k] = dthiscol[ithisidx[k]-1];
559-
} else {
559+
} else if (data->nrow) {
560560
memcpy(dtarget + j*data->nrow, dthiscol, data->nrow*size);
561561
}
562562
}
563563
break;
564564
case INTSXP :
565565
case LGLSXP : {
566566
int *itarget = INTEGER(target);
567-
const int *ithiscol = INTEGER(thiscol);
567+
const int *ithiscol = INTEGER_RO(thiscol);
568568
if (data->narm) {
569569
for (int k=0; k<thislen; ++k)
570570
itarget[counter + k] = ithiscol[ithisidx[k]-1];
571-
} else {
571+
} else if (data->nrow) {
572572
memcpy(itarget + j*data->nrow, ithiscol, data->nrow*size);
573573
}
574574
} break;
@@ -704,7 +704,7 @@ SEXP getidcols(SEXP DT, SEXP dtnames, Rboolean verbose, struct processData *data
704704
switch(TYPEOF(thiscol)) {
705705
case REALSXP : {
706706
double *dtarget = REAL(target);
707-
const double *dthiscol = REAL(thiscol);
707+
const double *dthiscol = REAL_RO(thiscol);
708708
if (data->narm) {
709709
for (int j=0; j<data->lmax; ++j) {
710710
SEXP thisidx = VECTOR_ELT(data->not_NA_indices, j);
@@ -714,7 +714,7 @@ SEXP getidcols(SEXP DT, SEXP dtnames, Rboolean verbose, struct processData *data
714714
dtarget[counter + k] = dthiscol[ithisidx[k]-1];
715715
counter += thislen;
716716
}
717-
} else {
717+
} else if (data->nrow) {
718718
for (int j=0; j<data->lmax; ++j)
719719
memcpy(dtarget + j*data->nrow, dthiscol, data->nrow*size);
720720
}
@@ -723,7 +723,7 @@ SEXP getidcols(SEXP DT, SEXP dtnames, Rboolean verbose, struct processData *data
723723
case INTSXP :
724724
case LGLSXP : {
725725
int *itarget = INTEGER(target);
726-
const int *ithiscol = INTEGER(thiscol);
726+
const int *ithiscol = INTEGER_RO(thiscol);
727727
if (data->narm) {
728728
for (int j=0; j<data->lmax; ++j) {
729729
SEXP thisidx = VECTOR_ELT(data->not_NA_indices, j);
@@ -733,7 +733,7 @@ SEXP getidcols(SEXP DT, SEXP dtnames, Rboolean verbose, struct processData *data
733733
itarget[counter + k] = ithiscol[ithisidx[k]-1];
734734
counter += thislen;
735735
}
736-
} else {
736+
} else if (data->nrow) {
737737
for (int j=0; j<data->lmax; ++j)
738738
memcpy(itarget + j*data->nrow, ithiscol, data->nrow*size);
739739
}

0 commit comments

Comments
 (0)