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

mtaha pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/age.git


The following commit(s) were added to refs/heads/master by this push:
     new 0ea94644 Fix possible memory and file descriptors leaks (#2258)
0ea94644 is described below

commit 0ea94644f25bdc08c803ff6521bfd412a6690401
Author: Aleksey Konovkin <[email protected]>
AuthorDate: Tue Dec 9 22:49:05 2025 +0300

    Fix possible memory and file descriptors leaks (#2258)
    
    - Used postgres memory allocation functions instead of standard ones.
    - Wrapped main loop of csv loader in PG_TRY block for better error handling.
---
 src/backend/utils/adt/age_global_graph.c |   6 +-
 src/backend/utils/adt/agtype.c           |  39 ++++++-----
 src/backend/utils/load/ag_load_edges.c   |  91 +++++++++++++-----------
 src/backend/utils/load/ag_load_labels.c  | 115 +++++++++++++++++--------------
 src/include/utils/agtype.h               |   1 +
 5 files changed, 135 insertions(+), 117 deletions(-)

diff --git a/src/backend/utils/adt/age_global_graph.c 
b/src/backend/utils/adt/age_global_graph.c
index 6f30060a..c34e51ee 100644
--- a/src/backend/utils/adt/age_global_graph.c
+++ b/src/backend/utils/adt/age_global_graph.c
@@ -1237,12 +1237,10 @@ Datum age_delete_global_graphs(PG_FUNCTION_ARGS)
     {
         char *graph_name = NULL;
 
-        graph_name = strndup(agtv_temp->val.string.val,
-                             agtv_temp->val.string.len);
+        graph_name = pnstrdup(agtv_temp->val.string.val,
+                              agtv_temp->val.string.len);
 
         success = delete_specific_GRAPH_global_contexts(graph_name);
-
-        free(graph_name);
     }
     else
     {
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index be838cbd..02fc3221 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -181,6 +181,17 @@ static agtype_value 
*agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo);
 agtype_value *agtype_composite_to_agtype_value_binary(agtype *a);
 static agtype_value *tostring_helper(Datum arg, Oid type, char *msghdr);
 
+
+void *repalloc_check(void *ptr, size_t len)
+{
+   if (ptr != NULL)
+   {
+       return repalloc(ptr, len);
+   }
+
+   return palloc(len);
+}
+
 /*
  * Due to how pfree can be implemented, it may not check for a passed NULL. 
This
  * wrapper does just that, it will only call pfree is the pointer passed is not
@@ -5580,7 +5591,7 @@ static char *get_label_name(const char *graph_name, 
graphid element_graphid)
     result = NameStr(*DatumGetName(heap_getattr(tuple, Anum_ag_label_name,
                                                 tupdesc, &column_is_null)));
     /* duplicate it */
-    result = strdup(result);
+    result = pstrdup(result);
 
     /* end the scan and close the relation */
     systable_endscan(scan_desc);
@@ -5673,8 +5684,8 @@ Datum age_startnode(PG_FUNCTION_ARGS)
     Assert(AGT_ROOT_IS_SCALAR(agt_arg));
     agtv_object = get_ith_agtype_value_from_container(&agt_arg->root, 0);
     Assert(agtv_object->type == AGTV_STRING);
-    graph_name = strndup(agtv_object->val.string.val,
-                         agtv_object->val.string.len);
+    graph_name = pnstrdup(agtv_object->val.string.val,
+                          agtv_object->val.string.len);
 
     /* get the edge */
     agt_arg = AG_GET_ARG_AGTYPE_P(1);
@@ -5708,8 +5719,6 @@ Datum age_startnode(PG_FUNCTION_ARGS)
 
     result = get_vertex(graph_name, label_name, start_id);
 
-    free(label_name);
-
     return result;
 }
 
@@ -5738,8 +5747,8 @@ Datum age_endnode(PG_FUNCTION_ARGS)
     Assert(AGT_ROOT_IS_SCALAR(agt_arg));
     agtv_object = get_ith_agtype_value_from_container(&agt_arg->root, 0);
     Assert(agtv_object->type == AGTV_STRING);
-    graph_name = strndup(agtv_object->val.string.val,
-                         agtv_object->val.string.len);
+    graph_name = pnstrdup(agtv_object->val.string.val,
+                          agtv_object->val.string.len);
 
     /* get the edge */
     agt_arg = AG_GET_ARG_AGTYPE_P(1);
@@ -5773,8 +5782,6 @@ Datum age_endnode(PG_FUNCTION_ARGS)
 
     result = get_vertex(graph_name, label_name, end_id);
 
-    free(label_name);
-
     return result;
 }
 
