This is an automated email from the ASF dual-hosted git repository.

nickva pushed a commit to tag 1.1.5
in repository https://gitbox.apache.org/repos/asf/couchdb-jiffy.git

commit e140b344a62653f9686d4772810da34bf6b0d5b1
Author: Nick Vatamaniuc <[email protected]>
AuthorDate: Fri Jun 12 18:00:05 2026 -0400

    Fix unitialized var access on allocation failure
    
    Fix two places where we didn't handle allocation failures. While
    `enif_alloc_resource()` blows up on allocation failure, `enif_alloc()` and
    `enif_alloc_binary()` don't. During encoder and decoder resource creation if
    small (a few KB) mallocs fail we could end up calling the resource 
destructor
    with some uninitalized flags like `have_buffer`.
    
    To prevent this class of errors in the future opt to memset the encoder and
    decoder structure so new fields in the future are by default 0-initialized.
    
    Thanks to @qzhuyan (William) in https://github.com/davisp/jiffy/pull/296 for
    pointing this issue out and providing a fix.
---
 c_src/decoder.c | 19 +++++++++----------
 c_src/encoder.c | 16 ++++------------
 2 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/c_src/decoder.c b/c_src/decoder.c
index 27d101a..01d0215 100644
--- a/c_src/decoder.c
+++ b/c_src/decoder.c
@@ -66,6 +66,7 @@ typedef struct {
     int             st_top;
 } Decoder;
 
+// Returns an allocated resource or NULL on allocation failure
 Decoder*
 dec_new(ErlNifEnv* env)
 {
@@ -77,23 +78,21 @@ dec_new(ErlNifEnv* env)
         return NULL;
     }
 
-    d->atoms = st;
+    // Zero everything and only set non-0 fields
+    memset(d, 0, sizeof(*d));
 
+    d->atoms = st;
     d->bytes_per_red = DEFAULT_BYTES_PER_REDUCTION;
-    d->is_partial = 0;
-    d->return_maps = 0;
-    d->return_trailer = 0;
-    d->dedupe_keys = 0;
-    d->copy_strings = 0;
     d->null_term = d->atoms->atom_null;
-
-    d->p = NULL;
     d->len = -1;
-    d->i = 0;
 
     d->st_data = (char*) enif_alloc(STACK_SIZE_INC);
+    if(d->st_data == NULL) {
+        enif_release_resource(d);
+        return NULL;
+    }
+
     d->st_size = STACK_SIZE_INC;
-    d->st_top = 0;
 
     for(i = 0; i < d->st_size; i++) {
         d->st_data[i] = st_invalid;
diff --git a/c_src/encoder.c b/c_src/encoder.c
index 03c5500..2ec0dd8 100644
--- a/c_src/encoder.c
+++ b/c_src/encoder.c
@@ -72,29 +72,21 @@ enc_new(ErlNifEnv* env)
     jiffy_st* st = (jiffy_st*) enif_priv_data(env);
     Encoder* e = enif_alloc_resource(st->res_enc, sizeof(Encoder));
 
+    // Zero everything so enc_destroy() never sees an uninitialized
+    // have_buffer if we bail out before the encoder is fully built
+    memset(e, 0, sizeof(*e));
+
     e->atoms = st;
     e->bytes_per_red = DEFAULT_BYTES_PER_REDUCTION;
-    e->uescape = 0;
-    e->pretty = 0;
-    e->use_nil = 0;
-    e->escape_forward_slashes = 0;
-    e->shiftcnt = 0;
-    e->count = 0;
-
-    e->iosize = 0;
     e->iolist = enif_make_list(env, 0);
 
-    e->partial_output = 0;
-
     if(!enif_alloc_binary(BIN_INC_SIZE, &e->buffer)) {
         enif_release_resource(e);
         return NULL;
     }
 
     e->have_buffer = 1;
-
     e->p = e->buffer.data;
-    e->i = 0;
 
     return e;
 }

Reply via email to