Fix issue 2093: pfree() called with a NULL pointer (#2095) (#2104)

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
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index c3a6f23..2178608 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -8507,6 +8507,21 @@
 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
 --
 SELECT * FROM drop_graph('issue_1124', true);
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index 3f1661b..e92a542 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -3456,6 +3456,12 @@
 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
 --
 SELECT * FROM drop_graph('issue_1124', true);
diff --git a/src/backend/commands/label_commands.c b/src/backend/commands/label_commands.c
index 9480ccc..5752372 100644
--- a/src/backend/commands/label_commands.c
+++ b/src/backend/commands/label_commands.c
@@ -94,8 +94,6 @@
                                                    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 6365db1..066c0d1 100644
--- a/src/backend/executor/cypher_merge.c
+++ b/src/backend/executor/cypher_merge.c
@@ -346,7 +346,7 @@
 
     for (index = 0; index < length; index++)
     {
-        pfree(path_array[index]);
+        pfree_if_not_null(path_array[index]);
     }
 }
 
@@ -892,10 +892,10 @@
         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 8c46c11..7af575b 100644
--- a/src/backend/executor/cypher_set.c
+++ b/src/backend/executor/cypher_set.c
@@ -594,7 +594,7 @@
         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 098c111..4627f16 100644
--- a/src/backend/executor/cypher_utils.c
+++ b/src/backend/executor/cypher_utils.c
@@ -75,7 +75,7 @@
         /* 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 7aabf3c..f7773d4 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
@@ -796,7 +797,7 @@
     {
         if (size == 0)
         {
-            pfree(ptr);
+            pfree_if_not_null(ptr);
             return NULL;
         }
         else
@@ -813,7 +814,7 @@
 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)
@@ -826,7 +827,7 @@
 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 @@
         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 a218895..9e1adb9 100644
--- a/src/backend/parser/cypher_analyze.c
+++ b/src/backend/parser/cypher_analyze.c
@@ -106,7 +106,7 @@
         }
 
         /* reset extra_node */
-        pfree(extra_node);
+        pfree_if_not_null(extra_node);
         extra_node = NULL;
     }
 }
@@ -275,7 +275,7 @@
     ((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 3c77c83..50417b1 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) \
@@ -2796,7 +2797,7 @@
     /* 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 8fdb71d..73b527c 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 @@
         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 1f2c227..d1c3750 100644
--- a/src/backend/utils/adt/age_global_graph.c
+++ b/src/backend/utils/adt/age_global_graph.c
@@ -182,7 +182,7 @@
     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 @@
     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 */
@@ -625,7 +625,7 @@
     }
 
     /* free the graph name */
-    pfree(ggctx->graph_name);
+    pfree_if_not_null(ggctx->graph_name);
     ggctx->graph_name = NULL;
 
     ggctx->graph_oid = InvalidOid;
@@ -657,7 +657,7 @@
         }
 
         /* 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 */
@@ -699,7 +699,7 @@
         }
 
         /* 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 */
@@ -722,7 +722,7 @@
     ggctx->edge_hashtable = NULL;
 
     /* free the context */
-    pfree(ggctx);
+    pfree_if_not_null(ggctx);
     ggctx = NULL;
 
     return true;
@@ -1225,7 +1225,7 @@
     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 73be8dc..625a694 100644
--- a/src/backend/utils/adt/age_graphid_ds.c
+++ b/src/backend/utils/adt/age_graphid_ds.c
@@ -144,14 +144,14 @@
     {
         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 @@
         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 @@
     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 350273e..f224d40 100644
--- a/src/backend/utils/adt/age_session_info.c
+++ b/src/backend/utils/adt/age_session_info.c
@@ -125,12 +125,12 @@
     {
         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 8e3b4d3..1e7910c 100644
--- a/src/backend/utils/adt/age_vle.c
+++ b/src/backend/utils/adt/age_vle.c
@@ -313,7 +313,7 @@
                                                 EDGE_STATE_HTAB_INITIAL_SIZE,
                                                 &edge_state_ctl,
                                                 HASH_ELEM | HASH_FUNCTION);
-    pfree(eshn);
+    pfree_if_not_null(eshn);
 }
 
 /*
@@ -400,14 +400,14 @@
     /* 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;
     }
 
@@ -429,15 +429,15 @@
     }
 
     /* 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 d908f3c..5b2dc40 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -178,6 +178,19 @@
 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 @@
     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 @@
     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);
 
@@ -1543,7 +1556,7 @@
                 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:
@@ -1588,7 +1601,7 @@
                                                ObjectIdGetDatum(InvalidOid),
                                                Int32GetDatum(-1));
                     agtv.val.numeric = DatumGetNumeric(numd);
-                    pfree(outputstr);
+                    pfree_if_not_null(outputstr);
                 }
                 else
                 {
@@ -1818,8 +1831,8 @@
     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);
 }
 
 /*
@@ -2218,7 +2231,7 @@
 
         if ((Pointer) (agt) != lfirst(lc))
         {
-            pfree(agt);
+            pfree_if_not_null(agt);
         }
         pfree_agtype_value(elem);
 
@@ -2471,7 +2484,7 @@
             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
         {
@@ -2833,7 +2846,7 @@
     /* free the container, if it was used */
     if (container)
     {
-        pfree(container);
+        pfree_if_not_null(container);
     }
 
     PG_FREE_IF_COPY(arg_agt, 0);
@@ -2954,7 +2967,7 @@
     /* free the container, if it was used */
     if (container)
     {
-        pfree(container);
+        pfree_if_not_null(container);
     }
 
     PG_FREE_IF_COPY(arg_agt, 0);
@@ -3076,7 +3089,7 @@
     /* free the container, if it was used */
     if (container)
     {
-        pfree(container);
+        pfree_if_not_null(container);
     }
 
     PG_FREE_IF_COPY(arg_agt, 0);
@@ -3226,7 +3239,7 @@
     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);
 }
@@ -4000,9 +4013,9 @@
      */
     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();
     }
@@ -4013,9 +4026,9 @@
         /* 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();
         }
     }
@@ -4134,9 +4147,9 @@
         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);
@@ -4611,8 +4624,8 @@
             {
                 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);
@@ -4668,7 +4681,7 @@
         seed = LEFT_ROTATE(seed, 1);
     }
 
-    pfree(r);
+    pfree_if_not_null(r);
     PG_FREE_IF_COPY(agt, 0);
 
     PG_RETURN_INT32(hash);
@@ -4774,7 +4787,7 @@
                                    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 */
@@ -4862,7 +4875,7 @@
 
         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 */
@@ -4999,7 +5012,7 @@
 
         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 */
@@ -7082,7 +7095,7 @@
 
     /* 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);
 }
@@ -10285,9 +10298,9 @@
     /* 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;
     }
 
@@ -10308,9 +10321,9 @@
         {
             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;
         }
     }
@@ -10334,9 +10347,9 @@
         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 3d7de21..07d9402 100644
--- a/src/backend/utils/adt/agtype_gin.c
+++ b/src/backend/utils/adt/agtype_gin.c
@@ -553,7 +553,7 @@
          */
         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 e7270ef..d8bad3d 100644
--- a/src/backend/utils/adt/agtype_raw.c
+++ b/src/backend/utils/adt/agtype_raw.c
@@ -172,8 +172,8 @@
      * 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 878f184..01a965c 100644
--- a/src/backend/utils/adt/agtype_util.c
+++ b/src/backend/utils/adt/agtype_util.c
@@ -433,14 +433,14 @@
     {
         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 @@
     }
 
     /* Not found */
-    pfree(result);
+    pfree_if_not_null(result);
     return NULL;
 }
 
@@ -1217,7 +1217,7 @@
 {
     agtype_iterator *v = it->parent;
 
-    pfree(it);
+    pfree_if_not_null(it);
     return v;
 }
 
@@ -1469,9 +1469,9 @@
                     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 @@
 void pfree_agtype_value(agtype_value* value)
 {
     pfree_agtype_value_content(value);
-    pfree(value);
+    pfree_if_not_null(value);
 }
 
 /*
@@ -2456,7 +2456,7 @@
     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 @@
              * 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 @@
             {
                 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 @@
                 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 71683bf..30dc476 100644
--- a/src/backend/utils/load/ag_load_edges.c
+++ b/src/backend/utils/load/ag_load_edges.c
@@ -307,9 +307,9 @@
     }
 
     // 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 b38c7fc..9416781 100644
--- a/src/backend/utils/load/ag_load_labels.c
+++ b/src/backend/utils/load/ag_load_labels.c
@@ -458,11 +458,11 @@
     }
 
     /* 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 ea9dabd..a5bb527 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 ebf0035..5bd072f 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 0124dd7..fcf0657 100644
--- a/src/include/utils/agtype.h
+++ b/src/include/utils/agtype.h
@@ -555,6 +555,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);
 agtype_value *agtype_value_from_cstring(char *str, int len);
 /* Oid accessors for AGTYPE */
 Oid get_AGTYPEOID(void);