recallocarray.c 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
  2. /*
  3. * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */
  18. #include "includes.h"
  19. #ifndef HAVE_RECALLOCARRAY
  20. #include <errno.h>
  21. #include <stdlib.h>
  22. #ifdef HAVE_STDINT_H
  23. #include <stdint.h>
  24. #endif
  25. #include <string.h>
  26. #include <unistd.h>
  27. /*
  28. * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
  29. * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
  30. */
  31. #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
  32. void *
  33. recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
  34. {
  35. size_t oldsize, newsize;
  36. void *newptr;
  37. if (ptr == NULL)
  38. return calloc(newnmemb, size);
  39. if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
  40. newnmemb > 0 && SIZE_MAX / newnmemb < size) {
  41. errno = ENOMEM;
  42. return NULL;
  43. }
  44. newsize = newnmemb * size;
  45. if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
  46. oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
  47. errno = EINVAL;
  48. return NULL;
  49. }
  50. oldsize = oldnmemb * size;
  51. /*
  52. * Don't bother too much if we're shrinking just a bit,
  53. * we do not shrink for series of small steps, oh well.
  54. */
  55. if (newsize <= oldsize) {
  56. size_t d = oldsize - newsize;
  57. if (d < oldsize / 2 && d < (size_t)getpagesize()) {
  58. memset((char *)ptr + newsize, 0, d);
  59. return ptr;
  60. }
  61. }
  62. newptr = malloc(newsize);
  63. if (newptr == NULL)
  64. return NULL;
  65. if (newsize > oldsize) {
  66. memcpy(newptr, ptr, oldsize);
  67. memset((char *)newptr + oldsize, 0, newsize - oldsize);
  68. } else
  69. memcpy(newptr, ptr, newsize);
  70. explicit_bzero(ptr, oldsize);
  71. free(ptr);
  72. return newptr;
  73. }
  74. /* DEF_WEAK(recallocarray); */
  75. #endif /* HAVE_RECALLOCARRAY */