1 /******************************************************************************
2 * Project: PROJ.4
3 * Purpose: Memory management for proj.4.
4 * This version includes an implementation of generic destructors,
5 * for memory deallocation for the large majority of PJ-objects
6 * that do not allocate anything else than the PJ-object itself,
7 * and its associated opaque object - i.e. no additional malloc'ed
8 * memory inside the opaque object.
9 *
10 * Author: Gerald I. Evenden (Original proj.4 author),
11 * Frank Warmerdam (2000) pj_malloc?
12 * Thomas Knudsen (2016) - freeup/dealloc parts
13 *
14 ******************************************************************************
15 * Copyright (c) 2000, Frank Warmerdam
16 * Copyright (c) 2016, Thomas Knudsen / SDFE
17 *
18 * Permission is hereby granted, free of charge, to any person obtaining a
19 * copy of this software and associated documentation files (the "Software"),
20 * to deal in the Software without restriction, including without limitation
21 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22 * and/or sell copies of the Software, and to permit persons to whom the
23 * Software is furnished to do so, subject to the following conditions:
24 *
25 * The above copyright notice and this permission notice shall be included
26 * in all copies or substantial portions of the Software.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34 * DEALINGS IN THE SOFTWARE.
35 *****************************************************************************/
36
37 /* allocate and deallocate memory */
38 /* These routines are used so that applications can readily replace
39 ** projection system memory allocation/deallocation call with custom
40 ** application procedures. */
41
42 #include <errno.h>
43 #include <stddef.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include <new>
48
49 #include "proj.h"
50 #include "proj_internal.h"
51 #include "grids.hpp"
52 #include "filemanager.hpp"
53
54 using namespace NS_PROJ;
55
56 /**********************************************************************/
pj_malloc(size_t size)57 void *pj_malloc(size_t size) {
58 /***********************************************************************
59 Currently, pj_malloc is a hack to solve an errno problem.
60 The problem is described in more details at
61 https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=86420.
62 It seems, that pj_init and similar functions incorrectly
63 (under debian/glibs-2.3.2) assume that pj_malloc resets
64 errno after success. pj_malloc tries to mimic this.
65
66 NOTE (2017-09-29): The problem described at the bugzilla page
67 referred to above, is most likely a case of someone not
68 understanding the proper usage of errno. We should review
69 whether "the problem is actually a problem" in PROJ.4 code.
70
71 Library specific allocators can be useful, and improve
72 interoperability, if properly used. That is, by making them
73 run/initialization time switchable, somewhat like the file i/o
74 interface.
75
76 But as things stand, we are more likely to get benefit
77 from reviewing the code for proper errno usage, which is hard,
78 due to the presence of context local and global pj_errnos.
79
80 Probably, these were introduced in order to support incomplete
81 implementations of thread local errnos at an early phase of the
82 implementation of multithreading support in PROJ.4).
83
84 It is likely too late to get rid of contexts, but we can still
85 benefit from a better usage of errno.
86 ***********************************************************************/
87 int old_errno = errno;
88 void *res = malloc(size);
89 if ( res && !old_errno )
90 errno = 0;
91 return res;
92 }
93
94
95 /**********************************************************************/
pj_calloc(size_t n,size_t size)96 void *pj_calloc (size_t n, size_t size) {
97 /***********************************************************************
98 pj_calloc is the pj-equivalent of calloc().
99
100 It allocates space for an array of <n> elements of size <size>.
101 The array is initialized to zeros.
102 ***********************************************************************/
103 void *res = pj_malloc (n*size);
104 if (nullptr==res)
105 return nullptr;
106 memset (res, 0, n*size);
107 return res;
108 }
109
110
111 /**********************************************************************/
pj_dalloc(void * ptr)112 void pj_dalloc(void *ptr) {
113 /**********************************************************************/
114 free(ptr);
115 }
116
117
118 /**********************************************************************/
pj_dealloc(void * ptr)119 void *pj_dealloc (void *ptr) {
120 /***********************************************************************
121 pj_dealloc supports the common use case of "clean up and return a null
122 pointer" to signal an error in a multi level allocation:
123
124 struct foo { int bar; int *baz; };
125
126 struct foo *p = pj_calloc (1, sizeof (struct foo));
127 if (0==p)
128 return 0;
129
130 p->baz = pj_calloc (10, sizeof(int));
131 if (0==p->baz)
132 return pj_dealloc (p); // clean up + signal error by 0-return
133
134 return p; // success
135
136 ***********************************************************************/
137 if (nullptr==ptr)
138 return nullptr;
139 pj_dalloc (ptr);
140 return nullptr;
141 }
142
143 /**********************************************************************/
pj_strdup(const char * str)144 char *pj_strdup(const char *str)
145 /**********************************************************************/
146 {
147 size_t len = strlen(str) + 1;
148 char *dup = static_cast<char*>(pj_malloc(len));
149 if (dup)
150 memcpy(dup, str, len);
151 return dup;
152 }
153
154
155 /*****************************************************************************/
pj_dealloc_params(PJ_CONTEXT * ctx,paralist * start,int errlev)156 void *pj_dealloc_params (PJ_CONTEXT *ctx, paralist *start, int errlev) {
157 /*****************************************************************************
158 Companion to pj_default_destructor (below). Deallocates a linked list
159 of "+proj=xxx" initialization parameters.
160
161 Also called from pj_init_ctx when encountering errors before the PJ
162 proper is allocated.
163 ******************************************************************************/
164 paralist *t, *n;
165 for (t = start; t; t = n) {
166 n = t->next;
167 pj_dealloc(t);
168 }
169 pj_ctx_set_errno (ctx, errlev);
170 return (void *) nullptr;
171 }
172
173
174
175
176 /************************************************************************/
177 /* pj_free() */
178 /* */
179 /* This is the application callable entry point for destroying */
180 /* a projection definition. It does work generic to all */
181 /* projection types, and then calls the projection specific */
182 /* free function, P->destructor(), to do local work. */
183 /* In most cases P->destructor()==pj_default_destructor. */
184 /************************************************************************/
185
pj_free(PJ * P)186 void pj_free(PJ *P) {
187 if (nullptr==P || !P->destructor)
188 return;
189 /* free projection parameters - all the hard work is done by */
190 /* pj_default_destructor, which is supposed */
191 /* to be called as the last step of the local destructor */
192 /* pointed to by P->destructor. In most cases, */
193 /* pj_default_destructor actually *is* what is pointed to */
194 P->destructor (P, proj_errno(P));
195 }
196
197 /*****************************************************************************/
198 // cppcheck-suppress uninitMemberVar
PJconsts()199 PJconsts::PJconsts(): destructor(pj_default_destructor) {}
200 /*****************************************************************************/
201
202 /*****************************************************************************/
pj_new()203 PJ *pj_new() {
204 /*****************************************************************************/
205 return new(std::nothrow) PJ();
206 }
207
208
209 /*****************************************************************************/
pj_default_destructor(PJ * P,int errlev)210 PJ *pj_default_destructor (PJ *P, int errlev) { /* Destructor */
211 /*****************************************************************************
212 Does memory deallocation for "plain" PJ objects, i.e. that vast majority
213 of PJs where the opaque object does not contain any additionally
214 allocated memory below the P->opaque level.
215 ******************************************************************************/
216
217 /* Even if P==0, we set the errlev on pj_error and the default context */
218 /* Note that both, in the multithreaded case, may then contain undefined */
219 /* values. This is expected behavior. For MT have one ctx per thread */
220 if (0!=errlev)
221 pj_ctx_set_errno (pj_get_ctx(P), errlev);
222
223 if (nullptr==P)
224 return nullptr;
225
226
227 pj_dealloc(P->def_size);
228 pj_dealloc(P->def_shape);
229 pj_dealloc(P->def_spherification);
230 pj_dealloc(P->def_ellps);
231
232 delete static_cast<ListOfHGrids*>(P->hgrids_legacy);
233 delete static_cast<ListOfVGrids*>(P->vgrids_legacy);
234
235 /* We used to call pj_dalloc( P->catalog ), but this will leak */
236 /* memory. The safe way to clear catalog and grid is to call */
237 /* pj_gc_unloadall(pj_get_default_ctx()); and pj_deallocate_grids(); */
238 /* TODO: we should probably have a public pj_cleanup() method to do all */
239 /* that */
240
241 /* free the interface to Charles Karney's geodesic library */
242 pj_dealloc( P->geod );
243
244 /* free parameter list elements */
245 pj_dealloc_params (pj_get_ctx(P), P->params, errlev);
246 pj_dealloc (P->def_full);
247
248 /* free the cs2cs emulation elements */
249 pj_free (P->axisswap);
250 pj_free (P->helmert);
251 pj_free (P->cart);
252 pj_free (P->cart_wgs84);
253 pj_free (P->hgridshift);
254 pj_free (P->vgridshift);
255
256 pj_dealloc (static_cast<struct pj_opaque*>(P->opaque));
257 delete P;
258 return nullptr;
259 }
260
261 /*****************************************************************************/
proj_cleanup()262 void proj_cleanup() {
263 /*****************************************************************************/
264 pj_clear_initcache();
265 pj_deallocate_grids();
266 FileManager::clearMemoryCache();
267 pj_clear_hgridshift_knowngrids_cache();
268 pj_clear_vgridshift_knowngrids_cache();
269 }
270