@@ -6401,11 +6408,10 @@ Datum age_tofloat(PG_FUNCTION_ARGS)
                 NumericGetDatum(agtv_value->val.numeric)));
         else if (agtv_value->type == AGTV_STRING)
         {
-            string = strndup(agtv_value->val.string.val,
-                             agtv_value->val.string.len);
+            string = pnstrdup(agtv_value->val.string.val,
+                              agtv_value->val.string.len);
             result = float8in_internal_null(string, NULL, "double precision",
                                             string, &is_valid);
-            free(string);
             if (!is_valid)
                 PG_RETURN_NULL();
         }
@@ -6703,8 +6709,8 @@ Datum age_tointeger(PG_FUNCTION_ARGS)
         {
             char *endptr;
             /* we need a null terminated cstring */
-            string = strndup(agtv_value->val.string.val,
-                             agtv_value->val.string.len);
+            string = pnstrdup(agtv_value->val.string.val,
+                              agtv_value->val.string.len);
             /* convert it if it is a regular integer string */
             result = strtoi64(string, &endptr, 10);
 
@@ -6718,7 +6724,6 @@ Datum age_tointeger(PG_FUNCTION_ARGS)
 
                 f = float8in_internal_null(string, NULL, "double precision",
                                            string, &is_valid);
-                free(string);
                 /*
                  * If the conversions failed or it's a special float value,
                  * return null.
@@ -6731,10 +6736,6 @@ Datum age_tointeger(PG_FUNCTION_ARGS)
 
                 result = (int64) f;
             }
-            else
-            {
-                free(string);
-            }
         }
         else
         {
diff --git a/src/backend/utils/load/ag_load_edges.c 
b/src/backend/utils/load/ag_load_edges.c
index 67049431..931c6e0d 100644
--- a/src/backend/utils/load/ag_load_edges.c
+++ b/src/backend/utils/load/ag_load_edges.c
@@ -36,8 +36,8 @@ void edge_field_cb(void *field, size_t field_len, void *data)
     if (cr->cur_field == cr->alloc)
     {
         cr->alloc *= 2;
-        cr->fields = realloc(cr->fields, sizeof(char *) * cr->alloc);
-        cr->fields_len = realloc(cr->header, sizeof(size_t *) * cr->alloc);
+        cr->fields = repalloc_check(cr->fields, sizeof(char *) * cr->alloc);
+        cr->fields_len = repalloc_check(cr->header, sizeof(size_t *) * 
cr->alloc);
         if (cr->fields == NULL)
         {
             cr->error = 1;
@@ -48,7 +48,7 @@ void edge_field_cb(void *field, size_t field_len, void *data)
     }
     cr->fields_len[cr->cur_field] = field_len;
     cr->curr_row_length += field_len;
-    cr->fields[cr->cur_field] = strndup((char*)field, field_len);
+    cr->fields[cr->cur_field] = pnstrdup((char*)field, field_len);
     cr->cur_field += 1;
 }
 
@@ -78,13 +78,13 @@ void edge_row_cb(int delim __attribute__((unused)), void 
*data)
     {
         cr->header_num = cr->cur_field;
         cr->header_row_length = cr->curr_row_length;
-        cr->header_len = (size_t* )malloc(sizeof(size_t *) * cr->cur_field);
-        cr->header = malloc((sizeof (char*) * cr->cur_field));
+        cr->header_len = (size_t* )palloc(sizeof(size_t *) * cr->cur_field);
+        cr->header = palloc((sizeof (char*) * cr->cur_field));
 
         for (i = 0; i<cr->cur_field; i++)
         {
             cr->header_len[i] = cr->fields_len[i];
-            cr->header[i] = strndup(cr->fields[i], cr->header_len[i]);
+            cr->header[i] = pnstrdup(cr->fields[i], cr->header_len[i]);
         }
     }
     else
@@ -133,7 +133,7 @@ void edge_row_cb(int delim __attribute__((unused)), void 
*data)
 
     for (i = 0; i < n_fields; ++i)
     {
-        free(cr->fields[i]);
+        pfree_if_not_null(cr->fields[i]);
     }
 
     if (cr->error)
@@ -192,6 +192,10 @@ int create_edges_from_csv_file(char *file_path,
                 (errmsg("Failed to initialize csv parser\n")));
     }
 
+    p.malloc_func = palloc;
+    p.realloc_func = repalloc_check;
+    p.free_func = pfree_if_not_null;
+
     csv_set_space_func(&p, is_space);
     csv_set_term_func(&p, is_term);
 
@@ -202,47 +206,52 @@ int create_edges_from_csv_file(char *file_path,
                 (errmsg("Failed to open %s\n", file_path)));
     }
 
-    label_seq_name = get_label_seq_relation_name(label_name);
-
-    memset((void*)&cr, 0, sizeof(csv_edge_reader));
-    cr.alloc = 128;
-    cr.fields = malloc(sizeof(char *) * cr.alloc);
-    cr.fields_len = malloc(sizeof(size_t *) * cr.alloc);
-    cr.header_row_length = 0;
-    cr.curr_row_length = 0;
-    cr.graph_name = graph_name;
-    cr.graph_oid = graph_oid;
-    cr.label_name = label_name;
-    cr.label_id = label_id;
-    cr.label_seq_relid = get_relname_relid(label_seq_name, graph_oid);
-    cr.load_as_agtype = load_as_agtype;
-
-    /* Initialize the batch insert state */
-    init_batch_insert(&cr.batch_state, label_name, graph_oid);
-
-    while ((bytes_read=fread(buf, 1, 1024, fp)) > 0)
+    PG_TRY();
     {
-        if (csv_parse(&p, buf, bytes_read, edge_field_cb,
-                      edge_row_cb, &cr) != bytes_read)
+        label_seq_name = get_label_seq_relation_name(label_name);
+
+        memset((void*)&cr, 0, sizeof(csv_edge_reader));
+        cr.alloc = 128;
+        cr.fields = palloc(sizeof(char *) * cr.alloc);
+        cr.fields_len = palloc(sizeof(size_t *) * cr.alloc);
+        cr.header_row_length = 0;
+        cr.curr_row_length = 0;
+        cr.graph_name = graph_name;
+        cr.graph_oid = graph_oid;
+        cr.label_name = label_name;
+        cr.label_id = label_id;
+        cr.label_seq_relid = get_relname_relid(label_seq_name, graph_oid);
+        cr.load_as_agtype = load_as_agtype;
+
+        /* Initialize the batch insert state */
+        init_batch_insert(&cr.batch_state, label_name, graph_oid);
+
+        while ((bytes_read=fread(buf, 1, 1024, fp)) > 0)
         {
-            ereport(ERROR, (errmsg("Error while parsing file: %s\n",
-                                   csv_strerror(csv_error(&p)))));
+            if (csv_parse(&p, buf, bytes_read, edge_field_cb,
+                        edge_row_cb, &cr) != bytes_read)
+            {
+                ereport(ERROR, (errmsg("Error while parsing file: %s\n",
+                                    csv_strerror(csv_error(&p)))));
+            }
         }
-    }
 
-    csv_fini(&p, edge_field_cb, edge_row_cb, &cr);
+        csv_fini(&p, edge_field_cb, edge_row_cb, &cr);
 
-    /* Finish any remaining batch inserts */
-    finish_batch_insert(&cr.batch_state);
+        /* Finish any remaining batch inserts */
+        finish_batch_insert(&cr.batch_state);
 
-    if (ferror(fp))
+        if (ferror(fp))
+        {
+            ereport(ERROR, (errmsg("Error while reading file %s\n", 
file_path)));
+        }
+    }
+    PG_FINALLY();
     {
-        ereport(ERROR, (errmsg("Error while reading file %s\n", file_path)));
+        fclose(fp);
+        csv_free(&p);
     }
+    PG_END_TRY();
 
-    fclose(fp);
-
-    free(cr.fields);
-    csv_free(&p);
     return EXIT_SUCCESS;
-}
\ No newline at end of file
+}
diff --git a/src/backend/utils/load/ag_load_labels.c 
b/src/backend/utils/load/ag_load_labels.c
index 4a04f3cd..1e86bbda 100644
--- a/src/backend/utils/load/ag_load_labels.c
+++ b/src/backend/utils/load/ag_load_labels.c
@@ -39,8 +39,8 @@ void vertex_field_cb(void *field, size_t field_len, void 
*data)
     if (cr->cur_field == cr->alloc)
     {
         cr->alloc *= 2;
-        cr->fields = realloc(cr->fields, sizeof(char *) * cr->alloc);
-        cr->fields_len = realloc(cr->header, sizeof(size_t *) * cr->alloc);
+        cr->fields = repalloc_check(cr->fields, sizeof(char *) * cr->alloc);
+        cr->fields_len = repalloc_check(cr->header, sizeof(size_t *) * 
cr->alloc);
         if (cr->fields == NULL)
         {
             cr->error = 1;
@@ -51,7 +51,7 @@ void vertex_field_cb(void *field, size_t field_len, void 
*data)
     }
     cr->fields_len[cr->cur_field] = field_len;
     cr->curr_row_length += field_len;
-    cr->fields[cr->cur_field] = strndup((char *) field, field_len);
+    cr->fields[cr->cur_field] = pnstrdup((char *) field, field_len);
     cr->cur_field += 1;
 }
 
