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