Fix crash in plugin function callback (#21713)
* Handle dictionary destruction in plugins: clean up and notify caller on error * One more check
Stelios Fragkakis committed
Feb 11, 2026 at 23:58 UTC
a56ad2c5a3606e494476dceef09dde6d7a07f1bc
2 files changed
+29
src/database/rrdfunctions-inflight.c
+13
@@ -531,6 +531,19 @@ int rrd_function_run(RRDHOST *host, BUFFER *result_wb, int timeout_s,
531
uuid_copy(t.transaction_uuid, uuid);
532
533
struct rrd_function_inflight *r = dictionary_set(rrd_functions_inflight_requests, transaction, &t, sizeof(t));
534
+ if(!r) {
535
+ // dictionary_set() returns NULL when the dictionary is destroyed (shutdown in progress)
536
+ code = rrd_call_function_error(result_wb, "Service is shutting down.", HTTP_RESP_SERVICE_UNAVAILABLE);
537
+
538
+ rrd_functions_inflight_cleanup(&t);
539
+ dictionary_acquired_item_release(host->functions, t.host_function_acquired);
540
+
541
+ if(result_cb)
542
+ result_cb(result_wb, code, result_cb_data);
543
+
544
+ return code;
545
+ }
546
+
547
if(r->used) {
548
nd_log(NDLS_DAEMON, NDLP_NOTICE,
549
"FUNCTIONS: duplicate transaction '%s', function: '%s'",
src/plugins.d/pluginsd_functions.c
+16
@@ -270,6 +270,22 @@ int pluginsd_function_execute_cb(struct rrd_function_execute *rfe, void *data) {
270
// if there is any error, our dictionary callbacks will call the caller callback to notify
271
// the caller about the error - no need for error handling here.
272
struct inflight_function *t = dictionary_set(parser->inflight.functions, transaction_str, &tmp, sizeof(struct inflight_function));
273
+ if(!t) {
274
+ // dictionary_set() returns NULL when the dictionary is destroyed
275
+ // (e.g., the plugin has exited). Clean up and notify the caller.
276
+ dictionary_write_unlock(parser->inflight.functions);
277
+
278
+ int code = HTTP_RESP_SERVICE_UNAVAILABLE;
279
+ rrd_call_function_error(rfe->result.wb, "The plugin is not available.", code);
280
+ rfe->result.cb(rfe->result.wb, code, rfe->result.data);
281
+
282
+ string_freez(tmp.function);
283
+ buffer_free(tmp.payload);
284
+ freez((void *)tmp.source);
285
+
286
+ return code;
287
+ }
288
+
289
if(!t->sent_successfully) {
290
int code = t->code;
291
dictionary_write_unlock(parser->inflight.functions);