• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2018-2021, Microsoft Research, Daan Leijen
3 This is free software; you can redistribute it and/or modify it under the
4 terms of the MIT license. A copy of the license can be found in the file
5 "LICENSE" at the root of this distribution.
6 -----------------------------------------------------------------------------*/
7 
8 // ------------------------------------------------------------------------
9 // mi prefixed publi definitions of various Posix, Unix, and C++ functions
10 // for convenience and used when overriding these functions.
11 // ------------------------------------------------------------------------
12 #include "mimalloc.h"
13 #include "mimalloc/internal.h"
14 
15 // ------------------------------------------------------
16 // Posix & Unix functions definitions
17 // ------------------------------------------------------
18 
19 #include <errno.h>
20 #include <string.h>  // memset
21 #include <stdlib.h>  // getenv
22 
23 #ifdef _MSC_VER
24 #pragma warning(disable:4996)  // getenv _wgetenv
25 #endif
26 
27 #ifndef EINVAL
28 #define EINVAL 22
29 #endif
30 #ifndef ENOMEM
31 #define ENOMEM 12
32 #endif
33 
34 
mi_malloc_size(const void * p)35 mi_decl_nodiscard size_t mi_malloc_size(const void* p) mi_attr_noexcept {
36   // if (!mi_is_in_heap_region(p)) return 0;
37   return mi_usable_size(p);
38 }
39 
mi_malloc_usable_size(const void * p)40 mi_decl_nodiscard size_t mi_malloc_usable_size(const void *p) mi_attr_noexcept {
41   // if (!mi_is_in_heap_region(p)) return 0;
42   return mi_usable_size(p);
43 }
44 
mi_malloc_good_size(size_t size)45 mi_decl_nodiscard size_t mi_malloc_good_size(size_t size) mi_attr_noexcept {
46   return mi_good_size(size);
47 }
48 
mi_cfree(void * p)49 void mi_cfree(void* p) mi_attr_noexcept {
50   if (mi_is_in_heap_region(p)) {
51     mi_free(p);
52   }
53 }
54 
mi_posix_memalign(void ** p,size_t alignment,size_t size)55 int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept {
56   // Note: The spec dictates we should not modify `*p` on an error. (issue#27)
57   // <http://man7.org/linux/man-pages/man3/posix_memalign.3.html>
58   if (p == NULL) return EINVAL;
59   if ((alignment % sizeof(void*)) != 0) return EINVAL;                 // natural alignment
60   // it is also required that alignment is a power of 2 and > 0; this is checked in `mi_malloc_aligned`
61   if (alignment==0 || !_mi_is_power_of_two(alignment)) return EINVAL;  // not a power of 2
62   void* q = mi_malloc_aligned(size, alignment);
63   if (q==NULL && size != 0) return ENOMEM;
64   mi_assert_internal(((uintptr_t)q % alignment) == 0);
65   *p = q;
66   return 0;
67 }
68 
mi_memalign(size_t alignment,size_t size)69 mi_decl_nodiscard mi_decl_restrict void* mi_memalign(size_t alignment, size_t size) mi_attr_noexcept {
70   void* p = mi_malloc_aligned(size, alignment);
71   mi_assert_internal(((uintptr_t)p % alignment) == 0);
72   return p;
73 }
74 
mi_valloc(size_t size)75 mi_decl_nodiscard mi_decl_restrict void* mi_valloc(size_t size) mi_attr_noexcept {
76   return mi_memalign( _mi_os_page_size(), size );
77 }
78 
mi_pvalloc(size_t size)79 mi_decl_nodiscard mi_decl_restrict void* mi_pvalloc(size_t size) mi_attr_noexcept {
80   size_t psize = _mi_os_page_size();
81   if (size >= SIZE_MAX - psize) return NULL; // overflow
82   size_t asize = _mi_align_up(size, psize);
83   return mi_malloc_aligned(asize, psize);
84 }
85 
mi_aligned_alloc(size_t alignment,size_t size)86 mi_decl_nodiscard mi_decl_restrict void* mi_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept {
87   // C11 requires the size to be an integral multiple of the alignment, see <https://en.cppreference.com/w/c/memory/aligned_alloc>.
88   // unfortunately, it turns out quite some programs pass a size that is not an integral multiple so skip this check..
89   /* if mi_unlikely((size & (alignment - 1)) != 0) { // C11 requires alignment>0 && integral multiple, see <https://en.cppreference.com/w/c/memory/aligned_alloc>
90       #if MI_DEBUG > 0
91       _mi_error_message(EOVERFLOW, "(mi_)aligned_alloc requires the size to be an integral multiple of the alignment (size %zu, alignment %zu)\n", size, alignment);
92       #endif
93       return NULL;
94     }
95   */
96   // C11 also requires alignment to be a power-of-two (and > 0) which is checked in mi_malloc_aligned
97   void* p = mi_malloc_aligned(size, alignment);
98   mi_assert_internal(((uintptr_t)p % alignment) == 0);
99   return p;
100 }
101 
mi_reallocarray(void * p,size_t count,size_t size)102 mi_decl_nodiscard void* mi_reallocarray( void* p, size_t count, size_t size ) mi_attr_noexcept {  // BSD
103   void* newp = mi_reallocn(p,count,size);
104   if (newp==NULL) { errno = ENOMEM; }
105   return newp;
106 }
107 
mi_reallocarr(void * p,size_t count,size_t size)108 mi_decl_nodiscard int mi_reallocarr( void* p, size_t count, size_t size ) mi_attr_noexcept { // NetBSD
109   mi_assert(p != NULL);
110   if (p == NULL) {
111     errno = EINVAL;
112     return EINVAL;
113   }
114   void** op = (void**)p;
115   void* newp = mi_reallocarray(*op, count, size);
116   if mi_unlikely(newp == NULL) { return errno; }
117   *op = newp;
118   return 0;
119 }
120 
mi__expand(void * p,size_t newsize)121 void* mi__expand(void* p, size_t newsize) mi_attr_noexcept {  // Microsoft
122   void* res = mi_expand(p, newsize);
123   if (res == NULL) { errno = ENOMEM; }
124   return res;
125 }
126 
mi_wcsdup(const unsigned short * s)127 mi_decl_nodiscard mi_decl_restrict unsigned short* mi_wcsdup(const unsigned short* s) mi_attr_noexcept {
128   if (s==NULL) return NULL;
129   size_t len;
130   for(len = 0; s[len] != 0; len++) { }
131   size_t size = (len+1)*sizeof(unsigned short);
132   unsigned short* p = (unsigned short*)mi_malloc(size);
133   if (p != NULL) {
134     _mi_memcpy(p,s,size);
135   }
136   return p;
137 }
138 
mi_mbsdup(const unsigned char * s)139 mi_decl_nodiscard mi_decl_restrict unsigned char* mi_mbsdup(const unsigned char* s)  mi_attr_noexcept {
140   return (unsigned char*)mi_strdup((const char*)s);
141 }
142 
mi_dupenv_s(char ** buf,size_t * size,const char * name)143 int mi_dupenv_s(char** buf, size_t* size, const char* name) mi_attr_noexcept {
144   if (buf==NULL || name==NULL) return EINVAL;
145   if (size != NULL) *size = 0;
146   char* p = getenv(name);        // mscver warning 4996
147   if (p==NULL) {
148     *buf = NULL;
149   }
150   else {
151     *buf = mi_strdup(p);
152     if (*buf==NULL) return ENOMEM;
153     if (size != NULL) *size = _mi_strlen(p);
154   }
155   return 0;
156 }
157 
mi_wdupenv_s(unsigned short ** buf,size_t * size,const unsigned short * name)158 int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name) mi_attr_noexcept {
159   if (buf==NULL || name==NULL) return EINVAL;
160   if (size != NULL) *size = 0;
161 #if !defined(_WIN32) || (defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP))
162   // not supported
163   *buf = NULL;
164   return EINVAL;
165 #else
166   unsigned short* p = (unsigned short*)_wgetenv((const wchar_t*)name);  // msvc warning 4996
167   if (p==NULL) {
168     *buf = NULL;
169   }
170   else {
171     *buf = mi_wcsdup(p);
172     if (*buf==NULL) return ENOMEM;
173     if (size != NULL) *size = wcslen((const wchar_t*)p);
174   }
175   return 0;
176 #endif
177 }
178 
mi_aligned_offset_recalloc(void * p,size_t newcount,size_t size,size_t alignment,size_t offset)179 mi_decl_nodiscard void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { // Microsoft
180   return mi_recalloc_aligned_at(p, newcount, size, alignment, offset);
181 }
182 
mi_aligned_recalloc(void * p,size_t newcount,size_t size,size_t alignment)183 mi_decl_nodiscard void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { // Microsoft
184   return mi_recalloc_aligned(p, newcount, size, alignment);
185 }
186