From cdc0f43347c7499f9d4496672793425f641ee64e Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Mon, 13 Apr 2026 15:28:32 -0700 Subject: [PATCH 1/2] doc: clarify lifetime and ownership rules for C hook callback parameters Strengthen the documentation in hook.h to make it explicit that all SDK-provided pointers (series_context, data, detail, etc.) must not be retained, cached, or stored beyond the scope of the callback invocation, and that any data needed outside the callback must be copied. --- .../server_side/bindings/c/hook.h | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/libs/server-sdk/include/launchdarkly/server_side/bindings/c/hook.h b/libs/server-sdk/include/launchdarkly/server_side/bindings/c/hook.h index c2ab7bab5..8a5c9e629 100644 --- a/libs/server-sdk/include/launchdarkly/server_side/bindings/c/hook.h +++ b/libs/server-sdk/include/launchdarkly/server_side/bindings/c/hook.h @@ -10,8 +10,15 @@ * - The function pointers and UserData pointer are copied when the hook is * registered with the config builder * - UserData lifetime must extend for the entire lifetime of the SDK client - * - All context parameters passed to callbacks are temporary - valid only - * during the callback execution + * + * WARNING: All pointers passed to callbacks by the SDK (series_context, data, + * detail, etc.) are owned by the SDK and may be freed after the callback + * returns. You MUST NOT retain, cache, or store these pointers, or any + * references to data within them, beyond the scope of the callback invocation. + * Any data needed outside the duration of a callback must be copied during the + * callback. Accessing a stored pointer or reference after the callback has + * returned results in undefined behavior. + * * - EvaluationSeriesData returned from callbacks transfers ownership to the SDK */ // NOLINTBEGIN(modernize-use-using) @@ -49,7 +56,8 @@ typedef struct p_LDServerSDKTrackSeriesContext* LDServerSDKTrackSeriesContext; * * LIFETIME: * - series_context: Valid only during callback execution - do not store - * - data: Ownership transfers to SDK + * - data: Valid only during callback execution - do not store. Ownership of + * the returned value transfers to the SDK. * - user_data: Managed by caller - must remain valid for SDK lifetime */ typedef LDServerSDKEvaluationSeriesData (*LDServerSDKHook_BeforeEvaluation)( @@ -77,10 +85,11 @@ typedef LDServerSDKEvaluationSeriesData (*LDServerSDKHook_BeforeEvaluation)( * If NULL is returned, an empty data object will be created. * * LIFETIME: - * - series_context: Valid only during callback execution - * - data: Ownership transfers to SDK - * - detail: Valid only during callback execution - * - user_data: Managed by caller + * - series_context: Valid only during callback execution - do not store + * - data: Valid only during callback execution - do not store. Ownership of + * the returned value transfers to the SDK. + * - detail: Valid only during callback execution - do not store + * - user_data: Managed by caller - must remain valid for SDK lifetime */ typedef LDServerSDKEvaluationSeriesData (*LDServerSDKHook_AfterEvaluation)( LDServerSDKEvaluationSeriesContext series_context, @@ -102,8 +111,8 @@ typedef LDServerSDKEvaluationSeriesData (*LDServerSDKHook_AfterEvaluation)( * RETURNS: void (no data is passed between track stages) * * LIFETIME: - * - series_context: Valid only during callback execution - * - user_data: Managed by caller + * - series_context: Valid only during callback execution - do not store + * - user_data: Managed by caller - must remain valid for SDK lifetime */ typedef void (*LDServerSDKHook_AfterTrack)(LDServerSDKTrackSeriesContext series_context, void* user_data); From da215a4827feb48d5e76053c10301ec2681d7e78 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Mon, 13 Apr 2026 15:43:20 -0700 Subject: [PATCH 2/2] doc: clarify that returned EvaluationSeriesData must not be retained --- .../include/launchdarkly/server_side/bindings/c/hook.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/server-sdk/include/launchdarkly/server_side/bindings/c/hook.h b/libs/server-sdk/include/launchdarkly/server_side/bindings/c/hook.h index 8a5c9e629..3fc712c95 100644 --- a/libs/server-sdk/include/launchdarkly/server_side/bindings/c/hook.h +++ b/libs/server-sdk/include/launchdarkly/server_side/bindings/c/hook.h @@ -51,7 +51,8 @@ typedef struct p_LDServerSDKTrackSeriesContext* LDServerSDKTrackSeriesContext; * * RETURNS: * EvaluationSeriesData to pass to afterEvaluation. Return the input data - * unmodified if you don't need to add anything. Ownership transfers to SDK. + * unmodified if you don't need to add anything. Ownership transfers to SDK; + * the caller must not retain or access the returned pointer after returning. * If NULL is returned, an empty data object will be created. * * LIFETIME: @@ -81,7 +82,8 @@ typedef LDServerSDKEvaluationSeriesData (*LDServerSDKHook_BeforeEvaluation)( * * RETURNS: * EvaluationSeriesData for potential future stages. Return the input data - * unmodified if you don't need to modify it. Ownership transfers to SDK. + * unmodified if you don't need to modify it. Ownership transfers to SDK; + * the caller must not retain or access the returned pointer after returning. * If NULL is returned, an empty data object will be created. * * LIFETIME: