1/* ----------------------------------------------------------------------------
2Copyright (c) 2018,2019, Microsoft Research, Daan Leijen
3This is free software; you can redistribute it and/or modify it under the
4terms 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
13#include "mimalloc.h"
14#include "mimalloc-internal.h"
15
16// ------------------------------------------------------
17// Posix & Unix functions definitions
18// ------------------------------------------------------
19
20#include <errno.h>
21#include <string.h> // memcpy
22#include <stdlib.h> // getenv
23
24#ifndef EINVAL
25#define EINVAL 22
26#endif
27#ifndef ENOMEM
28#define ENOMEM 12
29#endif
30
31
32size_t mi_malloc_size(const void* p) mi_attr_noexcept {
33 return mi_usable_size(p);
34}
35
36size_t mi_malloc_usable_size(const void *p) mi_attr_noexcept {
37 return mi_usable_size(p);
38}
39
40void mi_cfree(void* p) mi_attr_noexcept {
41 if (mi_is_in_heap_region(p)) {
42 mi_free(p);
43 }
44}
45
46int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept {
47 // Note: The spec dictates we should not modify `*p` on an error. (issue#27)
48 // <http://man7.org/linux/man-pages/man3/posix_memalign.3.html>
49 if (p == NULL) return EINVAL;
50 if (alignment % sizeof(void*) != 0) return EINVAL; // natural alignment
51 if (!_mi_is_power_of_two(alignment)) return EINVAL; // not a power of 2
52 void* q = mi_malloc_aligned(size, alignment);
53 if (q==NULL && size != 0) return ENOMEM;
54 *p = q;
55 return 0;
56}
57
58void* mi_memalign(size_t alignment, size_t size) mi_attr_noexcept {
59 return mi_malloc_aligned(size, alignment);
60}
61
62void* mi_valloc(size_t size) mi_attr_noexcept {
63 return mi_malloc_aligned(size, _mi_os_page_size());
64}
65
66void* mi_pvalloc(size_t size) mi_attr_noexcept {
67 size_t psize = _mi_os_page_size();
68 if (size >= SIZE_MAX - psize) return NULL; // overflow
69 size_t asize = ((size + psize - 1) / psize) * psize;
70 return mi_malloc_aligned(asize, psize);
71}
72
73void* mi_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept {
74 if (alignment==0 || !_mi_is_power_of_two(alignment)) return NULL;
75 if ((size&(alignment-1)) != 0) return NULL; // C11 requires integral multiple, see <https://en.cppreference.com/w/c/memory/aligned_alloc>
76 return mi_malloc_aligned(size, alignment);
77}
78
79void* mi_reallocarray( void* p, size_t count, size_t size ) mi_attr_noexcept { // BSD
80 void* newp = mi_reallocn(p,count,size);
81 if (newp==NULL) errno = ENOMEM;
82 return newp;
83}
84
85void* mi__expand(void* p, size_t newsize) mi_attr_noexcept { // Microsoft
86 void* res = mi_expand(p, newsize);
87 if (res == NULL) errno = ENOMEM;
88 return res;
89}
90
91unsigned short* mi_wcsdup(const unsigned short* s) mi_attr_noexcept {
92 if (s==NULL) return NULL;
93 size_t len;
94 for(len = 0; s[len] != 0; len++) { }
95 size_t size = (len+1)*sizeof(unsigned short);
96 unsigned short* p = (unsigned short*)mi_malloc(size);
97 if (p != NULL) {
98 memcpy(p,s,size);
99 }
100 return p;
101}
102
103unsigned char* mi_mbsdup(const unsigned char* s) mi_attr_noexcept {
104 return (unsigned char*)mi_strdup((const char*)s);
105}
106
107int mi_dupenv_s(char** buf, size_t* size, const char* name) mi_attr_noexcept {
108 if (buf==NULL || name==NULL) return EINVAL;
109 if (size != NULL) *size = 0;
110 #pragma warning(suppress:4996)
111 char* p = getenv(name);
112 if (p==NULL) {
113 *buf = NULL;
114 }
115 else {
116 *buf = mi_strdup(p);
117 if (*buf==NULL) return ENOMEM;
118 if (size != NULL) *size = strlen(p);
119 }
120 return 0;
121}
122
123int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name) mi_attr_noexcept {
124 if (buf==NULL || name==NULL) return EINVAL;
125 if (size != NULL) *size = 0;
126#if !defined(_WIN32) || (defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP))
127 // not supported
128 *buf = NULL;
129 return EINVAL;
130#else
131 #pragma warning(suppress:4996)
132 unsigned short* p = (unsigned short*)_wgetenv((const wchar_t*)name);
133 if (p==NULL) {
134 *buf = NULL;
135 }
136 else {
137 *buf = mi_wcsdup(p);
138 if (*buf==NULL) return ENOMEM;
139 if (size != NULL) *size = wcslen((const wchar_t*)p);
140 }
141 return 0;
142#endif
143}
144
145void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept { // Microsoft
146 return mi_recalloc_aligned_at(p, newcount, size, alignment, offset);
147}
148
149void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { // Microsoft
150 return mi_recalloc_aligned(p, newcount, size, alignment);
151}
152