Blame gettext-runtime/libasprintf/xsize.h

Packit 5b56b6
/* xsize.h -- Checked size_t computations.
Packit 5b56b6
Packit 5b56b6
   Copyright (C) 2003, 2008-2015 Free Software Foundation, Inc.
Packit 5b56b6
Packit 5b56b6
   This program is free software; you can redistribute it and/or modify
Packit 5b56b6
   it under the terms of the GNU Lesser General Public License as published by
Packit 5b56b6
   the Free Software Foundation; either version 2.1, or (at your option)
Packit 5b56b6
   any later version.
Packit 5b56b6
Packit 5b56b6
   This program is distributed in the hope that it will be useful,
Packit 5b56b6
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5b56b6
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 5b56b6
   GNU Lesser General Public License for more details.
Packit 5b56b6
Packit 5b56b6
   You should have received a copy of the GNU Lesser General Public License
Packit 5b56b6
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 5b56b6
Packit 5b56b6
#ifndef _XSIZE_H
Packit 5b56b6
#define _XSIZE_H
Packit 5b56b6
Packit 5b56b6
/* Get size_t.  */
Packit 5b56b6
#include <stddef.h>
Packit 5b56b6
Packit 5b56b6
/* Get SIZE_MAX.  */
Packit 5b56b6
#include <limits.h>
Packit 5b56b6
#if HAVE_STDINT_H
Packit 5b56b6
# include <stdint.h>
Packit 5b56b6
#endif
Packit 5b56b6
Packit 5b56b6
#ifndef _GL_INLINE_HEADER_BEGIN
Packit 5b56b6
 #error "Please include config.h first."
Packit 5b56b6
#endif
Packit 5b56b6
_GL_INLINE_HEADER_BEGIN
Packit 5b56b6
#ifndef XSIZE_INLINE
Packit 5b56b6
# define XSIZE_INLINE _GL_INLINE
Packit 5b56b6
#endif
Packit 5b56b6
Packit 5b56b6
/* The size of memory objects is often computed through expressions of
Packit 5b56b6
   type size_t. Example:
Packit 5b56b6
      void* p = malloc (header_size + n * element_size).
Packit 5b56b6
   These computations can lead to overflow.  When this happens, malloc()
Packit 5b56b6
   returns a piece of memory that is way too small, and the program then
Packit 5b56b6
   crashes while attempting to fill the memory.
Packit 5b56b6
   To avoid this, the functions and macros in this file check for overflow.
Packit 5b56b6
   The convention is that SIZE_MAX represents overflow.
Packit 5b56b6
   malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
Packit 5b56b6
   implementation that uses mmap --, it's recommended to use size_overflow_p()
Packit 5b56b6
   or size_in_bounds_p() before invoking malloc().
Packit 5b56b6
   The example thus becomes:
Packit 5b56b6
      size_t size = xsum (header_size, xtimes (n, element_size));
Packit 5b56b6
      void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
Packit 5b56b6
*/
Packit 5b56b6
Packit 5b56b6
/* Convert an arbitrary value >= 0 to type size_t.  */
Packit 5b56b6
#define xcast_size_t(N) \
Packit 5b56b6
  ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
Packit 5b56b6
Packit 5b56b6
/* Sum of two sizes, with overflow check.  */
Packit 5b56b6
XSIZE_INLINE size_t
Packit 5b56b6
#if __GNUC__ >= 3
Packit 5b56b6
__attribute__ ((__pure__))
Packit 5b56b6
#endif
Packit 5b56b6
xsum (size_t size1, size_t size2)
Packit 5b56b6
{
Packit 5b56b6
  size_t sum = size1 + size2;
Packit 5b56b6
  return (sum >= size1 ? sum : SIZE_MAX);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Sum of three sizes, with overflow check.  */
Packit 5b56b6
XSIZE_INLINE size_t
Packit 5b56b6
#if __GNUC__ >= 3
Packit 5b56b6
__attribute__ ((__pure__))
Packit 5b56b6
#endif
Packit 5b56b6
xsum3 (size_t size1, size_t size2, size_t size3)
Packit 5b56b6
{
Packit 5b56b6
  return xsum (xsum (size1, size2), size3);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Sum of four sizes, with overflow check.  */
Packit 5b56b6
XSIZE_INLINE size_t
Packit 5b56b6
#if __GNUC__ >= 3
Packit 5b56b6
__attribute__ ((__pure__))
Packit 5b56b6
#endif
Packit 5b56b6
xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
Packit 5b56b6
{
Packit 5b56b6
  return xsum (xsum (xsum (size1, size2), size3), size4);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Maximum of two sizes, with overflow check.  */
Packit 5b56b6
XSIZE_INLINE size_t
Packit 5b56b6
#if __GNUC__ >= 3
Packit 5b56b6
__attribute__ ((__pure__))
Packit 5b56b6
#endif
Packit 5b56b6
xmax (size_t size1, size_t size2)
Packit 5b56b6
{
Packit 5b56b6
  /* No explicit check is needed here, because for any n:
Packit 5b56b6
     max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX.  */
Packit 5b56b6
  return (size1 >= size2 ? size1 : size2);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Multiplication of a count with an element size, with overflow check.
Packit 5b56b6
   The count must be >= 0 and the element size must be > 0.
Packit 5b56b6
   This is a macro, not a function, so that it works correctly even
Packit 5b56b6
   when N is of a wider type and N > SIZE_MAX.  */
Packit 5b56b6
#define xtimes(N, ELSIZE) \
Packit 5b56b6
  ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
Packit 5b56b6
Packit 5b56b6
/* Check for overflow.  */
Packit 5b56b6
#define size_overflow_p(SIZE) \
Packit 5b56b6
  ((SIZE) == SIZE_MAX)
Packit 5b56b6
/* Check against overflow.  */
Packit 5b56b6
#define size_in_bounds_p(SIZE) \
Packit 5b56b6
  ((SIZE) != SIZE_MAX)
Packit 5b56b6
Packit 5b56b6
_GL_INLINE_HEADER_END
Packit 5b56b6
Packit 5b56b6
#endif /* _XSIZE_H */