Thanks to visit codestin.com
Credit goes to github.com

Skip to content

C API flaw - the callbacks can't pass user context #10

@alula

Description

@alula

I've been looking into the C API definitions in dave.h and noticed a significant limitation regarding callback handling.

Currently, the callback typedefs (like DAVEMLSFailureCallback and DAVEPairwiseFingerprintCallback) are defined as plain function pointers without a user context parameter:

typedef void (*DAVEMLSFailureCallback)(const char* source, const char* reason);
typedef void (*DAVEPairwiseFingerprintCallback)(const uint8_t* fingerprint, size_t length);
typedef void (*DAVEEncryptorProtocolVersionChangedCallback)(void);
typedef void (*DAVELogSinkCallback)(DAVELoggingSeverity severity,
const char* file,
int line,
const char* message);

And the registration functions do not accept a context pointer to pass through:

DAVE_EXPORT DAVESessionHandle daveSessionCreate(void* context,
const char* authSessionId,
DAVEMLSFailureCallback callback);

The Problem

While the underlying C++ implementation uses std::function (which supports capturing state/this), the C API strips this context away.

This makes it effectively impossible to map a callback invocation back to a specific session instance or language-level object without resorting to unsafe global state or thread-local storage.

For consumers using C++ or things like JNI, this isn't strictly a blocker because we can wrap the C++ API directly. However, for any consumer attempting to use the C API via FFI mechanisms (like Java's JNA/Project Panama, C# P/Invoke, Python ctypes, or Rust bindgen), this is a major pain point.

To make this work currently with FFI, one would have to resort to extreme hacks, like JIT-compiling a unique trampoline function for every session instance just to bake the instance pointer into the instruction stream.

Suggested Fix

Add a void* user_data argument to every callback type definition and any function consuming the callback.

The signatures should ideally look something like this:

typedef void (*DAVEMLSFailureCallback)(void* user_data, const char* source, const char* reason);

DAVE_EXPORT DAVESessionHandle daveSessionCreate(void* context,
                                                const char* authSessionId,
                                                DAVEMLSFailureCallback callback,
                                                void* user_data); // <--- Passed back to callback

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions