xref: /dragonfly/contrib/diffutils/lib/xsize.h (revision 6ea1f93e)
14536c563SJohn Marino /* xsize.h -- Checked size_t computations.
24536c563SJohn Marino 
3*6ea1f93eSDaniel Fojt    Copyright (C) 2003, 2008-2018 Free Software Foundation, Inc.
44536c563SJohn Marino 
54536c563SJohn Marino    This program is free software; you can redistribute it and/or modify
64536c563SJohn Marino    it under the terms of the GNU General Public License as published by
74536c563SJohn Marino    the Free Software Foundation; either version 3, or (at your option)
84536c563SJohn Marino    any later version.
94536c563SJohn Marino 
104536c563SJohn Marino    This program is distributed in the hope that it will be useful,
114536c563SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
124536c563SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
134536c563SJohn Marino    GNU General Public License for more details.
144536c563SJohn Marino 
154536c563SJohn Marino    You should have received a copy of the GNU General Public License
16*6ea1f93eSDaniel Fojt    along with this program; if not, see <https://www.gnu.org/licenses/>.  */
174536c563SJohn Marino 
184536c563SJohn Marino #ifndef _XSIZE_H
194536c563SJohn Marino #define _XSIZE_H
204536c563SJohn Marino 
214536c563SJohn Marino /* Get size_t.  */
224536c563SJohn Marino #include <stddef.h>
234536c563SJohn Marino 
244536c563SJohn Marino /* Get SIZE_MAX.  */
254536c563SJohn Marino #include <limits.h>
264536c563SJohn Marino #if HAVE_STDINT_H
274536c563SJohn Marino # include <stdint.h>
284536c563SJohn Marino #endif
294536c563SJohn Marino 
30*6ea1f93eSDaniel Fojt #ifndef _GL_INLINE_HEADER_BEGIN
31*6ea1f93eSDaniel Fojt  #error "Please include config.h first."
32*6ea1f93eSDaniel Fojt #endif
334536c563SJohn Marino _GL_INLINE_HEADER_BEGIN
344536c563SJohn Marino #ifndef XSIZE_INLINE
354536c563SJohn Marino # define XSIZE_INLINE _GL_INLINE
364536c563SJohn Marino #endif
374536c563SJohn Marino 
384536c563SJohn Marino /* The size of memory objects is often computed through expressions of
394536c563SJohn Marino    type size_t. Example:
404536c563SJohn Marino       void* p = malloc (header_size + n * element_size).
414536c563SJohn Marino    These computations can lead to overflow.  When this happens, malloc()
424536c563SJohn Marino    returns a piece of memory that is way too small, and the program then
434536c563SJohn Marino    crashes while attempting to fill the memory.
444536c563SJohn Marino    To avoid this, the functions and macros in this file check for overflow.
454536c563SJohn Marino    The convention is that SIZE_MAX represents overflow.
464536c563SJohn Marino    malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
474536c563SJohn Marino    implementation that uses mmap --, it's recommended to use size_overflow_p()
484536c563SJohn Marino    or size_in_bounds_p() before invoking malloc().
494536c563SJohn Marino    The example thus becomes:
504536c563SJohn Marino       size_t size = xsum (header_size, xtimes (n, element_size));
514536c563SJohn Marino       void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
524536c563SJohn Marino */
534536c563SJohn Marino 
544536c563SJohn Marino /* Convert an arbitrary value >= 0 to type size_t.  */
554536c563SJohn Marino #define xcast_size_t(N) \
564536c563SJohn Marino   ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
574536c563SJohn Marino 
584536c563SJohn Marino /* Sum of two sizes, with overflow check.  */
594536c563SJohn Marino XSIZE_INLINE size_t
604536c563SJohn Marino #if __GNUC__ >= 3
614536c563SJohn Marino __attribute__ ((__pure__))
624536c563SJohn Marino #endif
xsum(size_t size1,size_t size2)634536c563SJohn Marino xsum (size_t size1, size_t size2)
644536c563SJohn Marino {
654536c563SJohn Marino   size_t sum = size1 + size2;
664536c563SJohn Marino   return (sum >= size1 ? sum : SIZE_MAX);
674536c563SJohn Marino }
684536c563SJohn Marino 
694536c563SJohn Marino /* Sum of three sizes, with overflow check.  */
704536c563SJohn Marino XSIZE_INLINE size_t
714536c563SJohn Marino #if __GNUC__ >= 3
724536c563SJohn Marino __attribute__ ((__pure__))
734536c563SJohn Marino #endif
xsum3(size_t size1,size_t size2,size_t size3)744536c563SJohn Marino xsum3 (size_t size1, size_t size2, size_t size3)
754536c563SJohn Marino {
764536c563SJohn Marino   return xsum (xsum (size1, size2), size3);
774536c563SJohn Marino }
784536c563SJohn Marino 
794536c563SJohn Marino /* Sum of four sizes, with overflow check.  */
804536c563SJohn Marino XSIZE_INLINE size_t
814536c563SJohn Marino #if __GNUC__ >= 3
824536c563SJohn Marino __attribute__ ((__pure__))
834536c563SJohn Marino #endif
xsum4(size_t size1,size_t size2,size_t size3,size_t size4)844536c563SJohn Marino xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
854536c563SJohn Marino {
864536c563SJohn Marino   return xsum (xsum (xsum (size1, size2), size3), size4);
874536c563SJohn Marino }
884536c563SJohn Marino 
894536c563SJohn Marino /* Maximum of two sizes, with overflow check.  */
904536c563SJohn Marino XSIZE_INLINE size_t
914536c563SJohn Marino #if __GNUC__ >= 3
924536c563SJohn Marino __attribute__ ((__pure__))
934536c563SJohn Marino #endif
xmax(size_t size1,size_t size2)944536c563SJohn Marino xmax (size_t size1, size_t size2)
954536c563SJohn Marino {
964536c563SJohn Marino   /* No explicit check is needed here, because for any n:
974536c563SJohn Marino      max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX.  */
984536c563SJohn Marino   return (size1 >= size2 ? size1 : size2);
994536c563SJohn Marino }
1004536c563SJohn Marino 
1014536c563SJohn Marino /* Multiplication of a count with an element size, with overflow check.
1024536c563SJohn Marino    The count must be >= 0 and the element size must be > 0.
1034536c563SJohn Marino    This is a macro, not a function, so that it works correctly even
1044536c563SJohn Marino    when N is of a wider type and N > SIZE_MAX.  */
1054536c563SJohn Marino #define xtimes(N, ELSIZE) \
1064536c563SJohn Marino   ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
1074536c563SJohn Marino 
1084536c563SJohn Marino /* Check for overflow.  */
1094536c563SJohn Marino #define size_overflow_p(SIZE) \
1104536c563SJohn Marino   ((SIZE) == SIZE_MAX)
1114536c563SJohn Marino /* Check against overflow.  */
1124536c563SJohn Marino #define size_in_bounds_p(SIZE) \
1134536c563SJohn Marino   ((SIZE) != SIZE_MAX)
1144536c563SJohn Marino 
1154536c563SJohn Marino _GL_INLINE_HEADER_END
1164536c563SJohn Marino 
1174536c563SJohn Marino #endif /* _XSIZE_H */
118