Repository navigation
growVector, copyAsPlain may formally cause undefined behaviour with 0-length vectors #6819
Description
Activity
Funnily enough I managed to come across this same bug in a "different" setting, but I still can't reproduce it (even under
--enable-strict-barrier) locally.Could you share more details of the container you were using?
Does {vctrs} also segfault there? (I think it does: r-lib/vctrs#1968)
vctrsmust be encountering some other problem. Could it be due to ABI changes? Some package needing to be reinstalled?Here we had
r-devel-clang-sancomplaining that callingmemcpy(0x1, 0x1, 0)is formally undefined behaviour even though no modernmemcpy()dereferences the pointers whenn == 0. (Moreover, starting with C23,memcpy()withn == 0will be required to be a no-op, no matter whether the pointers are valid or notmemcpy(0,0,0)will be a no-op, which is not relevant here.) It wouldn't crash without the sanitizer.If this was a zero-length access, the crash would be due to access to
0x1or some other low-value pointer, not0x7f405afb3a6a(which looks likemmaparea, so probably a large heap allocation).Still, the fix shouldn't hurt and may prevent an UBSan warning during CRAN checks.
The only thing we did is update R 4.4.1 --> R 4.5.0. It seems that is turning on stricter checks in R:
https://github.com/r-devel/r-svn/blob/d62355fdacfd9a9a41639134ee9875e0c2502ca7/src/include/Rinlinedfuns.h#L84
https://github.com/r-devel/r-svn/blob/d62355fdacfd9a9a41639134ee9875e0c2502ca7/src/main/memory.c#L31
https://github.com/r-devel/r-svn/blob/d62355fdacfd9a9a41639134ee9875e0c2502ca7/src/main/memory.c#L4146Possibly the non-
0x1address is from(void*)1, though I admittedly still don't fully understand the issue, possibly we just have stricter implementations on by default.I couldn't get it to crash. I also tried installing all the
vctrsdependencies on R 4.4.1, then running R 4.5.0--with-strict-barrierwithout rebuilding them. (The latter only got me two test failures of the formHASHTAB: argument of type SYMSXP is not an environment or NULL.) Any other information that could help reproduce the crash? My compiler is probably too old. Agdbbacktrace could also be informative.While the C standard allows making a pointer out of a number to perform very wild transformations, on our today's computers with MMUs and flat address spaces,
(void*)1stores a 1 in the register (or memory).Are you compiling with
-fsanitize-trap? This is what-fsanitize-traplooks like: r-hub/containers#84CRAN special tests may be disabling the
memcpytest,or running their tests in C23 mode, whereor using an older version of the compiler which doesn't have this check enabled.memcpy(..., ..., 0)should no longer count as load/store (but I haven't verified either option)
Found while working on a custom Debian testing-based container (
using C compiler: ‘Debian clang version 19.1.7 (1+b1)’) with Clang sanitizers enabled for #6746:When trying to access the contents of a zero-length vector using
INTEGER(...)orREAL(...)or other accessor, R may return an invalid pointer (0x1). The C standard says that giving an invalid pointer tomemcpy()is undefined behaviour, even though in practice nothing breaks (memcpyseesn=0and doesn't dereference it).If nothing breaks, what's the risk? One of the CRAN special checks (
clang-UBSANor0len) might pick this up too. Very far-fetched, a compiler might optimize away a chunk of code deemed to cause undefined behaviour.(Yes, that
case CPLSXP:looks a bit strange.clangmust have merged the branches into one with different length arguments tomemcpy().)