SkMalloc.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * Copyright 2017 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #ifndef SkMalloc_DEFINED
  8. #define SkMalloc_DEFINED
  9. #include <cstddef>
  10. #include <cstring>
  11. #include "include/core/SkTypes.h"
  12. /*
  13. memory wrappers to be implemented by the porting layer (platform)
  14. */
  15. /** Free memory returned by sk_malloc(). It is safe to pass null. */
  16. SK_API extern void sk_free(void*);
  17. /**
  18. * Called internally if we run out of memory. The platform implementation must
  19. * not return, but should either throw an exception or otherwise exit.
  20. */
  21. SK_API extern void sk_out_of_memory(void);
  22. enum {
  23. /**
  24. * If this bit is set, the returned buffer must be zero-initialized. If this bit is not set
  25. * the buffer can be uninitialized.
  26. */
  27. SK_MALLOC_ZERO_INITIALIZE = 1 << 0,
  28. /**
  29. * If this bit is set, the implementation must throw/crash/quit if the request cannot
  30. * be fulfilled. If this bit is not set, then it should return nullptr on failure.
  31. */
  32. SK_MALLOC_THROW = 1 << 1,
  33. };
  34. /**
  35. * Return a block of memory (at least 4-byte aligned) of at least the specified size.
  36. * If the requested memory cannot be returned, either return nullptr or throw/exit, depending
  37. * on the SK_MALLOC_THROW bit. If the allocation succeeds, the memory will be zero-initialized
  38. * if the SK_MALLOC_ZERO_INITIALIZE bit was set.
  39. *
  40. * To free the memory, call sk_free()
  41. */
  42. SK_API extern void* sk_malloc_flags(size_t size, unsigned flags);
  43. /** Same as standard realloc(), but this one never returns null on failure. It will throw
  44. * an exception if it fails.
  45. */
  46. SK_API extern void* sk_realloc_throw(void* buffer, size_t size);
  47. static inline void* sk_malloc_throw(size_t size) {
  48. return sk_malloc_flags(size, SK_MALLOC_THROW);
  49. }
  50. static inline void* sk_calloc_throw(size_t size) {
  51. return sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_ZERO_INITIALIZE);
  52. }
  53. static inline void* sk_calloc_canfail(size_t size) {
  54. #if defined(IS_FUZZING_WITH_LIBFUZZER)
  55. // The Libfuzzer environment is very susceptible to OOM, so to avoid those
  56. // just pretend we can't allocate more than 200kb.
  57. if (size > 200000) {
  58. return nullptr;
  59. }
  60. #endif
  61. return sk_malloc_flags(size, SK_MALLOC_ZERO_INITIALIZE);
  62. }
  63. // Performs a safe multiply count * elemSize, checking for overflow
  64. SK_API extern void* sk_calloc_throw(size_t count, size_t elemSize);
  65. SK_API extern void* sk_malloc_throw(size_t count, size_t elemSize);
  66. SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize);
  67. /**
  68. * These variants return nullptr on failure
  69. */
  70. static inline void* sk_malloc_canfail(size_t size) {
  71. #if defined(IS_FUZZING_WITH_LIBFUZZER)
  72. // The Libfuzzer environment is very susceptible to OOM, so to avoid those
  73. // just pretend we can't allocate more than 200kb.
  74. if (size > 200000) {
  75. return nullptr;
  76. }
  77. #endif
  78. return sk_malloc_flags(size, 0);
  79. }
  80. SK_API extern void* sk_malloc_canfail(size_t count, size_t elemSize);
  81. // bzero is safer than memset, but we can't rely on it, so... sk_bzero()
  82. static inline void sk_bzero(void* buffer, size_t size) {
  83. // Please c.f. sk_careful_memcpy. It's undefined behavior to call memset(null, 0, 0).
  84. if (size) {
  85. memset(buffer, 0, size);
  86. }
  87. }
  88. /**
  89. * sk_careful_memcpy() is just like memcpy(), but guards against undefined behavior.
  90. *
  91. * It is undefined behavior to call memcpy() with null dst or src, even if len is 0.
  92. * If an optimizer is "smart" enough, it can exploit this to do unexpected things.
  93. * memcpy(dst, src, 0);
  94. * if (src) {
  95. * printf("%x\n", *src);
  96. * }
  97. * In this code the compiler can assume src is not null and omit the if (src) {...} check,
  98. * unconditionally running the printf, crashing the program if src really is null.
  99. * Of the compilers we pay attention to only GCC performs this optimization in practice.
  100. */
  101. static inline void* sk_careful_memcpy(void* dst, const void* src, size_t len) {
  102. // When we pass >0 len we had better already be passing valid pointers.
  103. // So we just need to skip calling memcpy when len == 0.
  104. if (len) {
  105. memcpy(dst,src,len);
  106. }
  107. return dst;
  108. }
  109. static inline void* sk_careful_memmove(void* dst, const void* src, size_t len) {
  110. // When we pass >0 len we had better already be passing valid pointers.
  111. // So we just need to skip calling memcpy when len == 0.
  112. if (len) {
  113. memmove(dst,src,len);
  114. }
  115. return dst;
  116. }
  117. #endif // SkMalloc_DEFINED