fix(codegen): C++ bindings target the *_cbor exports

The C++ wrapper speaks CBOR, but after the native/CBOR split it still called the
bare `<name>` symbols — which are now the *native* (typed-args) entry points, so
every C++ call hit the wrong ABI and the C++ e2e failed 19/19 (also reddening
the ASan/TSan jobs, which run the same suite). Point the generated extern
declarations and call sites at `<name>_cbor` for `{.ffi.}` procs and the ctor;
the destructor has no CBOR variant and stays bare. Regenerated the timer and
echo C++ bindings. C++ e2e back to 19/19.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ivan FB 2026-05-31 16:31:12 +02:00
parent a965deaae2
commit 914c70a131
No known key found for this signature in database
GPG Key ID: DF0C67A04C543270
3 changed files with 23 additions and 20 deletions

View File

@ -403,9 +403,9 @@ inline CborError decode_cbor(CborValue& it, EchoVersionReq&) {
extern "C" {
typedef void (*FFICallback)(int ret, const char* msg, size_t len, void* user_data);
void* echo_create(const uint8_t* req_cbor, size_t req_cbor_len, FFICallback callback, void* user_data);
int echo_shout(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int echo_version(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
void* echo_create_cbor(const uint8_t* req_cbor, size_t req_cbor_len, FFICallback callback, void* user_data);
int echo_shout_cbor(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int echo_version_cbor(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int echo_destroy(void* ctx);
uint64_t echo_add_event_listener(void* ctx, const char* event_name, FFICallback callback, void* user_data);
int echo_remove_event_listener(void* ctx, uint64_t listener_id);
@ -484,7 +484,7 @@ public:
if (ffi_enc_.isErr()) return Result<std::unique_ptr<EchoCtx>>::err(ffi_enc_.error());
const auto& ffi_req_bytes_ = ffi_enc_.value();
auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {
(void)echo_create(ffi_req_bytes_.data(), ffi_req_bytes_.size(), cb, ud);
(void)echo_create_cbor(ffi_req_bytes_.data(), ffi_req_bytes_.size(), cb, ud);
return 0;
}, timeout);
if (ffi_raw_.isErr()) return Result<std::unique_ptr<EchoCtx>>::err(ffi_raw_.error());
@ -532,7 +532,7 @@ public:
if (ffi_enc_.isErr()) return Result<ShoutResponse>::err(ffi_enc_.error());
const auto& ffi_req_bytes_ = ffi_enc_.value();
auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {
return echo_shout(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
return echo_shout_cbor(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
}, timeout_);
if (ffi_raw_.isErr()) return Result<ShoutResponse>::err(ffi_raw_.error());
return decodeCborFFI<ShoutResponse>(ffi_raw_.value());
@ -548,7 +548,7 @@ public:
if (ffi_enc_.isErr()) return Result<std::string>::err(ffi_enc_.error());
const auto& ffi_req_bytes_ = ffi_enc_.value();
auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {
return echo_version(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
return echo_version_cbor(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
}, timeout_);
if (ffi_raw_.isErr()) return Result<std::string>::err(ffi_raw_.error());
return decodeCborFFI<std::string>(ffi_raw_.value());

View File

@ -702,11 +702,11 @@ inline CborError decode_cbor(CborValue& it, MyTimerScheduleReq& v) {
extern "C" {
typedef void (*FFICallback)(int ret, const char* msg, size_t len, void* user_data);
void* my_timer_create(const uint8_t* req_cbor, size_t req_cbor_len, FFICallback callback, void* user_data);
int my_timer_echo(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int my_timer_version(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int my_timer_complex(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int my_timer_schedule(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
void* my_timer_create_cbor(const uint8_t* req_cbor, size_t req_cbor_len, FFICallback callback, void* user_data);
int my_timer_echo_cbor(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int my_timer_version_cbor(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int my_timer_complex_cbor(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int my_timer_schedule_cbor(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);
int my_timer_destroy(void* ctx);
uint64_t my_timer_add_event_listener(void* ctx, const char* event_name, FFICallback callback, void* user_data);
int my_timer_remove_event_listener(void* ctx, uint64_t listener_id);
@ -798,7 +798,7 @@ public:
if (ffi_enc_.isErr()) return Result<std::unique_ptr<MyTimerCtx>>::err(ffi_enc_.error());
const auto& ffi_req_bytes_ = ffi_enc_.value();
auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {
(void)my_timer_create(ffi_req_bytes_.data(), ffi_req_bytes_.size(), cb, ud);
(void)my_timer_create_cbor(ffi_req_bytes_.data(), ffi_req_bytes_.size(), cb, ud);
return 0;
}, timeout);
if (ffi_raw_.isErr()) return Result<std::unique_ptr<MyTimerCtx>>::err(ffi_raw_.error());
@ -876,7 +876,7 @@ public:
if (ffi_enc_.isErr()) return Result<EchoResponse>::err(ffi_enc_.error());
const auto& ffi_req_bytes_ = ffi_enc_.value();
auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {
return my_timer_echo(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
return my_timer_echo_cbor(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
}, timeout_);
if (ffi_raw_.isErr()) return Result<EchoResponse>::err(ffi_raw_.error());
return decodeCborFFI<EchoResponse>(ffi_raw_.value());
@ -892,7 +892,7 @@ public:
if (ffi_enc_.isErr()) return Result<std::string>::err(ffi_enc_.error());
const auto& ffi_req_bytes_ = ffi_enc_.value();
auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {
return my_timer_version(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
return my_timer_version_cbor(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
}, timeout_);
if (ffi_raw_.isErr()) return Result<std::string>::err(ffi_raw_.error());
return decodeCborFFI<std::string>(ffi_raw_.value());
@ -908,7 +908,7 @@ public:
if (ffi_enc_.isErr()) return Result<ComplexResponse>::err(ffi_enc_.error());
const auto& ffi_req_bytes_ = ffi_enc_.value();
auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {
return my_timer_complex(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
return my_timer_complex_cbor(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
}, timeout_);
if (ffi_raw_.isErr()) return Result<ComplexResponse>::err(ffi_raw_.error());
return decodeCborFFI<ComplexResponse>(ffi_raw_.value());
@ -924,7 +924,7 @@ public:
if (ffi_enc_.isErr()) return Result<ScheduleResult>::err(ffi_enc_.error());
const auto& ffi_req_bytes_ = ffi_enc_.value();
auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {
return my_timer_schedule(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
return my_timer_schedule_cbor(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());
}, timeout_);
if (ffi_raw_.isErr()) return Result<ScheduleResult>::err(ffi_raw_.error());
return decodeCborFFI<ScheduleResult>(ffi_raw_.value());

View File

@ -412,16 +412,19 @@ proc generateCppHeader*(
for p in procs:
case p.kind
of FFIKind.FFI:
# The C++ wrapper speaks CBOR, so it targets the `<name>_cbor` exports; the
# bare `<name>` symbol is the native (typed-args) entry point.
lines.add(
"int $1(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);" %
"int $1_cbor(void* ctx, FFICallback callback, void* user_data, const uint8_t* req_cbor, size_t req_cbor_len);" %
[p.procName]
)
of FFIKind.CTOR:
lines.add(
"void* $1(const uint8_t* req_cbor, size_t req_cbor_len, FFICallback callback, void* user_data);" %
"void* $1_cbor(const uint8_t* req_cbor, size_t req_cbor_len, FFICallback callback, void* user_data);" %
[p.procName]
)
of FFIKind.DTOR:
# The destructor takes no request payload, so it has no `_cbor` variant.
lines.add("int $1(void* ctx);" % [p.procName])
# `declareLibrary` always exports the listener-registration ABI. Declare
# it here so the typed event-handler wiring below can call into it.
@ -535,7 +538,7 @@ proc generateCppHeader*(
lines.add(" const auto& ffi_req_bytes_ = ffi_enc_.value();")
lines.add(" auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {")
lines.add(
" (void)$1(ffi_req_bytes_.data(), ffi_req_bytes_.size(), cb, ud);" %
" (void)$1_cbor(ffi_req_bytes_.data(), ffi_req_bytes_.size(), cb, ud);" %
[ctor.procName]
)
lines.add(" return 0;")
@ -629,7 +632,7 @@ proc generateCppHeader*(
lines.add(" const auto& ffi_req_bytes_ = ffi_enc_.value();")
lines.add(" auto ffi_raw_ = ffi_call_([&](FFICallback cb, void* ud) {")
lines.add(
" return $1(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());" %
" return $1_cbor(ptr_, cb, ud, ffi_req_bytes_.data(), ffi_req_bytes_.size());" %
[m.procName]
)
lines.add(" }, timeout_);")