opj_malloc.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * The copyright in this software is being made available under the 2-clauses
  3. * BSD License, included below. This software may be subject to other third
  4. * party and contributor rights, including patent rights, and no such rights
  5. * are granted under this license.
  6. *
  7. * Copyright (c) 2015, Mathieu Malaterre <mathieu.malaterre@gmail.com>
  8. * Copyright (c) 2015, Matthieu Darbois
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
  21. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  24. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  25. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  26. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. * POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #define OPJ_SKIP_POISON
  33. #include "opj_includes.h"
  34. #if defined(OPJ_HAVE_MALLOC_H) && defined(OPJ_HAVE_MEMALIGN)
  35. # include <malloc.h>
  36. #endif
  37. #ifndef SIZE_MAX
  38. # define SIZE_MAX ((size_t) -1)
  39. #endif
  40. static INLINE void *opj_aligned_alloc_n(size_t alignment, size_t size)
  41. {
  42. void* ptr;
  43. /* alignment shall be power of 2 */
  44. assert((alignment != 0U) && ((alignment & (alignment - 1U)) == 0U));
  45. /* alignment shall be at least sizeof(void*) */
  46. assert(alignment >= sizeof(void*));
  47. if (size == 0U) { /* prevent implementation defined behavior of realloc */
  48. return NULL;
  49. }
  50. #if defined(OPJ_HAVE_POSIX_MEMALIGN)
  51. /* aligned_alloc requires c11, restrict to posix_memalign for now. Quote:
  52. * This function was introduced in POSIX 1003.1d. Although this function is
  53. * superseded by aligned_alloc, it is more portable to older POSIX systems
  54. * that do not support ISO C11. */
  55. if (posix_memalign(&ptr, alignment, size)) {
  56. ptr = NULL;
  57. }
  58. /* older linux */
  59. #elif defined(OPJ_HAVE_MEMALIGN)
  60. ptr = memalign(alignment, size);
  61. /* _MSC_VER */
  62. #elif defined(OPJ_HAVE__ALIGNED_MALLOC)
  63. ptr = _aligned_malloc(size, alignment);
  64. #else
  65. /*
  66. * Generic aligned malloc implementation.
  67. * Uses size_t offset for the integer manipulation of the pointer,
  68. * as uintptr_t is not available in C89 to do
  69. * bitwise operations on the pointer itself.
  70. */
  71. alignment--;
  72. {
  73. size_t offset;
  74. OPJ_UINT8 *mem;
  75. /* Room for padding and extra pointer stored in front of allocated area */
  76. size_t overhead = alignment + sizeof(void *);
  77. /* let's be extra careful */
  78. assert(alignment <= (SIZE_MAX - sizeof(void *)));
  79. /* Avoid integer overflow */
  80. if (size > (SIZE_MAX - overhead)) {
  81. return NULL;
  82. }
  83. mem = (OPJ_UINT8*)malloc(size + overhead);
  84. if (mem == NULL) {
  85. return mem;
  86. }
  87. /* offset = ((alignment + 1U) - ((size_t)(mem + sizeof(void*)) & alignment)) & alignment; */
  88. /* Use the fact that alignment + 1U is a power of 2 */
  89. offset = ((alignment ^ ((size_t)(mem + sizeof(void*)) & alignment)) + 1U) &
  90. alignment;
  91. ptr = (void *)(mem + sizeof(void*) + offset);
  92. ((void**) ptr)[-1] = mem;
  93. }
  94. #endif
  95. return ptr;
  96. }
  97. static INLINE void *opj_aligned_realloc_n(void *ptr, size_t alignment,
  98. size_t new_size)
  99. {
  100. void *r_ptr;
  101. /* alignment shall be power of 2 */
  102. assert((alignment != 0U) && ((alignment & (alignment - 1U)) == 0U));
  103. /* alignment shall be at least sizeof(void*) */
  104. assert(alignment >= sizeof(void*));
  105. if (new_size == 0U) { /* prevent implementation defined behavior of realloc */
  106. return NULL;
  107. }
  108. /* no portable aligned realloc */
  109. #if defined(OPJ_HAVE_POSIX_MEMALIGN) || defined(OPJ_HAVE_MEMALIGN)
  110. /* glibc doc states one can mix aligned malloc with realloc */
  111. r_ptr = realloc(ptr, new_size); /* fast path */
  112. /* we simply use `size_t` to cast, since we are only interest in binary AND
  113. * operator */
  114. if (((size_t)r_ptr & (alignment - 1U)) != 0U) {
  115. /* this is non-trivial to implement a portable aligned realloc, so use a
  116. * simple approach where we do not need a function that return the size of an
  117. * allocated array (eg. _msize on Windows, malloc_size on MacOS,
  118. * malloc_usable_size on systems with glibc) */
  119. void *a_ptr = opj_aligned_alloc_n(alignment, new_size);
  120. if (a_ptr != NULL) {
  121. memcpy(a_ptr, r_ptr, new_size);
  122. }
  123. free(r_ptr);
  124. r_ptr = a_ptr;
  125. }
  126. /* _MSC_VER */
  127. #elif defined(OPJ_HAVE__ALIGNED_MALLOC)
  128. r_ptr = _aligned_realloc(ptr, new_size, alignment);
  129. #else
  130. if (ptr == NULL) {
  131. return opj_aligned_alloc_n(alignment, new_size);
  132. }
  133. alignment--;
  134. {
  135. void *oldmem;
  136. OPJ_UINT8 *newmem;
  137. size_t overhead = alignment + sizeof(void *);
  138. /* let's be extra careful */
  139. assert(alignment <= (SIZE_MAX - sizeof(void *)));
  140. /* Avoid integer overflow */
  141. if (new_size > SIZE_MAX - overhead) {
  142. return NULL;
  143. }
  144. oldmem = ((void**) ptr)[-1];
  145. newmem = (OPJ_UINT8*)realloc(oldmem, new_size + overhead);
  146. if (newmem == NULL) {
  147. return newmem;
  148. }
  149. if (newmem == oldmem) {
  150. r_ptr = ptr;
  151. } else {
  152. size_t old_offset;
  153. size_t new_offset;
  154. /* realloc created a new copy, realign the copied memory block */
  155. old_offset = (size_t)((OPJ_UINT8*)ptr - (OPJ_UINT8*)oldmem);
  156. /* offset = ((alignment + 1U) - ((size_t)(mem + sizeof(void*)) & alignment)) & alignment; */
  157. /* Use the fact that alignment + 1U is a power of 2 */
  158. new_offset = ((alignment ^ ((size_t)(newmem + sizeof(void*)) & alignment)) +
  159. 1U) & alignment;
  160. new_offset += sizeof(void*);
  161. r_ptr = (void *)(newmem + new_offset);
  162. if (new_offset != old_offset) {
  163. memmove(newmem + new_offset, newmem + old_offset, new_size);
  164. }
  165. ((void**) r_ptr)[-1] = newmem;
  166. }
  167. }
  168. #endif
  169. return r_ptr;
  170. }
  171. void * opj_malloc(size_t size)
  172. {
  173. if (size == 0U) { /* prevent implementation defined behavior of realloc */
  174. return NULL;
  175. }
  176. return malloc(size);
  177. }
  178. void * opj_calloc(size_t num, size_t size)
  179. {
  180. if (num == 0 || size == 0) {
  181. /* prevent implementation defined behavior of realloc */
  182. return NULL;
  183. }
  184. return calloc(num, size);
  185. }
  186. void *opj_aligned_malloc(size_t size)
  187. {
  188. return opj_aligned_alloc_n(16U, size);
  189. }
  190. void * opj_aligned_realloc(void *ptr, size_t size)
  191. {
  192. return opj_aligned_realloc_n(ptr, 16U, size);
  193. }
  194. void *opj_aligned_32_malloc(size_t size)
  195. {
  196. return opj_aligned_alloc_n(32U, size);
  197. }
  198. void * opj_aligned_32_realloc(void *ptr, size_t size)
  199. {
  200. return opj_aligned_realloc_n(ptr, 32U, size);
  201. }
  202. void opj_aligned_free(void* ptr)
  203. {
  204. #if defined(OPJ_HAVE_POSIX_MEMALIGN) || defined(OPJ_HAVE_MEMALIGN)
  205. free(ptr);
  206. #elif defined(OPJ_HAVE__ALIGNED_MALLOC)
  207. _aligned_free(ptr);
  208. #else
  209. /* Generic implementation has malloced pointer stored in front of used area */
  210. if (ptr != NULL) {
  211. free(((void**) ptr)[-1]);
  212. }
  213. #endif
  214. }
  215. void * opj_realloc(void *ptr, size_t new_size)
  216. {
  217. if (new_size == 0U) { /* prevent implementation defined behavior of realloc */
  218. return NULL;
  219. }
  220. return realloc(ptr, new_size);
  221. }
  222. void opj_free(void *ptr)
  223. {
  224. free(ptr);
  225. }