From 0e2c907ae27600d596ba7df3f0f806a6d33ec45a 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/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. --- 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/parser/ag_scanner.l | 11 +-- src/backend/parser/cypher_analyze.c | 4 +- src/backend/parser/cypher_expr.c | 6 +- src/backend/parser/cypher_gram.y | 3 +- src/backend/parser/cypher_parse_agg.c | 5 +- src/backend/utils/adt/age_global_graph.c | 16 ++--- 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 | 91 ++++++++++++++---------- 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 | 8 +-- 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, 141 insertions(+), 100 deletions(-) diff --git a/regress/expected/expr.out b/regress/expected/expr.out index ab9e432e1..361243f6d 100644 --- a/regress/expected/expr.out +++ b/regress/expected/expr.out @@ -8715,6 +8715,21 @@ SELECT * FROM cypher('fuzzystrmatch', $$ RETURN difference("hello world!", "hell ERROR: extension fuzzystrmatch is not installed for function difference LINE 1: SELECT * FROM cypher('fuzzystrmatch', $$ RETURN difference("... ^ +-- +-- 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 ad6d7ed3e..10dd0a95c 100644 --- a/regress/sql/expr.sql +++ b/regress/sql/expr.sql @@ -3517,6 +3517,12 @@ SELECT * FROM create_graph('fuzzystrmatch'); SELECT * FROM cypher('fuzzystrmatch', $$ RETURN soundex("hello world!") $$) AS (result agtype); SELECT * FROM cypher('fuzzystrmatch', $$ RETURN difference("hello world!", "hello world!") $$) AS (result agtype); +-- +-- 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 05c4b8495..200b4c9bf 100644 --- a/src/backend/commands/label_commands.c +++ b/src/backend/commands/label_commands.c @@ -131,7 +131,7 @@ Datum age_is_valid_label_name(PG_FUNCTION_ARGS) agtv_value->val.string.len); is_valid = is_valid_label_name(label_name, 0); - pfree(label_name); + pfree_if_not_null(label_name); if (is_valid) { diff --git a/src/backend/executor/cypher_merge.c b/src/backend/executor/cypher_merge.c index e61bb6205..6f06a0070 100644 --- a/src/backend/executor/cypher_merge.c +++ b/src/backend/executor/cypher_merge.c @@ -346,7 +346,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]); } } @@ -892,10 +892,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 94053c54a..402935765 100644 --- a/src/backend/executor/cypher_set.c +++ b/src/backend/executor/cypher_set.c @@ -595,7 +595,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/parser/ag_scanner.l b/src/backend/parser/ag_scanner.l index 35eb37acc..45ccdac3b 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 @@ -794,7 +795,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 @@ -811,7 +812,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) @@ -824,7 +825,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) @@ -1119,8 +1120,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 70e258896..75e51ad0f 100644 --- a/src/backend/parser/cypher_analyze.c +++ b/src/backend/parser/cypher_analyze.c @@ -113,7 +113,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; } } @@ -303,7 +303,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_expr.c b/src/backend/parser/cypher_expr.c index cdb82135f..0d61201d4 100644 --- a/src/backend/parser/cypher_expr.c +++ b/src/backend/parser/cypher_expr.c @@ -1700,7 +1700,7 @@ static List *cast_agtype_input_to_other_type(cypher_parsestate *cpstate, } /* free the old args and replace them with the new ones */ - pfree(targs); + pfree_if_not_null(targs); targs = new_targs; break; } @@ -1755,7 +1755,7 @@ static void check_for_extension_functions(char *extension, FuncCall *fn) if (procform->pronamespace == oid && isTempNamespace(procform->pronamespace) == false) { - pfree(asp); + pfree_if_not_null(asp); found = true; break; } @@ -1766,7 +1766,7 @@ static void check_for_extension_functions(char *extension, FuncCall *fn) break; } - pfree(asp); + pfree_if_not_null(asp); } /* if we didn't find it, it isn't in the search path */ diff --git a/src/backend/parser/cypher_gram.y b/src/backend/parser/cypher_gram.y index 790c069bb..7ebe4f24b 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) \ @@ -2929,7 +2930,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 47075ef7b..a5f7085f6 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 { @@ -807,7 +808,7 @@ static List * expand_grouping_sets(List *groupingSets, int limit) result = lappend(result, list_union_int(NIL, (List *) lfirst(lc))); } - for_each_cell(lc, expanded_groups, + for_each_cell(lc, expanded_groups, lnext(expanded_groups, list_head(expanded_groups))) { List *p = lfirst(lc); @@ -847,7 +848,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 30ec7479d..6f30060ae 100644 --- a/src/backend/utils/adt/age_global_graph.c +++ b/src/backend/utils/adt/age_global_graph.c @@ -182,7 +182,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)); @@ -191,7 +191,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 */ @@ -709,7 +709,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; @@ -741,7 +741,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 */ @@ -783,7 +783,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 */ @@ -806,7 +806,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; @@ -1309,7 +1309,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"); @@ -1415,7 +1415,7 @@ Datum age_graph_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); /* zero the state */ memset(&result, 0, sizeof(agtype_in_state)); 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 8e7e1ac49..1044ffe65 100644 --- a/src/backend/utils/adt/age_vle.c +++ b/src/backend/utils/adt/age_vle.c @@ -320,7 +320,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); } /* @@ -434,14 +434,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; } @@ -463,15 +463,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 e9cb40d2f..caace491a 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; @@ -296,7 +309,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; } @@ -321,8 +334,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); @@ -1544,7 +1557,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: @@ -1589,7 +1602,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 { @@ -1819,8 +1832,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); } /* @@ -2219,7 +2232,7 @@ Datum make_path(List *path) if ((Pointer) (agt) != lfirst(lc)) { - pfree(agt); + pfree_if_not_null(agt); } pfree_agtype_value(elem); @@ -2480,7 +2493,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 { @@ -2842,7 +2855,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); @@ -2963,7 +2976,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); @@ -3085,7 +3098,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); @@ -3230,7 +3243,7 @@ Datum text_to_agtype(PG_FUNCTION_ARGS) agtv.val.string.val = pstrdup(string); /* free the string */ - pfree(string); + pfree_if_not_null(string); /* convert to agtype */ result = agtype_value_to_agtype(&agtv); @@ -3278,7 +3291,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); } @@ -4065,9 +4078,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(); } @@ -4078,9 +4091,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(); } } @@ -4199,9 +4212,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); @@ -4676,8 +4689,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); @@ -4733,7 +4746,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); @@ -4839,7 +4852,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 */ @@ -4927,7 +4940,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 */ @@ -5064,7 +5077,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 */ @@ -7161,7 +7174,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); } @@ -10364,9 +10377,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; } @@ -10387,9 +10400,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; } } @@ -10413,9 +10426,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 6ae35c210..ac09de453 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 e7270ef84..d8bad3d24 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 878f1844a..01a965cdd 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 71683bf4c..30dc4761d 100644 --- a/src/backend/utils/load/ag_load_edges.c +++ b/src/backend/utils/load/ag_load_edges.c @@ -307,9 +307,9 @@ void finish_edge_batch_insert(batch_insert_state **batch_state, } // Clean up batch state - pfree((*batch_state)->slots); - pfree(*batch_state); + pfree_if_not_null((*batch_state)->slots); + pfree_if_not_null(*batch_state); *batch_state = NULL; table_close(relation, AccessShareLock); -} \ 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 b38c7fca9..94167812a 100644 --- a/src/backend/utils/load/ag_load_labels.c +++ b/src/backend/utils/load/ag_load_labels.c @@ -458,11 +458,11 @@ static void finish_vertex_batch_insert(batch_insert_state **batch_state, } /* Clean up batch state */ - pfree((*batch_state)->slots); - pfree((*batch_state)->temp_id_slots); - pfree(*batch_state); + pfree_if_not_null((*batch_state)->slots); + pfree_if_not_null((*batch_state)->temp_id_slots); + pfree_if_not_null(*batch_state); *batch_state = NULL; table_close(relation, AccessShareLock); table_close(temp_table_relation, AccessShareLock); -} \ 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 a1e14b325..a98c4f77d 100644 --- a/src/include/utils/agtype.h +++ b/src/include/utils/agtype.h @@ -556,6 +556,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);