Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ardupilot
GitHub Repository: Ardupilot/ardupilot
Path: blob/master/libraries/AP_Common/c++.cpp
9357 views
1
/*
2
wrapper around new for C++ to ensure we always get zero filled memory
3
*/
4
5
#include <AP_HAL/AP_HAL.h>
6
#include <stdlib.h>
7
#include <new>
8
#include <AP_InternalError/AP_InternalError.h>
9
10
/*
11
globally override new and delete to ensure that we always start with
12
zero memory. This ensures consistent behaviour.
13
14
Note that new comes in multiple different variants. When new is used
15
without std::nothrow the compiler is free to assume it will not fail
16
as it assumes exceptions are enabled. This makes code like this
17
unsafe when using -fno-exceptions:
18
19
a = new b;
20
if (a == nullptr) {
21
handle_error()
22
}
23
24
the compiler may remove the error handling. With g++ you can use
25
-fcheck-new to avoid this, but on clang++ the compiler accepts
26
-fcheck-new as a valid flag, but doesn't implement it, and may elide
27
the error checking. That makes using clang++ unsafe with
28
-fno-exceptions if you ever call new without std::nothrow.
29
30
To avoid this we define NEW_NOTHROW as new(std::nothrow) and use it
31
everywhere in ArduPilot, then we catch any missing cases with both
32
an internal error and with a check of the elf for the symbols we
33
want to avoid
34
*/
35
36
/*
37
variant for new(std::nothrow), which is all that should be used in
38
ArduPilot
39
*/
40
void * operator new(size_t size, std::nothrow_t const &nothrow)
41
{
42
if (size < 1) {
43
size = 1;
44
}
45
return(calloc(size, 1));
46
}
47
48
void * operator new[](size_t size, std::nothrow_t const &nothrow)
49
{
50
if (size < 1) {
51
size = 1;
52
}
53
return(calloc(size, 1));
54
}
55
56
/*
57
These variants are for new without std::nothrow. We don't want to ever
58
use this from ArduPilot code
59
*/
60
void * operator new(size_t size)
61
{
62
if (size < 1) {
63
size = 1;
64
}
65
return(calloc(size, 1));
66
}
67
68
69
void * operator new[](size_t size)
70
{
71
if (size < 1) {
72
size = 1;
73
}
74
return(calloc(size, 1));
75
}
76
77
void operator delete(void *p)
78
{
79
if (p) free(p);
80
}
81
82
void operator delete[](void * ptr)
83
{
84
if (ptr) free(ptr);
85
}
86
87
#if defined(CYGWIN_BUILD) && CONFIG_HAL_BOARD == HAL_BOARD_SITL
88
89
// intercept malloc to ensure memory so allocated is zeroed. this is rather
90
// nasty hack that hopefully does not live long! if it breaks again, that's it!
91
// this is completely unsupported!
92
93
// __imp_malloc is a pointer to a function that will be called to actually
94
// do the malloc work. we can't replace it (or malloc itself) at build time as
95
// that will cause cygwin to disable its own malloc. we therefore use a
96
// constructor function that runs before main but after cygwin's disable check
97
// to set the pointer to our own malloc which calls back into cygwin's allocator
98
// through calloc to actually do the work and the zeroing.
99
100
#include <stdio.h> // perror
101
#include <sys/mman.h> // mprotect and constants
102
103
extern "C" void *__imp_malloc; // the pointer of our affection
104
105
static void *do_the_malloc(size_t size) { // replacement for malloc
106
// allocate zeroed using calloc (malloc would of course recurse infinitely)
107
return calloc(1, size);
108
}
109
110
// called before main to set __imp_malloc. priority of 101 guarantees execution
111
// before C++ constructors.
112
__attribute__((constructor(101))) static void hack_in_malloc() {
113
// __imp_malloc is in .text which is read-only so make it read-write first
114
115
// compute address of its memory page as mprotect mandates page alignment
116
size_t page_size = (size_t)sysconf(_SC_PAGESIZE);
117
void *page_base = (void *)((size_t)&__imp_malloc & (~(page_size-1)));
118
119
// make it writable and executable as we (unlikely) may be executing near it
120
int res = mprotect(page_base, page_size, PROT_READ|PROT_WRITE|PROT_EXEC);
121
if (res) {
122
perror("hack_in_malloc() mprotect writable");
123
}
124
125
*(void **)&__imp_malloc = (void *)&do_the_malloc; // set the pointer now
126
127
// put the page back to read-only (and let execution keep happening)
128
res = mprotect(page_base, page_size, PROT_READ|PROT_EXEC);
129
if (res) {
130
perror("hack_in_malloc() mprotect readable");
131
}
132
}
133
134
#elif CONFIG_HAL_BOARD != HAL_BOARD_CHIBIOS && CONFIG_HAL_BOARD != HAL_BOARD_QURT
135
/*
136
wrapper around malloc to ensure all memory is initialised as zero
137
ChibiOS and QURT have their own wrappers
138
*/
139
extern "C" {
140
void *__wrap_malloc(size_t size);
141
void *__real_malloc(size_t size);
142
}
143
void *__wrap_malloc(size_t size)
144
{
145
void *ret = __real_malloc(size);
146
if (ret != nullptr) {
147
memset(ret, 0, size);
148
}
149
return ret;
150
}
151
#endif
152
153
/*
154
custom realloc which is guaranteed to zero newly-allocated memory
155
(assuming malloc does). marked as WEAK so tests can override it.
156
157
* always frees ptr (and returns nullptr) if new_size is 0
158
* allocates if ptr is nullptr and new_size is not 0
159
* else allocates new_size and copies over the smaller of old_size and new_size
160
and frees ptr (old_size can be <= actual original requested size)
161
* returns nullptr if allocation fails and leaves ptr and its data unchanged
162
*/
163
void * WEAK mem_realloc(void *ptr, size_t old_size, size_t new_size)
164
{
165
if (new_size == 0) {
166
free(ptr);
167
return nullptr;
168
}
169
170
if (ptr == nullptr) {
171
return malloc(new_size);
172
}
173
174
void *new_ptr = malloc(new_size);
175
if (new_ptr != nullptr) {
176
size_t copy_size = new_size > old_size ? old_size : new_size;
177
memcpy(new_ptr, ptr, copy_size);
178
free(ptr);
179
}
180
181
return new_ptr;
182
}
183
184