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..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 @@ -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) @@ -44,12 +51,14 @@ 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: * - 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)( @@ -73,14 +82,16 @@ 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: - * - 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 +113,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);