@@ -70,13 +70,13 @@ void vertex_row_cb(int delim __attribute__((unused)), void 
*data)
     {
         cr->header_num = cr->cur_field;
         cr->header_row_length = cr->curr_row_length;
-        cr->header_len = (size_t* )malloc(sizeof(size_t *) * cr->cur_field);
-        cr->header = malloc((sizeof (char*) * cr->cur_field));
+        cr->header_len = (size_t* )palloc(sizeof(size_t *) * cr->cur_field);
+        cr->header = palloc((sizeof (char*) * cr->cur_field));
 
         for (i = 0; i<cr->cur_field; i++)
         {
             cr->header_len[i] = cr->fields_len[i];
-            cr->header[i] = strndup(cr->fields[i], cr->header_len[i]);
+            cr->header[i] = pnstrdup(cr->fields[i], cr->header_len[i]);
         }
     }
     else
@@ -129,7 +129,7 @@ void vertex_row_cb(int delim __attribute__((unused)), void 
*data)
 
     for (i = 0; i < n_fields; ++i)
     {
-        free(cr->fields[i]);
+        pfree_if_not_null(cr->fields[i]);
     }
 
     if (cr->error)
@@ -189,6 +189,10 @@ int create_labels_from_csv_file(char *file_path,
                 (errmsg("Failed to initialize csv parser\n")));
     }
 
+    p.malloc_func = palloc;
+    p.realloc_func = repalloc_check;
+    p.free_func = pfree_if_not_null;
+
     csv_set_space_func(&p, is_space);
     csv_set_term_func(&p, is_term);
 
@@ -199,62 +203,67 @@ int create_labels_from_csv_file(char *file_path,
                 (errmsg("Failed to open %s\n", file_path)));
     }
 
