From 937c9ae0f48a1a967cd7609543e3b1ecdb8a3cf8 Mon Sep 17 00:00:00 2001 From: John Gemignani Date: Tue, 10 Sep 2024 11:08:01 -0700 Subject: [PATCH] Fix issue 2093: pfree() called with a NULL pointer (#2095) Fixed issue 2093 where pfree() was called with a NULL pointer. The issue is due to some confusion with pfree(). There are 2 definitions for it, one that checks for a passed NULL and the other which does not. Created a function, pfree_if_not_null(), to check for NULL and call pfree() if a NULL wasn't passed. Modified the pfree references in the following files - src/backend/commands/label_commands.c src/backend/executor/cypher_merge.c src/backend/executor/cypher_set.c src/backend/executor/cypher_utils.c src/backend/parser/ag_scanner.l src/backend/parser/cypher_analyze.c src/backend/parser/cypher_expr.c src/backend/parser/cypher_gram.y src/backend/parser/cypher_parse_agg.c src/backend/utils/adt/age_global_graph.c src/backend/utils/adt/age_graphid_ds.c src/backend/utils/adt/age_session_info.c src/backend/utils/adt/age_vle.c src/backend/utils/adt/agtype.c src/backend/utils/adt/agtype_gin.c src/backend/utils/adt/agtype_raw.c src/backend/utils/adt/agtype_util.c src/backend/utils/load/ag_load_edges.c src/backend/utils/load/ag_load_labels.c src/include/utils/age_graphid_ds.h src/include/utils/age_session_info.h src/include/utils/agtype.h Added regression tests for the original issue. Resolved Conflicts: src/backend/commands/label_commands.c src/backend/parser/cypher_expr.c src/backend/parser/cypher_parse_agg.c src/backend/utils/adt/age_global_graph.c src/backend/utils/adt/agtype.c Resolved Conflicts: src/backend/utils/load/ag_load_edges.c src/backend/utils/load/ag_load_labels.c --- regress/expected/expr.out | 15 ++++ regress/sql/expr.sql | 6 ++ src/backend/commands/label_commands.c | 2 - src/backend/executor/cypher_merge.c | 6 +- src/backend/executor/cypher_set.c | 2 +- src/backend/executor/cypher_utils.c | 2 +- src/backend/parser/ag_scanner.l | 11 +-- src/backend/parser/cypher_analyze.c | 4 +- src/backend/parser/cypher_gram.y | 3 +- src/backend/parser/cypher_parse_agg.c | 3 +- src/backend/utils/adt/age_global_graph.c | 14 ++-- src/backend/utils/adt/age_graphid_ds.c | 8 +-- src/backend/utils/adt/age_session_info.c | 4 +- src/backend/utils/adt/age_vle.c | 14 ++-- src/backend/utils/adt/agtype.c | 89 ++++++++++++++---------- src/backend/utils/adt/agtype_gin.c | 2 +- src/backend/utils/adt/agtype_raw.c | 4 +- src/backend/utils/adt/agtype_util.c | 24 +++---- src/backend/utils/load/ag_load_edges.c | 6 +- src/backend/utils/load/ag_load_labels.c | 18 ++--- src/include/utils/age_graphid_ds.h | 1 + src/include/utils/age_session_info.h | 2 + src/include/utils/agtype.h | 1 + 23 files changed, 140 insertions(+), 101 deletions(-) diff --git a/regress/expected/expr.out b/regress/expected/expr.out index 281c3e661..3da13ca77 100644 --- a/regress/expected/expr.out +++ b/regress/expected/expr.out @@ -8505,6 +8505,21 @@ SELECT agtype_to_int8(bool('neither')); ERROR: invalid input syntax for type boolean: "neither" LINE 1: SELECT agtype_to_int8(bool('neither')); ^ +-- +-- Issue 2093: Server crashes when executing SELECT agtype_hash_cmp(agtype_in('[null, null, null, null, null]')); +-- +SELECT agtype_access_operator(agtype_in('[null, null]')); + agtype_access_operator +------------------------ + +(1 row) + +SELECT agtype_hash_cmp(agtype_in('[null, null, null, null, null]')); + agtype_hash_cmp +----------------- + -505290721 +(1 row) + -- -- Cleanup -- diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql index 19d9b1b8b..e150e2abe 100644 --- a/regress/sql/expr.sql +++ b/regress/sql/expr.sql @@ -3453,6 +3453,12 @@ SELECT agtype_to_int2(bool('neither')); SELECT agtype_to_int4(bool('neither')); SELECT agtype_to_int8(bool('neither')); +-- +-- Issue 2093: Server crashes when executing SELECT agtype_hash_cmp(agtype_in('[null, null, null, null, null]')); +-- +SELECT agtype_access_operator(agtype_in('[null, null]')); +SELECT agtype_hash_cmp(agtype_in('[null, null, null, null, null]')); + -- -- Cleanup -- diff --git a/src/backend/commands/label_commands.c b/src/backend/commands/label_commands.c index ead3879d6..80226e7c7 100644 --- a/src/backend/commands/label_commands.c +++ b/src/backend/commands/label_commands.c @@ -94,8 +94,6 @@ static void range_var_callback_for_remove_relation(const RangeVar *rel, Oid odl_rel_oid, void *arg); - - PG_FUNCTION_INFO_V1(create_vlabel); /* diff --git a/src/backend/executor/cypher_merge.c b/src/backend/executor/cypher_merge.c index 83ff1266d..db1de18ea 100644 --- a/src/backend/executor/cypher_merge.c +++ b/src/backend/executor/cypher_merge.c @@ -347,7 +347,7 @@ static void free_path_entry_array(path_entry **path_array, int length) for (index = 0; index < length; index++) { - pfree(path_array[index]); + pfree_if_not_null(path_array[index]); } } @@ -901,10 +901,10 @@ static void end_cypher_merge(CustomScanState *node) free_path_entry_array(entry, path_length); /* free up the array container */ - pfree(entry); + pfree_if_not_null(entry); /* free up the created_path container */ - pfree(css->created_paths_list); + pfree_if_not_null(css->created_paths_list); css->created_paths_list = next; } diff --git a/src/backend/executor/cypher_set.c b/src/backend/executor/cypher_set.c index 552395c9c..ee2322d54 100644 --- a/src/backend/executor/cypher_set.c +++ b/src/backend/executor/cypher_set.c @@ -555,7 +555,7 @@ static void process_update_list(CustomScanState *node) lidx++; } /* free our lookup array */ - pfree(luindex); + pfree_if_not_null(luindex); } static TupleTableSlot *exec_cypher_set(CustomScanState *node) diff --git a/src/backend/executor/cypher_utils.c b/src/backend/executor/cypher_utils.c index 44158eb26..445a3e8f2 100644 --- a/src/backend/executor/cypher_utils.c +++ b/src/backend/executor/cypher_utils.c @@ -76,7 +76,7 @@ uint32 datum_image_hash(Datum value, bool typByVal, int typLen) /* Only free memory if it's a copy made here. */ if ((Pointer) val != (Pointer) value) { - pfree(val); + pfree_if_not_null(val); } } else if (typLen == -2) diff --git a/src/backend/parser/ag_scanner.l b/src/backend/parser/ag_scanner.l index 6fc9baf8d..3af558270 100644 --- a/src/backend/parser/ag_scanner.l +++ b/src/backend/parser/ag_scanner.l @@ -34,6 +34,7 @@ #include "mb/pg_wchar.h" #include "parser/ag_scanner.h" +#include "utils/agtype.h" } %option 8bit @@ -795,7 +796,7 @@ void *ag_yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner) { if (size == 0) { - pfree(ptr); + pfree_if_not_null(ptr); return NULL; } else @@ -812,7 +813,7 @@ void *ag_yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner) void ag_yyfree(void *ptr, yyscan_t yyscanner) { if (ptr) - pfree(ptr); + pfree_if_not_null(ptr); } static void strbuf_init(strbuf *sb, int capacity) @@ -825,7 +826,7 @@ static void strbuf_init(strbuf *sb, int capacity) static void strbuf_cleanup(strbuf *sb) { if (sb->buffer) - pfree(sb->buffer); + pfree_if_not_null(sb->buffer); } static void strbuf_append_buf(strbuf *sb, const char *b, const int len) @@ -1121,8 +1122,8 @@ static void _numstr_to_decimal(const char *numstr, const int base, strbuf *sb) strbuf_append_buf(sb, &buf[buf_i], ndigits_per_remainder - buf_i); } - pfree(remainders); - pfree(words); + pfree_if_not_null(remainders); + pfree_if_not_null(words); } static uint32 hexdigit_value(const char c) diff --git a/src/backend/parser/cypher_analyze.c b/src/backend/parser/cypher_analyze.c index c868070ae..080d489d5 100644 --- a/src/backend/parser/cypher_analyze.c +++ b/src/backend/parser/cypher_analyze.c @@ -108,7 +108,7 @@ static void post_parse_analyze(ParseState *pstate, Query *query) } /* reset extra_node */ - pfree(extra_node); + pfree_if_not_null(extra_node); extra_node = NULL; } } @@ -277,7 +277,7 @@ static void build_explain_query(Query *query, Node *explain_node) ((ExplainStmt *)explain_node)->options = NULL; /* we need to free query_node as it is no longer needed */ - pfree(query_node); + pfree_if_not_null(query_node); } static bool is_rte_cypher(RangeTblEntry *rte) diff --git a/src/backend/parser/cypher_gram.y b/src/backend/parser/cypher_gram.y index 0825c2065..e8652f21e 100644 --- a/src/backend/parser/cypher_gram.y +++ b/src/backend/parser/cypher_gram.y @@ -26,6 +26,7 @@ #include "parser/cypher_gram.h" #include "parser/cypher_parse_node.h" #include "parser/scansup.h" +#include "utils/agtype.h" // override the default action for locations #define YYLLOC_DEFAULT(current, rhs, n) \ @@ -2714,7 +2715,7 @@ static char *create_unique_name(char *prefix_name) /* if we created the prefix, we need to free it */ if (prefix_name == NULL || strlen(prefix_name) <= 0) { - pfree(prefix); + pfree_if_not_null(prefix); } return name; diff --git a/src/backend/parser/cypher_parse_agg.c b/src/backend/parser/cypher_parse_agg.c index b5654e778..54c57657c 100644 --- a/src/backend/parser/cypher_parse_agg.c +++ b/src/backend/parser/cypher_parse_agg.c @@ -31,6 +31,7 @@ #include "parser/cypher_parse_agg.h" #include "parser/parsetree.h" #include "rewrite/rewriteManip.h" +#include "utils/agtype.h" typedef struct { @@ -846,7 +847,7 @@ static List * expand_grouping_sets(List *groupingSets, int limit) while (result_len-- > 0) result = lappend(result, *ptr++); - pfree(buf); + pfree_if_not_null(buf); } return result; diff --git a/src/backend/utils/adt/age_global_graph.c b/src/backend/utils/adt/age_global_graph.c index d16e628ba..e1a50e732 100644 --- a/src/backend/utils/adt/age_global_graph.c +++ b/src/backend/utils/adt/age_global_graph.c @@ -181,7 +181,7 @@ static void create_GRAPH_global_hashtables(GRAPH_global_context *ggctx) ggctx->vertex_hashtable = hash_create(vhn, VERTEX_HTAB_INITIAL_SIZE, &vertex_ctl, HASH_ELEM | HASH_FUNCTION); - pfree(vhn); + pfree_if_not_null(vhn); /* initialize the edge hashtable */ MemSet(&edge_ctl, 0, sizeof(edge_ctl)); @@ -190,7 +190,7 @@ static void create_GRAPH_global_hashtables(GRAPH_global_context *ggctx) edge_ctl.hash = tag_hash; ggctx->edge_hashtable = hash_create(ehn, EDGE_HTAB_INITIAL_SIZE, &edge_ctl, HASH_ELEM | HASH_FUNCTION); - pfree(ehn); + pfree_if_not_null(ehn); } /* helper function to get a List of all label names for the specified graph */ @@ -624,7 +624,7 @@ static bool free_specific_GRAPH_global_context(GRAPH_global_context *ggctx) } /* free the graph name */ - pfree(ggctx->graph_name); + pfree_if_not_null(ggctx->graph_name); ggctx->graph_name = NULL; ggctx->graph_oid = InvalidOid; @@ -656,7 +656,7 @@ static bool free_specific_GRAPH_global_context(GRAPH_global_context *ggctx) } /* free the vertex's datumCopy properties */ - pfree(DatumGetPointer(value->vertex_properties)); + pfree_if_not_null(DatumGetPointer(value->vertex_properties)); value->vertex_properties = 0; /* free the edge list associated with this vertex */ @@ -698,7 +698,7 @@ static bool free_specific_GRAPH_global_context(GRAPH_global_context *ggctx) } /* free the edge's datumCopy properties */ - pfree(DatumGetPointer(value->edge_properties)); + pfree_if_not_null(DatumGetPointer(value->edge_properties)); value->edge_properties = 0; /* move to the next edge */ @@ -721,7 +721,7 @@ static bool free_specific_GRAPH_global_context(GRAPH_global_context *ggctx) ggctx->edge_hashtable = NULL; /* free the context */ - pfree(ggctx); + pfree_if_not_null(ggctx); ggctx = NULL; return true; @@ -1224,7 +1224,7 @@ Datum age_vertex_stats(PG_FUNCTION_ARGS) ggctx = manage_GRAPH_global_contexts(graph_name, graph_oid); /* free the graph name */ - pfree(graph_name); + pfree_if_not_null(graph_name); /* get the id */ agtv_temp = GET_AGTYPE_VALUE_OBJECT_VALUE(agtv_vertex, "id"); diff --git a/src/backend/utils/adt/age_graphid_ds.c b/src/backend/utils/adt/age_graphid_ds.c index 73be8dc2e..625a6947c 100644 --- a/src/backend/utils/adt/age_graphid_ds.c +++ b/src/backend/utils/adt/age_graphid_ds.c @@ -144,14 +144,14 @@ void free_ListGraphId(ListGraphId *container) { next_node = curr_node->next; /* we can do this because this is just a list of ints */ - pfree(curr_node); + pfree_if_not_null(curr_node); container->size--; curr_node = next_node; } Assert(container->size == 0); /* free the container */ - pfree(container); + pfree_if_not_null(container); } /* helper function to create a new, empty, graphid stack */ @@ -188,7 +188,7 @@ void free_graphid_stack(ListGraphId *stack) GraphIdNode *next = stack->head->next; /* free the head element */ - pfree(stack->head); + pfree_if_not_null(stack->head); /* move the head to the next */ stack->head = next; } @@ -253,7 +253,7 @@ graphid pop_graphid_stack(ListGraphId *stack) stack->head = stack->head->next; stack->size--; /* free the element */ - pfree(node); + pfree_if_not_null(node); /* return the id */ return id; diff --git a/src/backend/utils/adt/age_session_info.c b/src/backend/utils/adt/age_session_info.c index 350273eb3..f224d4064 100644 --- a/src/backend/utils/adt/age_session_info.c +++ b/src/backend/utils/adt/age_session_info.c @@ -125,12 +125,12 @@ void reset_session_info(void) { if (session_info_graph_name != NULL) { - pfree(session_info_graph_name); + pfree_if_not_null(session_info_graph_name); } if (session_info_cypher_statement != NULL) { - pfree(session_info_cypher_statement); + pfree_if_not_null(session_info_cypher_statement); } } diff --git a/src/backend/utils/adt/age_vle.c b/src/backend/utils/adt/age_vle.c index 856cdb6c1..3c0119a1a 100644 --- a/src/backend/utils/adt/age_vle.c +++ b/src/backend/utils/adt/age_vle.c @@ -314,7 +314,7 @@ static void create_VLE_local_state_hashtable(VLE_local_context *vlelctx) EDGE_STATE_HTAB_INITIAL_SIZE, &edge_state_ctl, HASH_ELEM | HASH_FUNCTION); - pfree(eshn); + pfree_if_not_null(eshn); } /* @@ -401,14 +401,14 @@ static void free_VLE_local_context(VLE_local_context *vlelctx) /* free the stored graph name */ if (vlelctx->graph_name != NULL) { - pfree(vlelctx->graph_name); + pfree_if_not_null(vlelctx->graph_name); vlelctx->graph_name = NULL; } /* free the stored edge label name */ if (vlelctx->edge_label_name != NULL) { - pfree(vlelctx->edge_label_name); + pfree_if_not_null(vlelctx->edge_label_name); vlelctx->edge_label_name = NULL; } @@ -430,15 +430,15 @@ static void free_VLE_local_context(VLE_local_context *vlelctx) } /* free the containers */ - pfree(vlelctx->dfs_vertex_stack); - pfree(vlelctx->dfs_edge_stack); - pfree(vlelctx->dfs_path_stack); + pfree_if_not_null(vlelctx->dfs_vertex_stack); + pfree_if_not_null(vlelctx->dfs_edge_stack); + pfree_if_not_null(vlelctx->dfs_path_stack); vlelctx->dfs_vertex_stack = NULL; vlelctx->dfs_edge_stack = NULL; vlelctx->dfs_path_stack = NULL; /* and finally the context itself */ - pfree(vlelctx); + pfree_if_not_null(vlelctx); vlelctx = NULL; } diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c index 073b4f59d..b3a13fbc9 100644 --- a/src/backend/utils/adt/agtype.c +++ b/src/backend/utils/adt/agtype.c @@ -179,6 +179,19 @@ 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); +/* + * 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 + * NULL. + */ +void pfree_if_not_null(void *ptr) +{ + if (ptr != NULL) + { + pfree(ptr); + } +} + /* global storage of OID for agtype and _agtype */ static Oid g_AGTYPEOID = InvalidOid; static Oid g_AGTYPEARRAYOID = InvalidOid; @@ -295,7 +308,7 @@ Datum agtype_recv(PG_FUNCTION_ARGS) result = agtype_from_cstring(str, nbytes); PG_FREE_IF_COPY(buf, 0); - pfree(str); + pfree_if_not_null(str); return result; } @@ -320,8 +333,8 @@ Datum agtype_send(PG_FUNCTION_ARGS) pq_begintypsend(&buf); pq_sendint8(&buf, version); pq_sendtext(&buf, agtype_text->data, agtype_text->len); - pfree(agtype_text->data); - pfree(agtype_text); + pfree_if_not_null(agtype_text->data); + pfree_if_not_null(agtype_text); PG_FREE_IF_COPY(agt, 0); @@ -1542,7 +1555,7 @@ static void datum_to_agtype(Datum val, bool is_null, agtype_in_state *result, intd = DirectFunctionCall1(int8in, CStringGetDatum(outputstr)); agtv.type = AGTV_INTEGER; agtv.val.int_value = DatumGetInt64(intd); - pfree(outputstr); + pfree_if_not_null(outputstr); } break; case AGT_TYPE_FLOAT: @@ -1587,7 +1600,7 @@ static void datum_to_agtype(Datum val, bool is_null, agtype_in_state *result, ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)); agtv.val.numeric = DatumGetNumeric(numd); - pfree(outputstr); + pfree_if_not_null(outputstr); } else { @@ -1817,8 +1830,8 @@ static void array_to_agtype_internal(Datum array, agtype_in_state *result) array_dim_to_agtype(result, 0, ndim, dim, elements, nulls, &count, tcategory, outfuncoid); - pfree(elements); - pfree(nulls); + pfree_if_not_null(elements); + pfree_if_not_null(nulls); } /* @@ -2216,7 +2229,7 @@ Datum make_path(List *path) if ((Pointer) (agt) != lfirst(lc)) { - pfree(agt); + pfree_if_not_null(agt); } pfree_agtype_value(elem); @@ -2469,7 +2482,7 @@ static agtype_value* agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo) result.res = push_agtype_value(&result.parse_state, WAGT_KEY, agtv); /* free the agtype_value from tostring_helper */ - pfree(agtv); + pfree_if_not_null(agtv); } else { @@ -2832,7 +2845,7 @@ Datum agtype_to_int8(PG_FUNCTION_ARGS) /* free the container, if it was used */ if (container) { - pfree(container); + pfree_if_not_null(container); } PG_FREE_IF_COPY(arg_agt, 0); @@ -2953,7 +2966,7 @@ Datum agtype_to_int4(PG_FUNCTION_ARGS) /* free the container, if it was used */ if (container) { - pfree(container); + pfree_if_not_null(container); } PG_FREE_IF_COPY(arg_agt, 0); @@ -3075,7 +3088,7 @@ Datum agtype_to_int2(PG_FUNCTION_ARGS) /* free the container, if it was used */ if (container) { - pfree(container); + pfree_if_not_null(container); } PG_FREE_IF_COPY(arg_agt, 0); @@ -3225,7 +3238,7 @@ Datum agtype_to_json(PG_FUNCTION_ARGS) result = DirectFunctionCall1(json_in, CStringGetDatum(json_str)); PG_FREE_IF_COPY(agt, 0); - pfree(json_str); + pfree_if_not_null(json_str); PG_RETURN_DATUM(result); } @@ -3999,9 +4012,9 @@ Datum agtype_access_operator(PG_FUNCTION_ARGS) */ if (args == NULL || nargs == 0 || nulls[0] == true) { - pfree(args); - pfree(types); - pfree(nulls); + pfree_if_not_null(args); + pfree_if_not_null(types); + pfree_if_not_null(nulls); PG_RETURN_NULL(); } @@ -4012,9 +4025,9 @@ Datum agtype_access_operator(PG_FUNCTION_ARGS) /* if we have a NULL, return NULL */ if (nulls[i] == true) { - pfree(args); - pfree(types); - pfree(nulls); + pfree_if_not_null(args); + pfree_if_not_null(types); + pfree_if_not_null(nulls); PG_RETURN_NULL(); } } @@ -4133,9 +4146,9 @@ Datum agtype_access_operator(PG_FUNCTION_ARGS) container = NULL; } - pfree(args); - pfree(types); - pfree(nulls); + pfree_if_not_null(args); + pfree_if_not_null(types); + pfree_if_not_null(nulls); /* serialize and return the result */ result = agtype_value_to_agtype(container_value); @@ -4610,8 +4623,8 @@ Datum agtype_string_match_contains(PG_FUNCTION_ARGS) { result = true; } - pfree(l); - pfree(r); + pfree_if_not_null(l); + pfree_if_not_null(r); } pfree_agtype_value(lhs_value); pfree_agtype_value(rhs_value); @@ -4667,7 +4680,7 @@ Datum agtype_hash_cmp(PG_FUNCTION_ARGS) seed = LEFT_ROTATE(seed, 1); } - pfree(r); + pfree_if_not_null(r); PG_FREE_IF_COPY(agt, 0); PG_RETURN_INT32(hash); @@ -4773,7 +4786,7 @@ Datum agtype_typecast_numeric(PG_FUNCTION_ARGS) ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)); /* free the string */ - pfree(string); + pfree_if_not_null(string); string = NULL; break; /* what was given doesn't cast to a numeric */ @@ -4861,7 +4874,7 @@ Datum agtype_typecast_int(PG_FUNCTION_ARGS) d = DirectFunctionCall1(int8in, CStringGetDatum(string)); /* free the string */ - pfree(string); + pfree_if_not_null(string); string = NULL; break; /* what was given doesn't cast to an int */ @@ -4998,7 +5011,7 @@ Datum agtype_typecast_float(PG_FUNCTION_ARGS) d = DirectFunctionCall1(float8in, CStringGetDatum(string)); /* free the string */ - pfree(string); + pfree_if_not_null(string); string = NULL; break; /* what was given doesn't cast to a float */ @@ -7088,7 +7101,7 @@ Datum age_tostring(PG_FUNCTION_ARGS) /* convert to agtype and free the agtype_value */ agt = agtype_value_to_agtype(agtv); - pfree(agtv); + pfree_if_not_null(agtv); PG_RETURN_POINTER(agt); } @@ -10292,9 +10305,9 @@ agtype *get_one_agtype_from_variadic_args(FunctionCallInfo fcinfo, /* if null, return null */ if (nulls[0]) { - pfree(args); - pfree(nulls); - pfree(types); + pfree_if_not_null(args); + pfree_if_not_null(nulls); + pfree_if_not_null(types); return NULL; } @@ -10315,9 +10328,9 @@ agtype *get_one_agtype_from_variadic_args(FunctionCallInfo fcinfo, { PG_FREE_IF_COPY(agtype_result, variadic_offset); - pfree(args); - pfree(nulls); - pfree(types); + pfree_if_not_null(args); + pfree_if_not_null(nulls); + pfree_if_not_null(types); return NULL; } } @@ -10341,9 +10354,9 @@ agtype *get_one_agtype_from_variadic_args(FunctionCallInfo fcinfo, pfree_agtype_in_state(&state); } - pfree(args); - pfree(nulls); - pfree(types); + pfree_if_not_null(args); + pfree_if_not_null(nulls); + pfree_if_not_null(types); return agtype_result; } diff --git a/src/backend/utils/adt/agtype_gin.c b/src/backend/utils/adt/agtype_gin.c index 312fcffae..3a02f4b37 100644 --- a/src/backend/utils/adt/agtype_gin.c +++ b/src/backend/utils/adt/agtype_gin.c @@ -552,7 +552,7 @@ static Datum make_scalar_key(const agtype_value *scalarVal, bool is_key) */ cstr = numeric_normalize(scalarVal->val.numeric); item = make_text_key(AGT_GIN_FLAG_NUM, cstr, strlen(cstr)); - pfree(cstr); + pfree_if_not_null(cstr); break; case AGTV_STRING: item = make_text_key(is_key ? AGT_GIN_FLAG_KEY : AGT_GIN_FLAG_STR, diff --git a/src/backend/utils/adt/agtype_raw.c b/src/backend/utils/adt/agtype_raw.c index f54068069..9c6954578 100644 --- a/src/backend/utils/adt/agtype_raw.c +++ b/src/backend/utils/adt/agtype_raw.c @@ -172,8 +172,8 @@ void pfree_agtype_build_state(agtype_build_state *bstate) * bstate->buffer->data is not pfree'd because this pointer * is returned by the `build_agtype` function. */ - pfree(bstate->buffer); - pfree(bstate); + pfree_if_not_null(bstate->buffer); + pfree_if_not_null(bstate); } void write_string(agtype_build_state *bstate, char *str) diff --git a/src/backend/utils/adt/agtype_util.c b/src/backend/utils/adt/agtype_util.c index 44780ecae..2044d47f6 100644 --- a/src/backend/utils/adt/agtype_util.c +++ b/src/backend/utils/adt/agtype_util.c @@ -433,14 +433,14 @@ int compare_agtype_containers_orderability(agtype_container *a, { agtype_iterator *i = ita->parent; - pfree(ita); + pfree_if_not_null(ita); ita = i; } while (itb != NULL) { agtype_iterator *i = itb->parent; - pfree(itb); + pfree_if_not_null(itb); itb = i; } @@ -557,7 +557,7 @@ agtype_value *find_agtype_value_from_container(agtype_container *container, } /* Not found */ - pfree(result); + pfree_if_not_null(result); return NULL; } @@ -1217,7 +1217,7 @@ static agtype_iterator *free_and_get_parent(agtype_iterator *it) { agtype_iterator *v = it->parent; - pfree(it); + pfree_if_not_null(it); return v; } @@ -1469,9 +1469,9 @@ bool agtype_deep_contains(agtype_iterator **val, contains = agtype_deep_contains(&nestval, &nest_contained, false); if (nestval) - pfree(nestval); + pfree_if_not_null(nestval); if (nest_contained) - pfree(nest_contained); + pfree_if_not_null(nest_contained); if (contains) break; } @@ -2438,7 +2438,7 @@ char *agtype_value_type_to_string(enum agtype_value_type type) void pfree_agtype_value(agtype_value* value) { pfree_agtype_value_content(value); - pfree(value); + pfree_if_not_null(value); } /* @@ -2456,7 +2456,7 @@ void pfree_agtype_value_content(agtype_value* value) switch (value->type) { case AGTV_NUMERIC: - pfree(value->val.numeric); + pfree_if_not_null(value->val.numeric); break; case AGTV_STRING: @@ -2464,7 +2464,7 @@ void pfree_agtype_value_content(agtype_value* value) * The char pointer (val.string.val) is not free'd because * it is not allocated by an agtype helper function. */ - pfree(value->val.string.val); + pfree_if_not_null(value->val.string.val); break; case AGTV_ARRAY: @@ -2473,7 +2473,7 @@ void pfree_agtype_value_content(agtype_value* value) { pfree_agtype_value_content(&value->val.array.elems[i]); } - pfree(value->val.array.elems); + pfree_if_not_null(value->val.array.elems); break; case AGTV_OBJECT: @@ -2484,11 +2484,11 @@ void pfree_agtype_value_content(agtype_value* value) pfree_agtype_value_content(&value->val.object.pairs[i].key); pfree_agtype_value_content(&value->val.object.pairs[i].value); } - pfree(value->val.object.pairs); + pfree_if_not_null(value->val.object.pairs); break; case AGTV_BINARY: - pfree(value->val.binary.data); + pfree_if_not_null(value->val.binary.data); break; case AGTV_NULL: diff --git a/src/backend/utils/load/ag_load_edges.c b/src/backend/utils/load/ag_load_edges.c index 65ce9366b..e7f1442b7 100644 --- a/src/backend/utils/load/ag_load_edges.c +++ b/src/backend/utils/load/ag_load_edges.c @@ -281,7 +281,7 @@ static void finish_edge_batch_insert(batch_insert_state **batch_state, } // Clean up batch state - pfree((*batch_state)->buffered_tuples); - pfree(*batch_state); + pfree_if_not_null((*batch_state)->buffered_tuples); + pfree_if_not_null(*batch_state); *batch_state = NULL; -} \ 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 194a6dc82..abefcbade 100644 --- a/src/backend/utils/load/ag_load_labels.c +++ b/src/backend/utils/load/ag_load_labels.c @@ -327,8 +327,8 @@ static void setup_temp_table_for_vertex_ids(char *graph_name) SPI_finish(); - pfree(create_as_query); - pfree(index_query); + pfree_if_not_null(create_as_query); + pfree_if_not_null(index_query); } /* @@ -366,7 +366,7 @@ static void insert_batch_in_temp_table(batch_insert_state *batch_state, for (i = 0; i < batch_state->num_tuples; i++) { TupleTableSlot *slot; - + slot = MakeSingleTupleTableSlot(batch_state->id_desc); ExecStoreTuple(batch_state->buffered_id_tuples[i], slot, InvalidBuffer, false); @@ -379,14 +379,14 @@ static void insert_batch_in_temp_table(batch_insert_state *batch_state, bool isnull; id = slot_getattr(slot, 1, &isnull); - pfree(slot); + pfree_if_not_null(slot); ereport(ERROR, (errmsg("Cannot insert duplicate vertex id: %ld", DATUM_GET_GRAPHID(id)), errhint("Entry id %ld is already used", get_graphid_entry_id(id)))); } - pfree(slot); + pfree_if_not_null(slot); } /* Clean up and close the indices */ ExecCloseIndices(resultRelInfo); @@ -442,8 +442,8 @@ static void finish_vertex_batch_insert(batch_insert_state **batch_state, } /* Clean up batch state */ - pfree((*batch_state)->buffered_tuples); - pfree((*batch_state)->buffered_id_tuples); - pfree(*batch_state); + pfree_if_not_null((*batch_state)->buffered_tuples); + pfree_if_not_null((*batch_state)->buffered_id_tuples); + pfree_if_not_null(*batch_state); *batch_state = NULL; -} \ No newline at end of file +} diff --git a/src/include/utils/age_graphid_ds.h b/src/include/utils/age_graphid_ds.h index ea9dabdc3..a5bb5273f 100644 --- a/src/include/utils/age_graphid_ds.h +++ b/src/include/utils/age_graphid_ds.h @@ -21,6 +21,7 @@ #define AG_AGE_GRAPHID_DS_H #include "utils/graphid.h" +#include "utils/agtype.h" #define IS_GRAPHID_STACK_EMPTY(stack) \ get_stack_size(stack) == 0 diff --git a/src/include/utils/age_session_info.h b/src/include/utils/age_session_info.h index ebf0035ab..5bd072fb6 100644 --- a/src/include/utils/age_session_info.h +++ b/src/include/utils/age_session_info.h @@ -20,6 +20,8 @@ #ifndef AGE_SESSION_INFO_H #define AGE_SESSION_INFO_H +#include "utils/agtype.h" + bool is_session_info_prepared(void); char *get_session_info_graph_name(void); char *get_session_info_cypher_statement(void); diff --git a/src/include/utils/agtype.h b/src/include/utils/agtype.h index 44fdea1b1..65f3e8aa9 100644 --- a/src/include/utils/agtype.h +++ b/src/include/utils/agtype.h @@ -557,6 +557,7 @@ agtype_iterator *get_next_list_element(agtype_iterator *it, 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); agtype_value *agtype_value_from_cstring(char *str, int len); /* Oid accessors for AGTYPE */ Oid get_AGTYPEOID(void);