1212
1313#include < iostream>
1414#include < sstream>
15+ #include < memory>
1516
1617#include " config.h"
1718#include " dataStructure/hashtable/hashtable.h"
@@ -58,7 +59,10 @@ struct RequestDeleter {
5859// **** Python plugin cache implementation BEGIN ****
5960// ***********************************************************************
6061
61- typedef struct pypluginCache_params {
62+ // Forward declaration with appropriate visibility
63+ struct pypluginCache_params ;
64+
65+ typedef struct __attribute__ ((visibility(" hidden" ))) pypluginCache_params {
6266 py::object data; // /< Plugin's internal data structure (python object)
6367 py::function cache_init_hook;
6468 py::function cache_hit_hook;
@@ -69,6 +73,23 @@ typedef struct pypluginCache_params {
6973 std::string cache_name;
7074} pypluginCache_params_t;
7175
76+ // Custom deleter for pypluginCache_params_t
77+ struct PypluginCacheParamsDeleter {
78+ void operator ()(pypluginCache_params_t* ptr) const {
79+ if (ptr != nullptr ) {
80+ // Call the free hook if available before deletion
81+ if (!ptr->cache_free_hook .is_none ()) {
82+ try {
83+ ptr->cache_free_hook (ptr->data );
84+ } catch (...) {
85+ // Ignore exceptions during cleanup to prevent double-fault
86+ }
87+ }
88+ delete ptr;
89+ }
90+ }
91+ };
92+
7293static void pypluginCache_free (cache_t * cache);
7394static bool pypluginCache_get (cache_t * cache, const request_t * req);
7495static cache_obj_t * pypluginCache_find (cache_t * cache, const request_t * req,
@@ -84,47 +105,70 @@ cache_t* pypluginCache_init(
84105 py::function cache_init_hook, py::function cache_hit_hook,
85106 py::function cache_miss_hook, py::function cache_eviction_hook,
86107 py::function cache_remove_hook, py::function cache_free_hook) {
87- // Initialize base cache structure
88- cache_t * cache = cache_struct_init (cache_name.c_str (), ccache_params, NULL );
89-
90- // Set function pointers for cache operations
91- cache->cache_init = NULL ;
92- cache->cache_free = pypluginCache_free;
93- cache->get = pypluginCache_get;
94- cache->find = pypluginCache_find;
95- cache->insert = pypluginCache_insert;
96- cache->evict = pypluginCache_evict;
97- cache->remove = pypluginCache_remove;
98- cache->to_evict = pypluginCache_to_evict;
99- cache->get_occupied_byte = cache_get_occupied_byte_default;
100- cache->get_n_obj = cache_get_n_obj_default;
101- cache->can_insert = cache_can_insert_default;
102- cache->obj_md_size = 0 ;
103-
104- // Allocate and initialize plugin parameters
105- pypluginCache_params_t* params = new pypluginCache_params_t ();
106- params->cache_name = cache_name;
107- params->cache_init_hook = cache_init_hook;
108- params->cache_hit_hook = cache_hit_hook;
109- params->cache_miss_hook = cache_miss_hook;
110- params->cache_eviction_hook = cache_eviction_hook;
111- params->cache_remove_hook = cache_remove_hook;
112- params->cache_free_hook = cache_free_hook;
113- params->data = cache_init_hook (ccache_params);
114-
115- cache->eviction_params = params;
116-
117- return cache;
108+
109+ // Initialize base cache structure with exception safety
110+ cache_t * cache = nullptr ;
111+ std::unique_ptr<pypluginCache_params_t, PypluginCacheParamsDeleter> params;
112+
113+ try {
114+ cache = cache_struct_init (cache_name.c_str (), ccache_params, NULL );
115+ if (!cache) {
116+ throw std::runtime_error (" Failed to initialize cache structure" );
117+ }
118+
119+ // Set function pointers for cache operations
120+ cache->cache_init = NULL ;
121+ cache->cache_free = pypluginCache_free;
122+ cache->get = pypluginCache_get;
123+ cache->find = pypluginCache_find;
124+ cache->insert = pypluginCache_insert;
125+ cache->evict = pypluginCache_evict;
126+ cache->remove = pypluginCache_remove;
127+ cache->to_evict = pypluginCache_to_evict;
128+ cache->get_occupied_byte = cache_get_occupied_byte_default;
129+ cache->get_n_obj = cache_get_n_obj_default;
130+ cache->can_insert = cache_can_insert_default;
131+ cache->obj_md_size = 0 ;
132+
133+ // Allocate and initialize plugin parameters using smart pointer with custom deleter
134+ params = std::unique_ptr<pypluginCache_params_t, PypluginCacheParamsDeleter>(
135+ new pypluginCache_params_t (), PypluginCacheParamsDeleter ());
136+ params->cache_name = cache_name;
137+ params->cache_init_hook = cache_init_hook;
138+ params->cache_hit_hook = cache_hit_hook;
139+ params->cache_miss_hook = cache_miss_hook;
140+ params->cache_eviction_hook = cache_eviction_hook;
141+ params->cache_remove_hook = cache_remove_hook;
142+ params->cache_free_hook = cache_free_hook;
143+
144+ // Initialize the cache data - this might throw
145+ params->data = cache_init_hook (ccache_params);
146+
147+ // Transfer ownership to the cache structure
148+ cache->eviction_params = params.release ();
149+
150+ return cache;
151+
152+ } catch (...) {
153+ // Clean up on exception
154+ if (cache) {
155+ cache_struct_free (cache);
156+ }
157+ // params will be automatically cleaned up by smart pointer destructor
158+ throw ; // Re-throw the exception
159+ }
118160}
119161
120162static void pypluginCache_free (cache_t * cache) {
121- pypluginCache_params_t* params =
122- (pypluginCache_params_t*)cache->eviction_params ;
123-
124- if (!params->cache_free_hook .is_none ()) {
125- params->cache_free_hook (params->data );
163+ if (!cache || !cache->eviction_params ) {
164+ return ;
126165 }
127- delete params;
166+
167+ // Use smart pointer for automatic cleanup
168+ std::unique_ptr<pypluginCache_params_t, PypluginCacheParamsDeleter> params (
169+ static_cast <pypluginCache_params_t*>(cache->eviction_params ));
170+
171+ // The smart pointer destructor will handle cleanup automatically
128172 cache_struct_free (cache);
129173}
130174
0 commit comments