In perl.git, the branch blead has been updated <https://perl5.git.perl.org/perl.git/commitdiff/f966a6e60c5062904734d261eea96ba070f47fdb?hp=a4eb0505c203b947fe64e98ace1af076f4c12153>
- Log ----------------------------------------------------------------- commit f966a6e60c5062904734d261eea96ba070f47fdb Author: Karl Williamson <[email protected]> Date: Sat Feb 16 11:44:56 2019 -0700 malloc.c: Limit malloc size to PTRDIFF_MAX Without doing this, it is possible that the behavior is undefined when subtracting two pointers that point to the same object. See thread beginning at http://nntp.perl.org/group/perl.perl5.porters/251541 In particular this from Tomasz Konojacki C11 says: > When two pointers are subtracted, both shall point to elements of the > same array object, or one past the last element of the array object; > the result is the difference of the subscripts of the two array > elements. The size of the result is implementation-defined, and its > type (a signed integer type) is ptrdiff_t defined in the <stddef.h> > header. If the result is not representable in an object of that type, > the behavior is undefined. There are many ways to interpret this passage, but according to (most?) C compilers developers, it means that no object can be larger than PTRDIFF_MAX. For example, gcc's optimizer assummes that strlen() will never return anything larger than PTRDIFF_MAX [1]. There's also a blogpost[2] on this topic, which IMO is a very interesting read. If gcc and clang can assume that all objects won't be larger than PTRDIFF_MAX, so can we. Also, in practice, ssize_t and ptrdiff_t on most (all?) platforms are defined as exactly the same type. BTW, the fact that compilers assume that objects can't be larger than PTRDIFF_MAX has very dangerous implications on 32-bit platforms. Is it possible to create string longer than PTRDIFF_MAX on 32-bit perls?. It shouldn't be allowed. [1] - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78153 [2] - https://trust-in-soft.com/objects-larger-than-ptrdiff_max-bytes/ ----------------------------------------------------------------------- Summary of changes: malloc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/malloc.c b/malloc.c index 53835e1f47..72cf2cd307 100644 --- a/malloc.c +++ b/malloc.c @@ -1230,6 +1230,18 @@ Perl_malloc(size_t nbytes) union overhead *p; int bucket; + /* A structure that has more than PTRDIFF_MAX bytes is unfortunately + * legal in C, but in such, if two elements are far enough apart, we + * can't legally find out how far apart they are. Limit the size of a + * malloc so that pointer subtraction in the same structure is always + * well defined */ + if (nbytes > PTRDIFF_MAX) { + MYMALLOC_WRITE2STDERR("Memory requests are limited to PTRDIFF_MAX" + " bytes to prevent possible undefined" + " behavior"); + return NULL; + } + #if defined(DEBUGGING) || defined(RCHECK) MEM_SIZE size = nbytes; #endif -- Perl5 Master Repository