-    label_seq_name = get_label_seq_relation_name(label_name);
-
-    memset((void*)&cr, 0, sizeof(csv_vertex_reader));
-
-    cr.alloc = 2048;
-    cr.fields = malloc(sizeof(char *) * cr.alloc);
-    cr.fields_len = malloc(sizeof(size_t *) * cr.alloc);
-    cr.header_row_length = 0;
-    cr.curr_row_length = 0;
-    cr.graph_name = graph_name;
-    cr.graph_oid = graph_oid;
-    cr.label_name = label_name;
-    cr.label_id = label_id;
-    cr.id_field_exists = id_field_exists;
-    cr.label_seq_relid = get_relname_relid(label_seq_name, graph_oid);
-    cr.load_as_agtype = load_as_agtype;
-    
-    if (cr.id_field_exists)
+    PG_TRY();
     {
-        /*
-         * Set the curr_seq_num since we will need it to compare with
-         * incoming entry_id.
-         * 
-         * We cant use currval because it will error out if nextval was
-         * not called before in the session.
-         */
-        cr.curr_seq_num = nextval_internal(cr.label_seq_relid, true);
-    }
+        label_seq_name = get_label_seq_relation_name(label_name);
+
+        memset((void*)&cr, 0, sizeof(csv_vertex_reader));
+
+        cr.alloc = 2048;
+        cr.fields = palloc(sizeof(char *) * cr.alloc);
+        cr.fields_len = palloc(sizeof(size_t *) * cr.alloc);
+        cr.header_row_length = 0;
+        cr.curr_row_length = 0;
+        cr.graph_name = graph_name;
+        cr.graph_oid = graph_oid;
+        cr.label_name = label_name;
+        cr.label_id = label_id;
+        cr.id_field_exists = id_field_exists;
+        cr.label_seq_relid = get_relname_relid(label_seq_name, graph_oid);
+        cr.load_as_agtype = load_as_agtype;
+            
+        if (cr.id_field_exists)
+        {
+            /*
+            * Set the curr_seq_num since we will need it to compare with
+            * incoming entry_id.
+            * 
+            * We cant use currval because it will error out if nextval was
+            * not called before in the session.
+            */
+            cr.curr_seq_num = nextval_internal(cr.label_seq_relid, true);
+        }
 
-    /* Initialize the batch insert state */
-    init_batch_insert(&cr.batch_state, label_name, graph_oid);
+        /* Initialize the batch insert state */
+        init_batch_insert(&cr.batch_state, label_name, graph_oid);
 
-    while ((bytes_read=fread(buf, 1, 1024, fp)) > 0)
-    {
-        if (csv_parse(&p, buf, bytes_read, vertex_field_cb,
-                      vertex_row_cb, &cr) != bytes_read)
+        while ((bytes_read=fread(buf, 1, 1024, fp)) > 0)
         {
-            ereport(ERROR, (errmsg("Error while parsing file: %s\n",
-                                   csv_strerror(csv_error(&p)))));
+            if (csv_parse(&p, buf, bytes_read, vertex_field_cb,
+                        vertex_row_cb, &cr) != bytes_read)
+            {
+                ereport(ERROR, (errmsg("Error while parsing file: %s\n",
+                                    csv_strerror(csv_error(&p)))));
+            }
         }
-    }
 
-    csv_fini(&p, vertex_field_cb, vertex_row_cb, &cr);
+        csv_fini(&p, vertex_field_cb, vertex_row_cb, &cr);
 
-    /* Finish any remaining batch inserts */
-    finish_batch_insert(&cr.batch_state);
+        /* Finish any remaining batch inserts */
+        finish_batch_insert(&cr.batch_state);
 
-    if (ferror(fp))
+        if (ferror(fp))
+        {
+            ereport(ERROR, (errmsg("Error while reading file %s\n",
+                                file_path)));
+        }
+    }
+    PG_FINALLY();
     {
-        ereport(ERROR, (errmsg("Error while reading file %s\n",
-                               file_path)));
+        fclose(fp);
+        csv_free(&p);
     }
+    PG_END_TRY();
 
-    fclose(fp);
-
-    free(cr.fields);
-    csv_free(&p);
     return EXIT_SUCCESS;
 }
\ No newline at end of file
diff --git a/src/include/utils/agtype.h b/src/include/utils/agtype.h
index 48677532..ab2ba08c 100644
--- a/src/include/utils/agtype.h
+++ b/src/include/utils/agtype.h
@@ -556,6 +556,7 @@ void pfree_agtype_value(agtype_value* value);
 void pfree_agtype_value_content(agtype_value* value);
 void pfree_agtype_in_state(agtype_in_state* value);
 void pfree_if_not_null(void *ptr);
+void *repalloc_check(void *ptr, size_t len);
 agtype_value *agtype_value_from_cstring(char *str, int len);
 /* Oid accessors for AGTYPE */
 Oid get_AGTYPEOID(void);

Reply via email to