@@ -63,10 +63,22 @@ static void erlfdb_future_cb(FDBFuture *fdb_future, void *data) {
6363 ErlNifEnv * caller ;
6464 ERL_NIF_TERM msg ;
6565
66- // FoundationDB callbacks can fire from the thread
67- // that created them. Check if we were actually
68- // submitted to the network thread or not so that
69- // we pass the correct environment to enif_send
66+ // FoundationDB callbacks can fire either:
67+ // 1. Synchronously from the calling thread (when the future is already
68+ // ready at the time fdb_future_set_callback is called), or
69+ // 2. Asynchronously from the FDB network thread
70+ //
71+ // We use enif_thread_type() to distinguish these cases:
72+ // - ERL_NIF_THR_UNDEFINED means we're on the FDB network thread (case 2)
73+ // - Any other value means we're on an Erlang scheduler thread (case 1)
74+ //
75+ // For enif_send, when called from a non-scheduler thread we must pass
76+ // NULL as the caller environment. When called synchronously from a NIF,
77+ // we can pass the process-bound environment (pid_env) for efficiency.
78+ //
79+ // IMPORTANT: pid_env is only valid during the NIF call that created
80+ // this future. This is safe here because synchronous callbacks only
81+ // occur during erlfdb_create_future, before that NIF returns.
7082 if (enif_thread_type () == ERL_NIF_THR_UNDEFINED ) {
7183 caller = NULL ;
7284 } else {
@@ -100,6 +112,11 @@ static ERL_NIF_TERM erlfdb_create_future(ErlNifEnv *env, ERL_NIF_TERM *tx_ref,
100112 fdb_error_t err ;
101113
102114 f = enif_alloc_resource (ErlFDBFutureRes , sizeof (ErlFDBFuture ));
115+ if (f == NULL ) {
116+ fdb_future_destroy (future );
117+ return enif_make_badarg (env );
118+ }
119+
103120 f -> future = future ;
104121 f -> ftype = ftype ;
105122 if (to == NULL ) {
@@ -109,13 +126,23 @@ static ERL_NIF_TERM erlfdb_create_future(ErlNifEnv *env, ERL_NIF_TERM *tx_ref,
109126 }
110127 f -> pid_env = env ;
111128 f -> msg_env = enif_alloc_env ();
129+ if (f -> msg_env == NULL ) {
130+ enif_release_resource (f );
131+ return enif_make_badarg (env );
132+ }
133+
112134 if (tx_ref != NULL ) {
113135 f -> msg_ref = T2 (f -> msg_env , enif_make_copy (f -> msg_env , * tx_ref ),
114136 enif_make_copy (f -> msg_env , ref ));
115137 } else {
116138 f -> msg_ref = enif_make_copy (f -> msg_env , ref );
117139 }
118140 f -> lock = enif_mutex_create ("fdb:future_lock" );
141+ if (f -> lock == NULL ) {
142+ enif_release_resource (f );
143+ return enif_make_badarg (env );
144+ }
145+
119146 f -> cancelled = false;
120147
121148 // This resource reference counting dance is a bit
@@ -591,9 +618,8 @@ static ERL_NIF_TERM erlfdb_network_set_option(ErlNifEnv *env, int argc,
591618 option = FDB_NET_OPTION_DISABLE_CLIENT_STATISTICS_LOGGING ;
592619 } else if (IS_ATOM (argv [0 ], enable_slow_task_profiling )) {
593620 option = FDB_NET_OPTION_ENABLE_SLOW_TASK_PROFILING ;
594- }
595621#if FDB_API_VERSION >= 630
596- else if (IS_ATOM (argv [0 ], enable_run_loop_profiling )) {
622+ } else if (IS_ATOM (argv [0 ], enable_run_loop_profiling )) {
597623 option = FDB_NET_OPTION_ENABLE_RUN_LOOP_PROFILING ;
598624 } else if (IS_ATOM (argv [0 ], client_threads_per_version )) {
599625 option = FDB_NET_OPTION_CLIENT_THREADS_PER_VERSION ;
@@ -602,9 +628,9 @@ static ERL_NIF_TERM erlfdb_network_set_option(ErlNifEnv *env, int argc,
602628#if FDB_API_VERSION >= 730
603629 option = FDB_NET_OPTION_IGNORE_EXTERNAL_CLIENT_FAILURES ;
604630#else
605- // 7.3 added some new checks for loading external client libraries
606- // and those checks are not present in the older versions
607- return ATOM_ok ;
631+ // 7.3 added some new checks for loading external client libraries
632+ // and those checks are not present in the older versions
633+ return ATOM_ok ;
608634#endif
609635 } else {
610636 return enif_make_badarg (env );
@@ -843,6 +869,11 @@ static ERL_NIF_TERM erlfdb_create_database(ErlNifEnv *env, int argc,
843869 }
844870
845871 d = enif_alloc_resource (ErlFDBDatabaseRes , sizeof (ErlFDBDatabase ));
872+ if (d == NULL ) {
873+ fdb_database_destroy (database );
874+ return enif_make_badarg (env );
875+ }
876+
846877 d -> database = database ;
847878
848879 ret = enif_make_resource (env , d );
@@ -890,6 +921,11 @@ static ERL_NIF_TERM erlfdb_database_open_tenant(ErlNifEnv *env, int argc,
890921 }
891922
892923 ten = enif_alloc_resource (ErlFDBTenantRes , sizeof (ErlFDBTenant ));
924+ if (ten == NULL ) {
925+ fdb_tenant_destroy (tenant );
926+ return enif_make_badarg (env );
927+ }
928+
893929 ten -> tenant = tenant ;
894930
895931 ret = enif_make_resource (env , ten );
@@ -995,6 +1031,11 @@ erlfdb_database_create_transaction(ErlNifEnv *env, int argc,
9951031 }
9961032
9971033 t = enif_alloc_resource (ErlFDBTransactionRes , sizeof (ErlFDBTransaction ));
1034+ if (t == NULL ) {
1035+ fdb_transaction_destroy (transaction );
1036+ return enif_make_badarg (env );
1037+ }
1038+
9981039 t -> transaction = transaction ;
9991040
10001041 enif_self (env , & pid );
@@ -1095,6 +1136,11 @@ erlfdb_tenant_create_transaction(ErlNifEnv *env, int argc,
10951136 }
10961137
10971138 t = enif_alloc_resource (ErlFDBTransactionRes , sizeof (ErlFDBTransaction ));
1139+ if (t == NULL ) {
1140+ fdb_transaction_destroy (transaction );
1141+ return enif_make_badarg (env );
1142+ }
1143+
10981144 t -> transaction = transaction ;
10991145
11001146 enif_self (env , & pid );
0 commit comments