Coverage Report

Created: 2026-10-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Objects/mimalloc/alloc-posix.c
Line
Count
Source
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
0
mi_decl_nodiscard size_t mi_malloc_good_size(size_t size) mi_attr_noexcept {
35
0
  return mi_good_size(size);
36
0
}
37
38
0
void mi_cfree(void* p) mi_attr_noexcept {
39
0
  if (mi_is_in_heap_region(p)) {
40
0
    mi_free(p);
41
0
  }
42
0
}
43
44
0
int mi_posix_memalign(void** p, size_t alignment, size_t size) {  // mi_attr_noexcept (issue #794)
45
  // Note: The spec dictates we should not modify `*p` on an error. (issue#27)
46
  // <http://man7.org/linux/man-pages/man3/posix_memalign.3.html>
47
0
  if (p == NULL) return EINVAL;
48
  // it is required that alignment is a power of 2 and a multiple of sizeof(void*)
49
0
  if (alignment<sizeof(void*) || !_mi_is_power_of_two(alignment)) return EINVAL;  // not a power of 2
50
0
  void* q = mi_malloc_aligned(size, alignment);
51
0
  if (q==NULL && size != 0) return ENOMEM;
52
0
  mi_assert_internal(_mi_is_aligned(q,alignment));
53
0
  *p = q;
54
0
  return 0;
55
0
}
56
57
0
mi_decl_nodiscard mi_decl_restrict void* mi_memalign(size_t alignment, size_t size) mi_attr_noexcept {
58
0
  void* p = mi_malloc_aligned(size, alignment);
59
0
  mi_assert_internal(_mi_is_aligned(p,alignment));
60
0
  return p;
61
0
}
62
63
0
mi_decl_nodiscard mi_decl_restrict void* mi_valloc(size_t size) mi_attr_noexcept {
64
0
  return mi_memalign( _mi_os_page_size(), size );
65
0
}
66
67
0
mi_decl_nodiscard mi_decl_restrict void* mi_pvalloc(size_t size) mi_attr_noexcept {
68
0
  size_t psize = _mi_os_page_size();
69
0
  if (size >= SIZE_MAX - psize) return NULL; // overflow
70
0
  size_t asize = _mi_align_up(size, psize);
71
0
  return mi_malloc_aligned(asize, psize);
72
0
}
73
74
0
mi_decl_nodiscard mi_decl_restrict void* mi_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept {
75
  // C11 requires the size to be an integral multiple of the alignment, see <https://en.cppreference.com/w/c/memory/aligned_alloc>.
76
  // unfortunately, it turns out quite some programs pass a size that is not an integral multiple so skip this check..
77
  /* if mi_unlikely((size & (alignment - 1)) != 0) { // C11 requires alignment>0 && integral multiple, see <https://en.cppreference.com/w/c/memory/aligned_alloc>
78
      #if MI_DEBUG > 0
79
      _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);
80
      #endif
81
      return NULL;
82
    }
83
  */
84
  // C11 also requires alignment to be a power-of-two (and > 0) which is checked in mi_malloc_aligned
85
0
  void* p = mi_malloc_aligned(size, alignment);
86
0
  mi_assert_internal(_mi_is_aligned(p,alignment));
87
0
  return p;
88
0
}
89
90
0
mi_decl_nodiscard void* mi_reallocarray( void* p, size_t count, size_t size ) mi_attr_noexcept {  // BSD <https://man.freebsd.org/cgi/man.cgi?query=reallocarray>
91
0
  size_t total;
92
0
  if mi_unlikely(mi_count_size_overflow(count, size, &total)) {
93
0
    errno = EOVERFLOW;
94
0
    return NULL;
95
0
  }
96
0
  void* newp = mi_realloc(p,total);
97
0
  if (newp==NULL) { errno = ENOMEM; }
98
0
  return newp;
99
0
}
100
101
0
mi_decl_nodiscard int mi_reallocarr( void* ptrp, size_t count, size_t size ) mi_attr_noexcept { // NetBSD <https://man.netbsd.org/reallocarr.3>
102
0
  mi_assert(size != 0);
103
0
  mi_assert(ptrp != NULL);
104
0
  if (ptrp == NULL || size == 0) {
105
0
    return (errno = EINVAL);
106
0
  }
107
0
  size_t total;
108
0
  if mi_unlikely(mi_count_size_overflow(count, size, &total)) {
109
0
    return (errno = EOVERFLOW);
110
0
  }
111
0
  void** op = (void**)ptrp;
112
0
  if (total == 0) {
113
0
    mi_free(*op);
114
0
    *op = NULL;
115
0
    return 0;
116
0
  }
117
0
  else {
118
0
    void* newp = mi_realloc(*op,total);
119
0
    if (newp == NULL) { return (errno = ENOMEM); }
120
0
    *op = newp;
121
0
    return 0;
122
0
  }
123
0
}
124
125
0
void* mi__expand(void* p, size_t newsize) mi_attr_noexcept {  // Microsoft
126
0
  void* res = mi_expand(p, newsize);
127
0
  if (res == NULL) { errno = ENOMEM; }
128
0
  return res;
129
0
}
130
131
0
mi_decl_nodiscard mi_decl_restrict wchar_t* mi_wcsdup(const wchar_t* s) mi_attr_noexcept {
132
0
  if (s==NULL) return NULL;
133
0
  size_t wlen;
134
0
  for(wlen = 0; s[wlen] != 0 && wlen < PTRDIFF_MAX; wlen++) { }  // prevent overflow on wlen+1
135
0
  size_t size;
136
0
  if (mi_mul_overflow(wlen+1, sizeof(wchar_t), &size) || size > PTRDIFF_MAX) return NULL;
137
0
  wchar_t* p = (wchar_t*)mi_malloc(size);
138
0
  if (p != NULL) {
139
0
    _mi_memcpy(p,s,size);
140
0
  }
141
0
  return p;
142
0
}
143
144
0
mi_decl_nodiscard mi_decl_restrict unsigned char* mi_mbsdup(const unsigned char* s)  mi_attr_noexcept {
145
0
  return (unsigned char*)mi_strdup((const char*)s);
146
0
}
147
148
0
int mi_dupenv_s(char** buf, size_t* size, const char* name) mi_attr_noexcept {
149
0
  if (size != NULL) *size = 0;
150
0
  if (buf==NULL || name==NULL) return EINVAL;
151
0
  char* p = getenv(name);
152
0
  if (p==NULL) {
153
0
    *buf = NULL;
154
0
  }
155
0
  else {
156
0
    *buf = mi_strdup(p);
157
0
    if (*buf==NULL) return ENOMEM;
158
0
    if (size != NULL) { *size = _mi_strlen(p) + 1; }    // cannot overflow as mi_strdup is limited to PTRDIFF_MAX
159
0
  }
160
0
  return 0;
161
0
}
162
163
0
int mi_wdupenv_s(wchar_t** buf, size_t* size, const wchar_t* name) mi_attr_noexcept {
164
0
  if (size != NULL) *size = 0;
165
0
  if (buf==NULL || name==NULL) return EINVAL;
166
0
#if !defined(_WIN32) || (defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP))
167
  // not supported
168
0
  *buf = NULL;
169
0
  return EINVAL;
170
#else
171
  wchar_t* p = (wchar_t*)_wgetenv(name);
172
  if (p==NULL) {
173
    *buf = NULL;
174
  }
175
  else {
176
    *buf = mi_wcsdup(p);
177
    if (*buf==NULL) return ENOMEM;
178
    if (size != NULL) { *size = wcslen(p) + 1; }  // cannot overflow as wcsdup is limited to PTRDIFF_MAX
179
  }
180
  return 0;
181
#endif
182
0
}
183
184
0
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
185
0
  return mi_recalloc_aligned_at(p, newcount, size, alignment, offset);
186
0
}
187
188
0
mi_decl_nodiscard void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept { // Microsoft
189
0
  return mi_recalloc_aligned(p, newcount, size, alignment);
190
0
}