From fd1c0906224791550a94d2449da2dabde6a33cca Mon Sep 17 00:00:00 2001 From: Samuel Kogler Date: Fri, 11 Nov 2022 13:08:57 +0100 Subject: [PATCH] Fix memory leak in CRS.to_authority/CRS.list_authority List elements were not properly disposed of when iterating the results of proj_identify. This fixes this and simplifies the cleanup logic. --- docs/history.rst | 1 + pyproj/_crs.pyx | 35 ++++++++++++++++++----------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/docs/history.rst b/docs/history.rst index 00c6c7c69..c90485e07 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -8,6 +8,7 @@ Latest ----- - BUG: Changed so that the setup.cfg depends on the version code in the __init__.py instead of the other way around (issuue #1155) - BUG: Fix :meth:`.CRS.to_cf` for Pole rotation GRIB convention (pull #1167) +- BUG: Fix :meth:`.CRS.to_authority` memory leak (pull #1178) - REF: Use upper case EPSG code when creating CRS (pull #1162) 3.4.0 diff --git a/pyproj/_crs.pyx b/pyproj/_crs.pyx index 9a0157b3a..9a18db969 100644 --- a/pyproj/_crs.pyx +++ b/pyproj/_crs.pyx @@ -2834,15 +2834,19 @@ cdef class _CRS(Base): # get list of possible matching projections cdef PJ_OBJ_LIST *proj_list = NULL cdef int *c_out_confidence_list = NULL - cdef int num_proj_objects = -9999 + cdef int num_proj_objects = 0 cdef bytes b_auth_name cdef char *user_auth_name = NULL cdef int iii = 0 + cdef PJ * proj = NULL + cdef const char * code + cdef const char * out_auth_name if auth_name is not None: b_auth_name = cstrencode(auth_name) user_auth_name = b_auth_name + authority_list = [] out_confidence_list = [] try: proj_list = proj_identify( @@ -2854,24 +2858,16 @@ cdef class _CRS(Base): ) if proj_list != NULL: num_proj_objects = proj_list_get_count(proj_list) - if c_out_confidence_list != NULL and num_proj_objects > 0: - out_confidence_list = [ - c_out_confidence_list[iii] for iii in range(num_proj_objects) - ] - finally: - if c_out_confidence_list != NULL: - proj_int_list_destroy(c_out_confidence_list) - CRSError.clear() - # retrieve the best matching projection - cdef PJ* proj = NULL - cdef const char* code - cdef const char* out_auth_name - authority_list = [] - try: + out_confidence_list = [ + c_out_confidence_list[iii] for iii in range(num_proj_objects) + ] + + # retrieve the best matching projection for iii in range(num_proj_objects): if out_confidence_list[iii] < min_confidence: continue + proj = proj_list_get(self.context, proj_list, iii) code = proj_get_id_code(proj, 0) out_auth_name = proj_get_id_auth_name(proj, 0) @@ -2883,9 +2879,14 @@ cdef class _CRS(Base): out_confidence_list[iii] ) ) + # at this point, the auth name is copied and we can release the proj object + proj_destroy(proj) + proj = NULL finally: - for iii in range(num_proj_objects): - proj_destroy(proj_list_get(self.context, proj_list, iii)) + # If there was an error we have to call proj_destroy + # If there was none, calling it on NULL does nothing + proj_destroy(proj) + proj_int_list_destroy(c_out_confidence_list) proj_list_destroy(proj_list) CRSError.clear() return authority_list