From 640a09fcf54f0c8712667bc5db027cb84d552d72 Mon Sep 17 00:00:00 2001 From: Ivan K Date: Thu, 18 Jun 2026 14:16:14 +0300 Subject: [PATCH 1/6] test case --- inst/tests/tests.Rraw | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 90e33145e..d69de32af 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -21669,3 +21669,8 @@ test(2375.3, print(data.table(x=c("short", "abcdefghijklmnopqrstuvwxyz"))), outp test(2375.4, print(data.table(x="abcdefghijklmnopqrstuvwxyz")), output="abcdefghijklmnopqrstuvwxyz", options=list(width=200, datatable.prettyprint.char=NULL)) test(2375.5, print(data.table(id=1L, score=99.1, txt="abcdefghijklmnopqrstuvwxyz")), output="abcdefghijklmn...", options=list(width=20, datatable.prettyprint.char=NULL)) test(2375.6, print(data.table(x=rep("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e6)), topn=1), output="1000000: ABCDEFGHIJKLM...", options=list(width=25, datatable.prettyprint.char=NULL)) + +# rbindlist() used to put O(ncol(...)) > R_PPStackSize = 50000 items on the protect stack, #7793 +x = as.data.table(as.list(1:50001)) +test(2376, rbindlist(list(x)), x) +rm(x) From c14dd78fbc04349eccbe2639edf31b296aafb10b Mon Sep 17 00:00:00 2001 From: Ivan K Date: Thu, 18 Jun 2026 13:59:31 +0300 Subject: [PATCH 2/6] Protect coercedForFactor deeper in the stack --- src/rbindlist.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rbindlist.c b/src/rbindlist.c index e8159c1ef..3af2b8b93 100644 --- a/src/rbindlist.c +++ b/src/rbindlist.c @@ -272,7 +272,9 @@ SEXP rbindlist(SEXP l, SEXP usenamesArg, SEXP fillArg, SEXP idcolArg, SEXP ignor } } - SEXP coercedForFactor = NULL; + PROTECT_INDEX IcoercedForFactor; + SEXP coercedForFactor = R_NilValue; + PROTECT_WITH_INDEX(coercedForFactor, &IcoercedForFactor); nprotect++; for(int j=0; j Date: Thu, 18 Jun 2026 14:05:30 +0300 Subject: [PATCH 3/6] Unprotect longestLevels inside the loop --- src/rbindlist.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rbindlist.c b/src/rbindlist.c index 3af2b8b93..9fed04774 100644 --- a/src/rbindlist.c +++ b/src/rbindlist.c @@ -281,7 +281,7 @@ SEXP rbindlist(SEXP l, SEXP usenamesArg, SEXP fillArg, SEXP idcolArg, SEXP ignor int longestLen=-1, longestW=-1, longestI=-1; // just for ordered factor; longestLen must be initialized as -1 so that rbind zero-length ordered factor could work #4795 PROTECT_INDEX ILongestLevels; SEXP longestLevels=R_NilValue; // just for ordered factor - PROTECT_WITH_INDEX(longestLevels, &ILongestLevels); nprotect++; + PROTECT_WITH_INDEX(longestLevels, &ILongestLevels); bool int64=false, date=false, posixct=false, itime=false, asis=false; const char *foundName=NULL; bool anyNotStringOrFactor=false; @@ -565,7 +565,8 @@ SEXP rbindlist(SEXP l, SEXP usenamesArg, SEXP fillArg, SEXP idcolArg, SEXP ignor ansloc += thisnrow; } } + UNPROTECT(1); // longestLevels } - UNPROTECT(nprotect); // ans, ansNames, longestLevels? coercedForFactor? + UNPROTECT(nprotect); // ans, ansNames, coercedForFactor return(ans); } From 40495615508da01208e7d3386fc479dc37289d98 Mon Sep 17 00:00:00 2001 From: Ivan K Date: Thu, 18 Jun 2026 14:25:55 +0300 Subject: [PATCH 4/6] NEWS entry --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 9de21ce6f..daa815151 100644 --- a/NEWS.md +++ b/NEWS.md @@ -58,6 +58,8 @@ 12. `print.data.table()` now truncates long character columns and list-column summaries by default to avoid horizontal console overflow, [#7718](https://github.com/Rdatatable/data.table/issues/7718). When `datatable.prettyprint.char` is `NULL` (the default), the truncation limit is now dynamically calculated based on the available console width. Use `options(datatable.prettyprint.char=Inf)` for the old default behavior (never truncate). Thanks @tdhock for the report and @venom1204 for the fix. +13. `rbindlist()` (and therefore the `rbind()` method for `data.table`s) no longer raises an error upon encountering more than approximately 50000 columns in a list entry, [#7793](https://github.com/Rdatatable/data.table/issues/7793). The bug was introduced in `data.table` version 1.18.2.1. Thanks to @rickhelmus for the report and @aitap for the fix. + ### Notes 1. {data.table} now depends on R 3.5.0 (2018). From f2b8c58ee9ea18ec73248d6dbb911ecd3f40bfed Mon Sep 17 00:00:00 2001 From: Ivan K Date: Thu, 18 Jun 2026 15:10:29 +0300 Subject: [PATCH 5/6] Keep listNames protected --- src/rbindlist.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rbindlist.c b/src/rbindlist.c index 9fed04774..d7ac8d816 100644 --- a/src/rbindlist.c +++ b/src/rbindlist.c @@ -250,7 +250,7 @@ SEXP rbindlist(SEXP l, SEXP usenamesArg, SEXP fillArg, SEXP idcolArg, SEXP ignor setAttrib(ans, R_NamesSymbol, ansNames); if (idcol) { SET_STRING_ELT(ansNames, 0, STRING_ELT(idcolArg, 0)); - SEXP idval, listNames=getAttrib(l, R_NamesSymbol); + SEXP idval, listNames=PROTECT(getAttrib(l, R_NamesSymbol)); if (length(listNames)) { SET_VECTOR_ELT(ans, 0, idval=allocVector(STRSXP, nrow)); for (int i=0,ansloc=0; i Date: Thu, 18 Jun 2026 19:36:13 +0300 Subject: [PATCH 6/6] Clarify test comment Co-Authored-By: Michael Chirico --- inst/tests/tests.Rraw | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index d69de32af..8c1a0deb0 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -21670,7 +21670,8 @@ test(2375.4, print(data.table(x="abcdefghijklmnopqrstuvwxyz")), output="abcdefgh test(2375.5, print(data.table(id=1L, score=99.1, txt="abcdefghijklmnopqrstuvwxyz")), output="abcdefghijklmn...", options=list(width=20, datatable.prettyprint.char=NULL)) test(2375.6, print(data.table(x=rep("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e6)), topn=1), output="1000000: ABCDEFGHIJKLM...", options=list(width=25, datatable.prettyprint.char=NULL)) -# rbindlist() used to put O(ncol(...)) > R_PPStackSize = 50000 items on the protect stack, #7793 +# rbindlist() used to put O(ncol(...)) > R_PPStackSize items on the protect stack, #7793 +# Assuming 50000 as the default protection stack size, although R --max-ppsize=... can increase it to 500000. x = as.data.table(as.list(1:50001)) test(2376, rbindlist(list(x)), x) rm(x)