Skip to content

Commit 9932e51

Browse files
committed
fix(imc): add parameter validation to all IMC API thunks
Add consistent null/invalid checks at the BML_API_* boundary layer for all ~30 IMC thunk functions, matching ConfigApi/TimerApi patterns. Validation rules: - Handles (Subscription, Future, RpcStream): INVALID_HANDLE - TopicId/RpcId == *_ID_INVALID: INVALID_ARGUMENT - Handler/callback null: INVALID_ARGUMENT - Out pointer null: INVALID_ARGUMENT - Data+size mismatch: INVALID_ARGUMENT - owner (BML_Mod): not validated (resolved internally)
1 parent 918c0cb commit 9932e51

2 files changed

Lines changed: 141 additions & 31 deletions

File tree

src/Core/ImcBusApi.cpp

Lines changed: 93 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,119 +4,181 @@
44

55
namespace BML::Core {
66
namespace {
7+
// -- Pub/Sub ----------------------------------------------------------
8+
79
BML_Result BML_API_ImcPublish(BML_Mod owner, BML_TopicId t,
810
const void *d, size_t s) {
11+
if (t == BML_TOPIC_ID_INVALID) return BML_RESULT_INVALID_ARGUMENT;
12+
if (s > 0 && !d) return BML_RESULT_INVALID_ARGUMENT;
913
return ImcPublish(owner, t, d, s);
1014
}
1115
BML_Result BML_API_ImcPublishEx(BML_Mod owner, BML_TopicId t,
1216
const BML_ImcMessage *m) {
17+
if (t == BML_TOPIC_ID_INVALID || !m) return BML_RESULT_INVALID_ARGUMENT;
1318
return ImcPublishEx(owner, t, m);
1419
}
1520
BML_Result BML_API_ImcPublishBuffer(BML_Mod owner, BML_TopicId t,
1621
const BML_ImcBuffer *b) {
22+
if (t == BML_TOPIC_ID_INVALID || !b) return BML_RESULT_INVALID_ARGUMENT;
1723
return ImcPublishBuffer(owner, t, b);
1824
}
1925
BML_Result BML_API_ImcPublishMulti(BML_Mod owner, const BML_TopicId *ts,
2026
size_t n, const void *d, size_t s,
2127
const BML_ImcMessage *m, size_t *o) {
28+
if (!ts || n == 0) return BML_RESULT_INVALID_ARGUMENT;
29+
if (s > 0 && !d) return BML_RESULT_INVALID_ARGUMENT;
2230
return ImcPublishMulti(owner, ts, n, d, s, m, o);
2331
}
2432
BML_Result BML_API_ImcSubscribe(BML_Mod owner, BML_TopicId t, BML_ImcHandler h,
2533
void *u, BML_Subscription *o) {
34+
if (t == BML_TOPIC_ID_INVALID || !h || !o) return BML_RESULT_INVALID_ARGUMENT;
2635
return ImcSubscribe(owner, t, h, u, o);
2736
}
2837
BML_Result BML_API_ImcSubscribeEx(BML_Mod owner, BML_TopicId t, BML_ImcHandler h,
2938
void *u, const BML_SubscribeOptions *opts,
3039
BML_Subscription *o) {
40+
if (t == BML_TOPIC_ID_INVALID || !h || !o) return BML_RESULT_INVALID_ARGUMENT;
3141
return ImcSubscribeEx(owner, t, h, u, opts, o);
3242
}
33-
BML_Result BML_API_ImcUnsubscribe(BML_Subscription s) { return ImcUnsubscribe(s); }
43+
BML_Result BML_API_ImcUnsubscribe(BML_Subscription s) {
44+
if (!s) return BML_RESULT_INVALID_HANDLE;
45+
return ImcUnsubscribe(s);
46+
}
3447
BML_Result BML_API_ImcSubscriptionIsActive(BML_Subscription s, BML_Bool *o) {
48+
if (!s) return BML_RESULT_INVALID_HANDLE;
49+
if (!o) return BML_RESULT_INVALID_ARGUMENT;
3550
return ImcSubscriptionIsActive(s, o);
3651
}
3752
BML_Result BML_API_ImcSubscribeIntercept(BML_Mod owner, BML_TopicId t,
3853
BML_ImcInterceptHandler h, void *u,
3954
BML_Subscription *o) {
55+
if (t == BML_TOPIC_ID_INVALID || !h || !o) return BML_RESULT_INVALID_ARGUMENT;
4056
return ImcSubscribeIntercept(owner, t, h, u, o);
4157
}
4258
BML_Result BML_API_ImcSubscribeInterceptEx(BML_Mod owner, BML_TopicId t,
4359
BML_ImcInterceptHandler h, void *u,
4460
const BML_SubscribeOptions *opts,
4561
BML_Subscription *o) {
62+
if (t == BML_TOPIC_ID_INVALID || !h || !o) return BML_RESULT_INVALID_ARGUMENT;
4663
return ImcSubscribeInterceptEx(owner, t, h, u, opts, o);
4764
}
4865
BML_Result BML_API_ImcPublishInterceptable(BML_Mod owner, BML_TopicId t,
4966
BML_ImcMessage *m, BML_EventResult *o) {
67+
if (t == BML_TOPIC_ID_INVALID || !m) return BML_RESULT_INVALID_ARGUMENT;
5068
return ImcPublishInterceptable(owner, t, m, o);
5169
}
70+
BML_Result BML_API_ImcPublishState(BML_Mod owner, BML_TopicId t,
71+
const BML_ImcMessage *m) {
72+
if (t == BML_TOPIC_ID_INVALID || !m) return BML_RESULT_INVALID_ARGUMENT;
73+
return ImcPublishState(owner, t, m);
74+
}
75+
BML_Result BML_API_ImcGetSubscriptionStats(BML_Subscription s, BML_SubscriptionStats *o) {
76+
if (!s) return BML_RESULT_INVALID_HANDLE;
77+
if (!o) return BML_RESULT_INVALID_ARGUMENT;
78+
return ImcGetSubscriptionStats(s, o);
79+
}
80+
81+
// -- RPC --------------------------------------------------------------
82+
5283
BML_Result BML_API_ImcRegisterRpc(BML_Mod owner, BML_RpcId r, BML_RpcHandler h,
5384
void *u) {
85+
if (r == BML_RPC_ID_INVALID || !h) return BML_RESULT_INVALID_ARGUMENT;
5486
return ImcRegisterRpc(owner, r, h, u);
5587
}
5688
BML_Result BML_API_ImcUnregisterRpc(BML_Mod owner, BML_RpcId r) {
89+
if (r == BML_RPC_ID_INVALID) return BML_RESULT_INVALID_ARGUMENT;
5790
return ImcUnregisterRpc(owner, r);
5891
}
5992
BML_Result BML_API_ImcCallRpc(BML_Mod owner, BML_RpcId r,
6093
const BML_ImcMessage *req, BML_Future *o) {
94+
if (r == BML_RPC_ID_INVALID || !o) return BML_RESULT_INVALID_ARGUMENT;
6195
return ImcCallRpc(owner, r, req, o);
6296
}
63-
BML_Result BML_API_ImcFutureAwait(BML_Future f, uint32_t t) { return ImcFutureAwait(f, t); }
64-
BML_Result BML_API_ImcFutureGetResult(BML_Future f, BML_ImcMessage *o) {
65-
return ImcFutureGetResult(f, o);
66-
}
67-
BML_Result BML_API_ImcFutureGetState(BML_Future f, BML_FutureState *o) {
68-
return ImcFutureGetState(f, o);
69-
}
70-
BML_Result BML_API_ImcFutureCancel(BML_Future f) { return ImcFutureCancel(f); }
71-
BML_Result BML_API_ImcFutureOnComplete(BML_Mod owner, BML_Future f,
72-
BML_FutureCallback cb, void *u) {
73-
return ImcFutureOnComplete(owner, f, cb, u);
74-
}
75-
BML_Result BML_API_ImcFutureRelease(BML_Future f) { return ImcFutureRelease(f); }
76-
BML_Result BML_API_ImcGetSubscriptionStats(BML_Subscription s, BML_SubscriptionStats *o) {
77-
return ImcGetSubscriptionStats(s, o);
78-
}
79-
BML_Result BML_API_ImcPublishState(BML_Mod owner, BML_TopicId t,
80-
const BML_ImcMessage *m) {
81-
return ImcPublishState(owner, t, m);
82-
}
8397
BML_Result BML_API_ImcRegisterRpcEx(BML_Mod owner, BML_RpcId r,
8498
BML_RpcHandlerEx h, void *u) {
99+
if (r == BML_RPC_ID_INVALID || !h) return BML_RESULT_INVALID_ARGUMENT;
85100
return ImcRegisterRpcEx(owner, r, h, u);
86101
}
87102
BML_Result BML_API_ImcCallRpcEx(BML_Mod owner, BML_RpcId r,
88103
const BML_ImcMessage *req,
89104
const BML_RpcCallOptions *opts, BML_Future *o) {
105+
if (r == BML_RPC_ID_INVALID || !o) return BML_RESULT_INVALID_ARGUMENT;
90106
return ImcCallRpcEx(owner, r, req, opts, o);
91107
}
92-
BML_Result BML_API_ImcFutureGetError(BML_Future f, BML_Result *c, char *m, size_t cap,
93-
size_t *ol) {
94-
return ImcFutureGetError(f, c, m, cap, ol);
95-
}
96108
BML_Result BML_API_ImcAddRpcMiddleware(BML_Mod owner, BML_RpcMiddleware mw,
97109
int32_t p, void *u) {
110+
if (!mw) return BML_RESULT_INVALID_ARGUMENT;
98111
return ImcAddRpcMiddleware(owner, mw, p, u);
99112
}
100113
BML_Result BML_API_ImcRemoveRpcMiddleware(BML_Mod owner, BML_RpcMiddleware mw) {
114+
if (!mw) return BML_RESULT_INVALID_ARGUMENT;
101115
return ImcRemoveRpcMiddleware(owner, mw);
102116
}
103117
BML_Result BML_API_ImcRegisterStreamingRpc(BML_Mod owner, BML_RpcId r,
104118
BML_StreamingRpcHandler h, void *u) {
119+
if (r == BML_RPC_ID_INVALID || !h) return BML_RESULT_INVALID_ARGUMENT;
105120
return ImcRegisterStreamingRpc(owner, r, h, u);
106121
}
122+
BML_Result BML_API_ImcCallStreamingRpc(BML_Mod owner, BML_RpcId r,
123+
const BML_ImcMessage *req,
124+
BML_ImcHandler oc, BML_FutureCallback od,
125+
void *u, BML_Future *o) {
126+
if (r == BML_RPC_ID_INVALID || !o) return BML_RESULT_INVALID_ARGUMENT;
127+
return ImcCallStreamingRpc(owner, r, req, oc, od, u, o);
128+
}
129+
130+
// -- Stream -----------------------------------------------------------
131+
107132
BML_Result BML_API_ImcStreamPush(BML_RpcStream s, const void *d, size_t sz) {
133+
if (!s) return BML_RESULT_INVALID_HANDLE;
134+
if (sz > 0 && !d) return BML_RESULT_INVALID_ARGUMENT;
108135
return ImcStreamPush(s, d, sz);
109136
}
110-
BML_Result BML_API_ImcStreamComplete(BML_RpcStream s) { return ImcStreamComplete(s); }
137+
BML_Result BML_API_ImcStreamComplete(BML_RpcStream s) {
138+
if (!s) return BML_RESULT_INVALID_HANDLE;
139+
return ImcStreamComplete(s);
140+
}
111141
BML_Result BML_API_ImcStreamError(BML_RpcStream s, BML_Result e, const char *m) {
142+
if (!s) return BML_RESULT_INVALID_HANDLE;
112143
return ImcStreamError(s, e, m);
113144
}
114-
BML_Result BML_API_ImcCallStreamingRpc(BML_Mod owner, BML_RpcId r,
115-
const BML_ImcMessage *req,
116-
BML_ImcHandler oc, BML_FutureCallback od,
117-
void *u, BML_Future *o) {
118-
return ImcCallStreamingRpc(owner, r, req, oc, od, u, o);
145+
146+
// -- Future -----------------------------------------------------------
147+
148+
BML_Result BML_API_ImcFutureAwait(BML_Future f, uint32_t t) {
149+
if (!f) return BML_RESULT_INVALID_HANDLE;
150+
return ImcFutureAwait(f, t);
151+
}
152+
BML_Result BML_API_ImcFutureGetResult(BML_Future f, BML_ImcMessage *o) {
153+
if (!f) return BML_RESULT_INVALID_HANDLE;
154+
if (!o) return BML_RESULT_INVALID_ARGUMENT;
155+
return ImcFutureGetResult(f, o);
156+
}
157+
BML_Result BML_API_ImcFutureGetState(BML_Future f, BML_FutureState *o) {
158+
if (!f) return BML_RESULT_INVALID_HANDLE;
159+
if (!o) return BML_RESULT_INVALID_ARGUMENT;
160+
return ImcFutureGetState(f, o);
161+
}
162+
BML_Result BML_API_ImcFutureCancel(BML_Future f) {
163+
if (!f) return BML_RESULT_INVALID_HANDLE;
164+
return ImcFutureCancel(f);
165+
}
166+
BML_Result BML_API_ImcFutureOnComplete(BML_Mod owner, BML_Future f,
167+
BML_FutureCallback cb, void *u) {
168+
if (!f) return BML_RESULT_INVALID_HANDLE;
169+
if (!cb) return BML_RESULT_INVALID_ARGUMENT;
170+
return ImcFutureOnComplete(owner, f, cb, u);
171+
}
172+
BML_Result BML_API_ImcFutureRelease(BML_Future f) {
173+
if (!f) return BML_RESULT_INVALID_HANDLE;
174+
return ImcFutureRelease(f);
175+
}
176+
BML_Result BML_API_ImcFutureGetError(BML_Future f, BML_Result *c, char *m, size_t cap,
177+
size_t *ol) {
178+
if (!f) return BML_RESULT_INVALID_HANDLE;
179+
return ImcFutureGetError(f, c, m, cap, ol);
119180
}
181+
120182
} // namespace
121183

122184
void RegisterImcApis(ApiRegistry &apiRegistry) {

tests/CoreApisTests.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,14 @@ void OrderingHandler(BML_Context ctx,
342342
capture->values.push_back(value);
343343
}
344344

345+
BML_Result StreamingErrorHandler(BML_Context,
346+
BML_RpcId,
347+
const BML_ImcMessage *,
348+
BML_RpcStream stream,
349+
void *) {
350+
return BML::Core::ImcStreamError(stream, BML_RESULT_FAIL, "stream error");
351+
}
352+
345353
TEST_F(CoreApisTests, ImcBroadcastPreservesPublishOrderPerSubscriber) {
346354
auto owner = CreateTrackedMod("coreapis.imc.order");
347355
ASSERT_NE(owner, nullptr);
@@ -382,6 +390,46 @@ TEST_F(CoreApisTests, ImcBroadcastPreservesPublishOrderPerSubscriber) {
382390
Context::SetLifecycleModule(nullptr);
383391
}
384392

393+
TEST_F(CoreApisTests, ImcCallStreamingRpcExportAllowsNullChunkHandler) {
394+
BML::Core::RegisterImcApis(*kernel_->api_registry);
395+
396+
auto call_streaming_rpc =
397+
reinterpret_cast<PFN_BML_ImcCallStreamingRpc>(
398+
kernel_->api_registry->Get("bmlImcCallStreamingRpc"));
399+
ASSERT_NE(call_streaming_rpc, nullptr);
400+
401+
auto owner = CreateTrackedMod("coreapis.imc.streaming");
402+
ASSERT_NE(owner, nullptr);
403+
Context::SetLifecycleModule(owner);
404+
405+
BML_RpcId rpc_id = BML_RPC_ID_INVALID;
406+
ASSERT_EQ(BML_RESULT_OK,
407+
ImcGetRpcId(*kernel_, "coreapis.imc.streaming", &rpc_id));
408+
ASSERT_EQ(BML_RESULT_OK,
409+
ImcRegisterStreamingRpc(owner, rpc_id, StreamingErrorHandler, nullptr));
410+
411+
BML_Future future = nullptr;
412+
EXPECT_EQ(BML_RESULT_OK,
413+
call_streaming_rpc(owner, rpc_id, nullptr, nullptr, nullptr,
414+
nullptr, &future));
415+
ASSERT_NE(future, nullptr);
416+
417+
BML_FutureState state = BML_FUTURE_PENDING;
418+
ASSERT_EQ(BML_RESULT_OK, ImcFutureGetState(future, &state));
419+
EXPECT_EQ(BML_FUTURE_FAILED, state);
420+
421+
BML_Result code = BML_RESULT_OK;
422+
char message[64] = {};
423+
ASSERT_EQ(BML_RESULT_OK,
424+
ImcFutureGetError(future, &code, message, sizeof(message), nullptr));
425+
EXPECT_EQ(BML_RESULT_FAIL, code);
426+
EXPECT_STREQ("stream error", message);
427+
428+
EXPECT_EQ(BML_RESULT_OK, ImcFutureRelease(future));
429+
EXPECT_EQ(BML_RESULT_OK, ImcUnregisterRpc(owner, rpc_id));
430+
Context::SetLifecycleModule(nullptr);
431+
}
432+
385433
TEST_F(CoreApisTests, CurrentModuleApisAreAbsentFromTheRegistry) {
386434
BML::Core::RegisterCoreApis(*kernel_->api_registry);
387435

0 commit comments

Comments
 (0)