Skip to content

Commit c022af6

Browse files
authored
Merge pull request #29 from benoitc/fix/memory-and-todos
Fix memory leaks and TODOs in C source
2 parents 4bc706c + f6a84a1 commit c022af6

File tree

4 files changed

+30
-57
lines changed

4 files changed

+30
-57
lines changed

c_src/py_convert.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ static inline bool is_numpy_ndarray(PyObject *obj) {
141141
*
142142
* @see term_to_py() for the reverse conversion
143143
*/
144-
static ERL_NIF_TERM py_to_term(ErlNifEnv *env, PyObject *obj) {
144+
ERL_NIF_TERM py_to_term(ErlNifEnv *env, PyObject *obj) {
145145
/*
146146
* Type check ordering optimized for web/ASGI workloads:
147147
* 1. Strings (most common in HTTP headers, bodies, JSON)

c_src/py_event_loop.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2774,9 +2774,10 @@ bool event_loop_add_pending(erlang_event_loop_t *loop, event_type_t type,
27742774
loop->pending_capacity = new_capacity;
27752775
/* Note: Linked list doesn't need realloc, just the capacity limit */
27762776
} else {
2777-
/* At hard cap - log warning but don't drop silently */
2778-
/* TODO: Add proper logging mechanism */
2779-
return false; /* Queue at maximum capacity */
2777+
/* At hard cap - warn and reject */
2778+
fprintf(stderr, "event_loop_add_pending: queue at maximum capacity (%zu), rejecting event\n",
2779+
(size_t)MAX_PENDING_CAPACITY);
2780+
return false;
27802781
}
27812782
}
27822783

c_src/py_nif.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1403,7 +1403,7 @@ extern ERL_NIF_TERM ATOM_SPAN_EVENT; /**< @brief `span_event` atom */
14031403
* @note Does not consume a reference to obj
14041404
* @note May return ATOM_ERROR on allocation failure
14051405
*/
1406-
static ERL_NIF_TERM py_to_term(ErlNifEnv *env, PyObject *obj);
1406+
extern ERL_NIF_TERM py_to_term(ErlNifEnv *env, PyObject *obj);
14071407

14081408
/**
14091409
* @brief Convert an Erlang term to a Python object

c_src/py_subinterp_thread.c

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525

2626
#include "py_subinterp_thread.h"
27+
#include "py_nif.h"
2728
#include <string.h>
2829
#include <unistd.h>
2930
#include <fcntl.h>
@@ -429,6 +430,15 @@ static void *worker_thread_main(void *arg) {
429430
PyObject *result = NULL;
430431
PyObject *globals = ns ? ns->globals : PyDict_New();
431432
PyObject *locals = ns ? ns->locals : PyDict_New();
433+
bool owns_globals = (ns == NULL);
434+
bool owns_locals = (ns == NULL);
435+
436+
/* Check allocation if we own the dicts */
437+
if ((owns_globals && globals == NULL) || (owns_locals && locals == NULL)) {
438+
if (owns_globals) Py_XDECREF(globals);
439+
if (owns_locals) Py_XDECREF(locals);
440+
break;
441+
}
432442

433443
switch (header.req_type) {
434444
case REQ_CALL:
@@ -447,6 +457,8 @@ static void *worker_thread_main(void *arg) {
447457
} else if (enif_get_atom(tmp_env, elements[0], mod_str, 256, ERL_NIF_LATIN1)) {
448458
/* Already filled */
449459
} else {
460+
if (owns_globals) Py_DECREF(globals);
461+
if (owns_locals) Py_DECREF(locals);
450462
break;
451463
}
452464

@@ -458,6 +470,8 @@ static void *worker_thread_main(void *arg) {
458470
} else if (enif_get_atom(tmp_env, elements[1], func_str, 256, ERL_NIF_LATIN1)) {
459471
/* Already filled */
460472
} else {
473+
if (owns_globals) Py_DECREF(globals);
474+
if (owns_locals) Py_DECREF(locals);
461475
break;
462476
}
463477

@@ -481,6 +495,8 @@ static void *worker_thread_main(void *arg) {
481495

482496
if (module == NULL) {
483497
PyErr_Clear();
498+
if (owns_globals) Py_DECREF(globals);
499+
if (owns_locals) Py_DECREF(locals);
484500
break;
485501
}
486502

@@ -490,6 +506,8 @@ static void *worker_thread_main(void *arg) {
490506

491507
if (func == NULL) {
492508
PyErr_Clear();
509+
if (owns_globals) Py_DECREF(globals);
510+
if (owns_locals) Py_DECREF(locals);
493511
break;
494512
}
495513

@@ -592,59 +610,13 @@ static void *worker_thread_main(void *arg) {
592610
break;
593611
}
594612

595-
/* Serialize result */
613+
/* Clean up owned dicts after switch completes */
614+
if (owns_globals) Py_DECREF(globals);
615+
if (owns_locals) Py_DECREF(locals);
616+
617+
/* Serialize result using py_to_term for full type support */
596618
if (success && result != NULL) {
597-
/* For now, just return ok atom */
598-
/* TODO: Proper py_to_term conversion and ETF serialization */
599-
ERL_NIF_TERM result_term;
600-
if (result == Py_None) {
601-
result_term = enif_make_atom(tmp_env, "none");
602-
} else if (PyLong_Check(result)) {
603-
long val = PyLong_AsLong(result);
604-
result_term = enif_make_long(tmp_env, val);
605-
} else if (PyFloat_Check(result)) {
606-
double val = PyFloat_AsDouble(result);
607-
result_term = enif_make_double(tmp_env, val);
608-
} else if (PyUnicode_Check(result)) {
609-
Py_ssize_t size;
610-
const char *str = PyUnicode_AsUTF8AndSize(result, &size);
611-
if (str) {
612-
ErlNifBinary bin;
613-
if (enif_alloc_binary(size, &bin)) {
614-
memcpy(bin.data, str, size);
615-
result_term = enif_make_binary(tmp_env, &bin);
616-
} else {
617-
result_term = enif_make_atom(tmp_env, "conversion_error");
618-
}
619-
} else {
620-
result_term = enif_make_atom(tmp_env, "conversion_error");
621-
}
622-
} else if (PyBool_Check(result)) {
623-
result_term = result == Py_True ?
624-
enif_make_atom(tmp_env, "true") :
625-
enif_make_atom(tmp_env, "false");
626-
} else {
627-
/* Fallback: convert to string representation */
628-
PyObject *str = PyObject_Str(result);
629-
if (str) {
630-
Py_ssize_t size;
631-
const char *s = PyUnicode_AsUTF8AndSize(str, &size);
632-
if (s) {
633-
ErlNifBinary bin;
634-
if (enif_alloc_binary(size, &bin)) {
635-
memcpy(bin.data, s, size);
636-
result_term = enif_make_binary(tmp_env, &bin);
637-
} else {
638-
result_term = enif_make_atom(tmp_env, "conversion_error");
639-
}
640-
} else {
641-
result_term = enif_make_atom(tmp_env, "conversion_error");
642-
}
643-
Py_DECREF(str);
644-
} else {
645-
result_term = enif_make_atom(tmp_env, "pyobject");
646-
}
647-
}
619+
ERL_NIF_TERM result_term = py_to_term(tmp_env, result);
648620
Py_XDECREF(result);
649621

650622
/* Wrap in {ok, Result} */

0 commit comments

Comments
 (0)