[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2] pkl-ast: Avoid double-frees by keeping track of frees
From: |
Arsen Arsenović |
Subject: |
[PATCH v2] pkl-ast: Avoid double-frees by keeping track of frees |
Date: |
Thu, 27 Oct 2022 18:03:36 +0200 |
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25379
---
I do like those suggestions. This still passes the tests :)
Range-diff against v1:
1: 1042cc71 ! 1: 32950f77 pkl-ast: Avoid double-frees by keeping track of
frees
@@ ChangeLog
+ (pkl_ast_node_free_1): ... to here, so that we can track and avoid
+ freed nodes. Also, no longer consult IS_RECURSIVE for lifetime
+ information.
-+ (visit_and_free): New function. Frees and tracks what it freed,
-+ to avoid double frees.
+ * testsuite/poke.pkl/recursion-bad-1.pk: New test.
+ * testsuite/poke.pkl/recursion-bad-2.pk: New test.
+ * testsuite/Makefile.am (EXTRA_DIST): Add the new tests.
@@ libpoke/pkl-ast.c: pkl_ast_node_free_chain (pkl_ast_node ast)
-/* Free all allocated resources used by AST. Note that nodes marked
- as "registered", as well as their children, are not disposed. */
-+/* Mark PTR as freed in VISITATIONS and free. It is safe to call this
-+ functions on freed pointers inside VISITATIONS as well as NULLs. */
-
--void
--pkl_ast_node_free (pkl_ast_node ast)
-+static void
-+visit_and_free (gl_set_t visitations, void *ptr)
- {
-+ if (!ptr)
-+ return;
-+
-+ bool added = gl_set_add (visitations, ptr);
-+
-+ /* This one was already freed. */
-+ if (!added)
-+ return;
-+
-+ free (ptr);
-+}
-+
+/* Recursively descends down a tree, marking and freeing as it goes.
+ VISITATIONS is a set of pointers that has already been freed that this
+ function can track frees in. */
+
+-void
+-pkl_ast_node_free (pkl_ast_node ast)
++#define PKL_AST_NODE_FREE(...) \
++ pkl_ast_node_free_1 (visitations, __VA_ARGS__)
+
+static void
+pkl_ast_node_free_1 (gl_set_t visitations, pkl_ast_node ast)
-+{
+ {
+ /* Take care not to use pkl_ast_node_free here, as doing that will
result in
+ a double-free, as it throws away the current visitation set. In the
same
+ vein, take care to mark and check VISITATIONS, using visit_and_free
when
@@ libpoke/pkl-ast.c: pkl_ast_node_free_chain (pkl_ast_node ast)
+ /* Check if we already freed this one. */
+ if (gl_set_search (visitations, ast))
+ return;
++
++
++#define visit_and_free(ptr) \
++ do { \
++ if (!ptr) \
++ break; \
++ \
++ bool added = gl_set_add (visitations, ptr); \
++ \
++ /* This one was already freed. */ \
++ if (!added) \
++ return; \
++ \
++ free (ptr); \
++ } while (0)
++
+
assert (PKL_AST_REFCOUNT (ast) > 0);
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
case PKL_AST_SRC:
- free (PKL_AST_SRC_FILENAME (ast));
-+ visit_and_free (visitations, PKL_AST_SRC_FILENAME (ast));
++ visit_and_free (PKL_AST_SRC_FILENAME (ast));
break;
case PKL_AST_EXP:
for (i = 0; i < PKL_AST_EXP_NUMOPS (ast); i++)
- pkl_ast_node_free (PKL_AST_EXP_OPERAND (ast, i));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_EXP_OPERAND (ast, i));
++ PKL_AST_NODE_FREE (PKL_AST_EXP_OPERAND (ast, i));
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_COND_EXP_COND (ast));
- pkl_ast_node_free (PKL_AST_COND_EXP_THENEXP (ast));
- pkl_ast_node_free (PKL_AST_COND_EXP_ELSEEXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_COND_EXP_COND (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_COND_EXP_THENEXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_COND_EXP_ELSEEXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_COND_EXP_COND (ast));
++ PKL_AST_NODE_FREE (PKL_AST_COND_EXP_THENEXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_COND_EXP_ELSEEXP (ast));
break;
case PKL_AST_ENUM:
- pkl_ast_node_free (PKL_AST_ENUM_TAG (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ENUM_TAG (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ENUM_TAG (ast));
for (t = PKL_AST_ENUM_VALUES (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_ENUMERATOR_IDENTIFIER (ast));
- pkl_ast_node_free (PKL_AST_ENUMERATOR_VALUE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ENUMERATOR_IDENTIFIER
(ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ENUMERATOR_VALUE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ENUMERATOR_IDENTIFIER (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ENUMERATOR_VALUE (ast));
break;
case PKL_AST_TYPE:
- free (PKL_AST_TYPE_NAME (ast));
-+ visit_and_free (visitations, PKL_AST_TYPE_NAME (ast));
++ visit_and_free (PKL_AST_TYPE_NAME (ast));
switch (PKL_AST_TYPE_CODE (ast))
{
case PKL_TYPE_ARRAY:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_TYPE_A_BOUND (ast));
- pkl_ast_node_free (PKL_AST_TYPE_A_ETYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TYPE_A_BOUND (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TYPE_A_ETYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TYPE_A_BOUND (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TYPE_A_ETYPE (ast));
break;
case PKL_TYPE_STRUCT:
pvm_free_uncollectable (PKL_AST_TYPE_S_CLOSURES (ast));
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
case PKL_TYPE_FUNCTION:
- pkl_ast_node_free (PKL_AST_TYPE_F_RTYPE (ast));
- pkl_ast_node_free (PKL_AST_TYPE_F_FIRST_OPT_ARG (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TYPE_F_RTYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TYPE_F_FIRST_OPT_ARG
(ast));
++ PKL_AST_NODE_FREE (PKL_AST_TYPE_F_RTYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TYPE_F_FIRST_OPT_ARG (ast));
for (t = PKL_AST_TYPE_F_ARGS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
case PKL_TYPE_OFFSET:
- pkl_ast_node_free (PKL_AST_TYPE_O_UNIT (ast));
- pkl_ast_node_free (PKL_AST_TYPE_O_BASE_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TYPE_O_UNIT (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TYPE_O_BASE_TYPE
(ast));
++ PKL_AST_NODE_FREE (PKL_AST_TYPE_O_UNIT (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TYPE_O_BASE_TYPE (ast));
break;
case PKL_TYPE_INTEGRAL:
case PKL_TYPE_STRING:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_LABEL (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_PRE (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_POST (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_STRUCT_TYPE_FIELD_NAME
(ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_STRUCT_TYPE_FIELD_TYPE
(ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_STRUCT_TYPE_FIELD_SIZE
(ast));
-+ pkl_ast_node_free_1 (visitations,
PKL_AST_STRUCT_TYPE_FIELD_CONSTRAINT (ast));
-+ pkl_ast_node_free_1 (visitations,
PKL_AST_STRUCT_TYPE_FIELD_INITIALIZER (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_STRUCT_TYPE_FIELD_LABEL
(ast));
-+ pkl_ast_node_free_1 (visitations,
PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_PRE (ast));
-+ pkl_ast_node_free_1 (visitations,
PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_POST (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_NAME (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_SIZE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_CONSTRAINT (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_INITIALIZER (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_LABEL (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_PRE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_POST (ast));
break;
case PKL_AST_FUNC_TYPE_ARG:
- pkl_ast_node_free (PKL_AST_FUNC_TYPE_ARG_TYPE (ast));
- pkl_ast_node_free (PKL_AST_FUNC_TYPE_ARG_NAME (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNC_TYPE_ARG_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNC_TYPE_ARG_NAME (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNC_TYPE_ARG_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNC_TYPE_ARG_NAME (ast));
break;
case PKL_AST_INDEXER:
- pkl_ast_node_free (PKL_AST_INDEXER_ENTITY (ast));
- pkl_ast_node_free (PKL_AST_INDEXER_INDEX (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_INDEXER_ENTITY (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_INDEXER_INDEX (ast));
++ PKL_AST_NODE_FREE (PKL_AST_INDEXER_ENTITY (ast));
++ PKL_AST_NODE_FREE (PKL_AST_INDEXER_INDEX (ast));
break;
case PKL_AST_TRIMMER:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_TRIMMER_FROM (ast));
- pkl_ast_node_free (PKL_AST_TRIMMER_TO (ast));
- pkl_ast_node_free (PKL_AST_TRIMMER_ADDEND (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRIMMER_ENTITY (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRIMMER_FROM (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRIMMER_TO (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRIMMER_ADDEND (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRIMMER_ENTITY (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRIMMER_FROM (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRIMMER_TO (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRIMMER_ADDEND (ast));
break;
case PKL_AST_FUNC:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_FUNC_RET_TYPE (ast));
- pkl_ast_node_free (PKL_AST_FUNC_BODY (ast));
- pkl_ast_node_free (PKL_AST_FUNC_FIRST_OPT_ARG (ast));
-+ visit_and_free (visitations, PKL_AST_FUNC_NAME (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNC_RET_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNC_BODY (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNC_FIRST_OPT_ARG (ast));
++ visit_and_free (PKL_AST_FUNC_NAME (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNC_RET_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNC_BODY (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNC_FIRST_OPT_ARG (ast));
for (t = PKL_AST_FUNC_ARGS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_FUNC_ARG_TYPE (ast));
- pkl_ast_node_free (PKL_AST_FUNC_ARG_IDENTIFIER (ast));
- pkl_ast_node_free (PKL_AST_FUNC_ARG_INITIAL (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNC_ARG_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNC_ARG_IDENTIFIER
(ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNC_ARG_INITIAL (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNC_ARG_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNC_ARG_IDENTIFIER (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNC_ARG_INITIAL (ast));
break;
case PKL_AST_STRING:
- free (PKL_AST_STRING_POINTER (ast));
-+ visit_and_free (visitations, PKL_AST_STRING_POINTER (ast));
++ visit_and_free (PKL_AST_STRING_POINTER (ast));
break;
case PKL_AST_IDENTIFIER:
- free (PKL_AST_IDENTIFIER_POINTER (ast));
-+ visit_and_free (visitations, PKL_AST_IDENTIFIER_POINTER (ast));
++ visit_and_free (PKL_AST_IDENTIFIER_POINTER (ast));
break;
case PKL_AST_STRUCT_REF:
- pkl_ast_node_free (PKL_AST_STRUCT_REF_STRUCT (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_REF_IDENTIFIER (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_STRUCT_REF_STRUCT (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_STRUCT_REF_IDENTIFIER
(ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_REF_STRUCT (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_REF_IDENTIFIER (ast));
break;
case PKL_AST_STRUCT_FIELD:
- pkl_ast_node_free (PKL_AST_STRUCT_FIELD_NAME (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_FIELD_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_STRUCT_FIELD_NAME (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_STRUCT_FIELD_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_FIELD_NAME (ast));
++ PKL_AST_NODE_FREE (PKL_AST_STRUCT_FIELD_EXP (ast));
break;
case PKL_AST_STRUCT:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_ARRAY_INITIALIZER_INDEX (ast));
- pkl_ast_node_free (PKL_AST_ARRAY_INITIALIZER_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ARRAY_INITIALIZER_INDEX
(ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ARRAY_INITIALIZER_EXP
(ast));
++ PKL_AST_NODE_FREE (PKL_AST_ARRAY_INITIALIZER_INDEX (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ARRAY_INITIALIZER_EXP (ast));
break;
case PKL_AST_ARRAY:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- free (PKL_AST_DECL_SOURCE (ast));
- pkl_ast_node_free (PKL_AST_DECL_NAME (ast));
- pkl_ast_node_free (PKL_AST_DECL_INITIAL (ast));
-+ visit_and_free (visitations, PKL_AST_DECL_SOURCE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_DECL_NAME (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_DECL_INITIAL (ast));
++ visit_and_free (PKL_AST_DECL_SOURCE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_DECL_NAME (ast));
++ PKL_AST_NODE_FREE (PKL_AST_DECL_INITIAL (ast));
break;
case PKL_AST_OFFSET:
- pkl_ast_node_free (PKL_AST_OFFSET_MAGNITUDE (ast));
- pkl_ast_node_free (PKL_AST_OFFSET_UNIT (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_OFFSET_MAGNITUDE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_OFFSET_UNIT (ast));
++ PKL_AST_NODE_FREE (PKL_AST_OFFSET_MAGNITUDE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_OFFSET_UNIT (ast));
break;
case PKL_AST_CAST:
- pkl_ast_node_free (PKL_AST_CAST_TYPE (ast));
- pkl_ast_node_free (PKL_AST_CAST_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_CAST_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_CAST_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_CAST_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_CAST_EXP (ast));
break;
case PKL_AST_ISA:
- pkl_ast_node_free (PKL_AST_ISA_TYPE (ast));
- pkl_ast_node_free (PKL_AST_ISA_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ISA_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ISA_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ISA_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ISA_EXP (ast));
break;
case PKL_AST_MAP:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_MAP_TYPE (ast));
- pkl_ast_node_free (PKL_AST_MAP_IOS (ast));
- pkl_ast_node_free (PKL_AST_MAP_OFFSET (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_MAP_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_MAP_IOS (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_MAP_OFFSET (ast));
++ PKL_AST_NODE_FREE (PKL_AST_MAP_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_MAP_IOS (ast));
++ PKL_AST_NODE_FREE (PKL_AST_MAP_OFFSET (ast));
break;
case PKL_AST_CONS:
- pkl_ast_node_free (PKL_AST_CONS_TYPE (ast));
- pkl_ast_node_free (PKL_AST_CONS_VALUE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_CONS_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_CONS_VALUE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_CONS_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_CONS_VALUE (ast));
break;
case PKL_AST_FUNCALL:
- pkl_ast_node_free (PKL_AST_FUNCALL_FUNCTION (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNCALL_FUNCTION (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNCALL_FUNCTION (ast));
for (t = PKL_AST_FUNCALL_ARGS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_FUNCALL_ARG_EXP (ast));
- pkl_ast_node_free (PKL_AST_FUNCALL_ARG_NAME (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNCALL_ARG_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FUNCALL_ARG_NAME (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNCALL_ARG_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FUNCALL_ARG_NAME (ast));
break;
case PKL_AST_VAR:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_VAR_NAME (ast));
- if (!PKL_AST_VAR_IS_RECURSIVE (ast))
- pkl_ast_node_free (PKL_AST_VAR_DECL (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_VAR_NAME (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_VAR_DECL (ast));
++ PKL_AST_NODE_FREE (PKL_AST_VAR_NAME (ast));
++ PKL_AST_NODE_FREE (PKL_AST_VAR_DECL (ast));
break;
case PKL_AST_INCRDECR:
- pkl_ast_node_free (PKL_AST_INCRDECR_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_INCRDECR_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_INCRDECR_EXP (ast));
break;
case PKL_AST_LAMBDA:
- pkl_ast_node_free (PKL_AST_LAMBDA_FUNCTION (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_LAMBDA_FUNCTION (ast));
++ PKL_AST_NODE_FREE (PKL_AST_LAMBDA_FUNCTION (ast));
break;
case PKL_AST_ASM_EXP:
- pkl_ast_node_free (PKL_AST_ASM_EXP_TYPE (ast));
- pkl_ast_node_free (PKL_AST_ASM_EXP_TEMPLATE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ASM_EXP_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ASM_EXP_TEMPLATE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ASM_EXP_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ASM_EXP_TEMPLATE (ast));
for (t = PKL_AST_ASM_EXP_INPUTS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_ASS_STMT_LVALUE (ast));
- pkl_ast_node_free (PKL_AST_ASS_STMT_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ASS_STMT_LVALUE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ASS_STMT_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ASS_STMT_LVALUE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ASS_STMT_EXP (ast));
break;
case PKL_AST_IF_STMT:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_IF_STMT_EXP (ast));
- pkl_ast_node_free (PKL_AST_IF_STMT_THEN_STMT (ast));
- pkl_ast_node_free (PKL_AST_IF_STMT_ELSE_STMT (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_IF_STMT_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_IF_STMT_THEN_STMT (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_IF_STMT_ELSE_STMT (ast));
++ PKL_AST_NODE_FREE (PKL_AST_IF_STMT_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_IF_STMT_THEN_STMT (ast));
++ PKL_AST_NODE_FREE (PKL_AST_IF_STMT_ELSE_STMT (ast));
break;
case PKL_AST_LOOP_STMT:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_LOOP_STMT_BODY (ast));
- pkl_ast_node_free (PKL_AST_LOOP_STMT_HEAD (ast));
- pkl_ast_node_free (PKL_AST_LOOP_STMT_TAIL (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_LOOP_STMT_ITERATOR (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_LOOP_STMT_CONDITION
(ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_LOOP_STMT_BODY (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_LOOP_STMT_HEAD (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_LOOP_STMT_TAIL (ast));
++ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_ITERATOR (ast));
++ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_CONDITION (ast));
++ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_BODY (ast));
++ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_HEAD (ast));
++ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_TAIL (ast));
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_LOOP_STMT_ITERATOR_DECL (ast));
- pkl_ast_node_free (PKL_AST_LOOP_STMT_ITERATOR_CONTAINER (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_LOOP_STMT_ITERATOR_DECL
(ast));
-+ pkl_ast_node_free_1 (visitations,
PKL_AST_LOOP_STMT_ITERATOR_CONTAINER (ast));
++ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_ITERATOR_DECL (ast));
++ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_ITERATOR_CONTAINER (ast));
break;
case PKL_AST_RETURN_STMT:
- pkl_ast_node_free (PKL_AST_RETURN_STMT_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_RETURN_STMT_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_RETURN_STMT_EXP (ast));
break;
case PKL_AST_EXP_STMT:
- pkl_ast_node_free (PKL_AST_EXP_STMT_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_EXP_STMT_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_EXP_STMT_EXP (ast));
break;
case PKL_AST_TRY_STMT:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- pkl_ast_node_free (PKL_AST_TRY_STMT_HANDLER (ast));
- pkl_ast_node_free (PKL_AST_TRY_STMT_ARG (ast));
- pkl_ast_node_free (PKL_AST_TRY_STMT_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRY_STMT_BODY (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRY_STMT_HANDLER (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRY_STMT_ARG (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRY_STMT_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_BODY (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_HANDLER (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_ARG (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_EXP (ast));
break;
case PKL_AST_TRY_STMT_BODY:
- pkl_ast_node_free (PKL_AST_TRY_STMT_BODY_CODE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRY_STMT_BODY_CODE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_BODY_CODE (ast));
break;
case PKL_AST_TRY_STMT_HANDLER:
- pkl_ast_node_free (PKL_AST_TRY_STMT_HANDLER_CODE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TRY_STMT_HANDLER_CODE
(ast));
++ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_HANDLER_CODE (ast));
break;
case PKL_AST_FORMAT_ARG:
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
- free (PKL_AST_FORMAT_ARG_BEGIN_SC (ast));
- free (PKL_AST_FORMAT_ARG_END_SC (ast));
- pkl_ast_node_free (PKL_AST_FORMAT_ARG_EXP (ast));
-+ visit_and_free (visitations, PKL_AST_FORMAT_ARG_SUFFIX (ast));
-+ visit_and_free (visitations, PKL_AST_FORMAT_ARG_BEGIN_SC (ast));
-+ visit_and_free (visitations, PKL_AST_FORMAT_ARG_END_SC (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FORMAT_ARG_EXP (ast));
++ visit_and_free (PKL_AST_FORMAT_ARG_SUFFIX (ast));
++ visit_and_free (PKL_AST_FORMAT_ARG_BEGIN_SC (ast));
++ visit_and_free (PKL_AST_FORMAT_ARG_END_SC (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FORMAT_ARG_EXP (ast));
break;
case PKL_AST_FORMAT:
{
- free (PKL_AST_FORMAT_PREFIX (ast));
-+ visit_and_free (visitations, PKL_AST_FORMAT_PREFIX (ast));
++ visit_and_free (PKL_AST_FORMAT_PREFIX (ast));
for (t = PKL_AST_FORMAT_ARGS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
for (t = PKL_AST_FORMAT_TYPES (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
- pkl_ast_node_free (PKL_AST_FORMAT_FMT (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_FORMAT_FMT (ast));
++ PKL_AST_NODE_FREE (PKL_AST_FORMAT_FMT (ast));
break;
}
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
{
- pkl_ast_node_free (PKL_AST_PRINT_STMT_STR_EXP (ast));
- pkl_ast_node_free (PKL_AST_PRINT_STMT_FORMAT (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_PRINT_STMT_STR_EXP
(ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_PRINT_STMT_FORMAT
(ast));
++ PKL_AST_NODE_FREE (PKL_AST_PRINT_STMT_STR_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_PRINT_STMT_FORMAT (ast));
break;
}
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
case PKL_AST_RAISE_STMT:
- pkl_ast_node_free (PKL_AST_RAISE_STMT_EXP (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_RAISE_STMT_EXP (ast));
++ PKL_AST_NODE_FREE (PKL_AST_RAISE_STMT_EXP (ast));
break;
case PKL_AST_ASM_STMT:
- pkl_ast_node_free (PKL_AST_ASM_STMT_TEMPLATE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_ASM_STMT_TEMPLATE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_ASM_STMT_TEMPLATE (ast));
for (t = PKL_AST_ASM_STMT_INPUTS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
for (t = PKL_AST_ASM_STMT_OUTPUTS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
-+ pkl_ast_node_free_1 (visitations, t);
++ PKL_AST_NODE_FREE (t);
}
break;
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
}
- pkl_ast_node_free (PKL_AST_TYPE (ast));
-+ pkl_ast_node_free_1 (visitations, PKL_AST_TYPE (ast));
++ PKL_AST_NODE_FREE (PKL_AST_TYPE (ast));
+
+ /* Free this node, to match the mark above. */
free (ast);
++
++#undef visit_and_free
}
+/* Free all allocated resources used by AST. Note that nodes marked
@@ libpoke/pkl-ast.c: pkl_ast_node_free (pkl_ast_node ast)
+{
+ gl_set_t visitations = gl_set_create_empty (GL_LINKEDHASH_SET,
+ NULL, NULL, NULL);
-+ pkl_ast_node_free_1 (visitations, ast);
++ PKL_AST_NODE_FREE (ast);
+ gl_set_free (visitations);
+}
++
++/* This macro shouldn't be invoked outside of the implementation of the
++ node_free walker, other users should be calling pkl_ast_node_free. */
++#undef PKL_AST_NODE_FREE
+
/* Allocate and initialize a new AST and return it. */
ChangeLog | 13 ++
bootstrap.conf | 3 +
libpoke/pkl-ast.c | 295 +++++++++++++++-----------
testsuite/Makefile.am | 2 +
testsuite/poke.pkl/recursion-bad-1.pk | 3 +
testsuite/poke.pkl/recursion-bad-2.pk | 11 +
6 files changed, 207 insertions(+), 120 deletions(-)
create mode 100644 testsuite/poke.pkl/recursion-bad-1.pk
create mode 100644 testsuite/poke.pkl/recursion-bad-2.pk
diff --git a/ChangeLog b/ChangeLog
index 37c67b50..dd28d0ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2022-10-27 Arsen Arsenović <arsen@aarsen.me>
+
+ * bootstrap.conf (libpoke_modules): Add set, xset and
+ linkedhash-set.
+ * libpoke/pkl-ast.c (pkl_ast_node_free): Allocate a visitation
+ set, and move most code...
+ (pkl_ast_node_free_1): ... to here, so that we can track and avoid
+ freed nodes. Also, no longer consult IS_RECURSIVE for lifetime
+ information.
+ * testsuite/poke.pkl/recursion-bad-1.pk: New test.
+ * testsuite/poke.pkl/recursion-bad-2.pk: New test.
+ * testsuite/Makefile.am (EXTRA_DIST): Add the new tests.
+
2022-10-25 Arsen Arsenović <arsen@aarsen.me>
* doc/Makefile.am (AM_MAKEINFOFLAGS): Enable the
diff --git a/bootstrap.conf b/bootstrap.conf
index 8a16795c..347aa551 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -82,11 +82,14 @@ libpoke_modules="
gettime
intprops
isatty
+ linkedhash-set
mkstemp
nanosleep
printf-posix
random
secure_getenv
+ set
+ xset
snprintf
stdarg
stdbool
diff --git a/libpoke/pkl-ast.c b/libpoke/pkl-ast.c
index 2b7cff73..8663fdaa 100644
--- a/libpoke/pkl-ast.c
+++ b/libpoke/pkl-ast.c
@@ -25,6 +25,8 @@
#include <inttypes.h>
#include "string-buffer.h"
#include "xalloc.h"
+#include "gl_linkedhash_set.h"
+#include "gl_xset.h"
#include "pvm.h"
#include "pvm-alloc.h" /* For pvm_{alloc,free}_uncollectable. */
@@ -2253,18 +2255,47 @@ pkl_ast_node_free_chain (pkl_ast_node ast)
}
}
-/* Free all allocated resources used by AST. Note that nodes marked
- as "registered", as well as their children, are not disposed. */
+/* Recursively descends down a tree, marking and freeing as it goes.
+ VISITATIONS is a set of pointers that has already been freed that this
+ function can track frees in. */
-void
-pkl_ast_node_free (pkl_ast_node ast)
+#define PKL_AST_NODE_FREE(...) \
+ pkl_ast_node_free_1 (visitations, __VA_ARGS__)
+
+static void
+pkl_ast_node_free_1 (gl_set_t visitations, pkl_ast_node ast)
{
+ /* Take care not to use pkl_ast_node_free here, as doing that will result in
+ a double-free, as it throws away the current visitation set. In the same
+ vein, take care to mark and check VISITATIONS, using visit_and_free when
+ possible. */
pkl_ast_node t, n;
size_t i;
+ bool added;
if (ast == NULL)
return;
+ /* Check if we already freed this one. */
+ if (gl_set_search (visitations, ast))
+ return;
+
+
+#define visit_and_free(ptr) \
+ do { \
+ if (!ptr) \
+ break; \
+ \
+ bool added = gl_set_add (visitations, ptr); \
+ \
+ /* This one was already freed. */ \
+ if (!added) \
+ return; \
+ \
+ free (ptr); \
+ } while (0)
+
+
assert (PKL_AST_REFCOUNT (ast) > 0);
if (PKL_AST_REFCOUNT (ast) > 1)
@@ -2273,62 +2304,67 @@ pkl_ast_node_free (pkl_ast_node ast)
return;
}
+ /* OK, we need to free. Mark this node as freed (it will be actually freed
+ at the end). */
+ added = gl_set_add (visitations, ast);
+ assert (added);
+
switch (PKL_AST_CODE (ast))
{
case PKL_AST_PROGRAM:
for (t = PKL_AST_PROGRAM_ELEMS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
case PKL_AST_SRC:
- free (PKL_AST_SRC_FILENAME (ast));
+ visit_and_free (PKL_AST_SRC_FILENAME (ast));
break;
case PKL_AST_EXP:
for (i = 0; i < PKL_AST_EXP_NUMOPS (ast); i++)
- pkl_ast_node_free (PKL_AST_EXP_OPERAND (ast, i));
+ PKL_AST_NODE_FREE (PKL_AST_EXP_OPERAND (ast, i));
break;
case PKL_AST_COND_EXP:
- pkl_ast_node_free (PKL_AST_COND_EXP_COND (ast));
- pkl_ast_node_free (PKL_AST_COND_EXP_THENEXP (ast));
- pkl_ast_node_free (PKL_AST_COND_EXP_ELSEEXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_COND_EXP_COND (ast));
+ PKL_AST_NODE_FREE (PKL_AST_COND_EXP_THENEXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_COND_EXP_ELSEEXP (ast));
break;
case PKL_AST_ENUM:
- pkl_ast_node_free (PKL_AST_ENUM_TAG (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ENUM_TAG (ast));
for (t = PKL_AST_ENUM_VALUES (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
case PKL_AST_ENUMERATOR:
- pkl_ast_node_free (PKL_AST_ENUMERATOR_IDENTIFIER (ast));
- pkl_ast_node_free (PKL_AST_ENUMERATOR_VALUE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ENUMERATOR_IDENTIFIER (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ENUMERATOR_VALUE (ast));
break;
case PKL_AST_TYPE:
- free (PKL_AST_TYPE_NAME (ast));
+ visit_and_free (PKL_AST_TYPE_NAME (ast));
switch (PKL_AST_TYPE_CODE (ast))
{
case PKL_TYPE_ARRAY:
pvm_free_uncollectable (PKL_AST_TYPE_A_CLOSURES (ast));
- pkl_ast_node_free (PKL_AST_TYPE_A_BOUND (ast));
- pkl_ast_node_free (PKL_AST_TYPE_A_ETYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TYPE_A_BOUND (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TYPE_A_ETYPE (ast));
break;
case PKL_TYPE_STRUCT:
pvm_free_uncollectable (PKL_AST_TYPE_S_CLOSURES (ast));
@@ -2336,21 +2372,21 @@ pkl_ast_node_free (pkl_ast_node ast)
for (t = PKL_AST_TYPE_S_ELEMS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
case PKL_TYPE_FUNCTION:
- pkl_ast_node_free (PKL_AST_TYPE_F_RTYPE (ast));
- pkl_ast_node_free (PKL_AST_TYPE_F_FIRST_OPT_ARG (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TYPE_F_RTYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TYPE_F_FIRST_OPT_ARG (ast));
for (t = PKL_AST_TYPE_F_ARGS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
case PKL_TYPE_OFFSET:
- pkl_ast_node_free (PKL_AST_TYPE_O_UNIT (ast));
- pkl_ast_node_free (PKL_AST_TYPE_O_BASE_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TYPE_O_UNIT (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TYPE_O_BASE_TYPE (ast));
break;
case PKL_TYPE_INTEGRAL:
case PKL_TYPE_STRING:
@@ -2362,76 +2398,76 @@ pkl_ast_node_free (pkl_ast_node ast)
case PKL_AST_STRUCT_TYPE_FIELD:
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_NAME (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_TYPE (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_SIZE (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_CONSTRAINT (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_INITIALIZER (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_LABEL (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_PRE (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_POST (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_NAME (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_SIZE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_CONSTRAINT (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_INITIALIZER (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_LABEL (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_PRE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_TYPE_FIELD_OPTCOND_POST (ast));
break;
case PKL_AST_FUNC_TYPE_ARG:
- pkl_ast_node_free (PKL_AST_FUNC_TYPE_ARG_TYPE (ast));
- pkl_ast_node_free (PKL_AST_FUNC_TYPE_ARG_NAME (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNC_TYPE_ARG_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNC_TYPE_ARG_NAME (ast));
break;
case PKL_AST_INDEXER:
- pkl_ast_node_free (PKL_AST_INDEXER_ENTITY (ast));
- pkl_ast_node_free (PKL_AST_INDEXER_INDEX (ast));
+ PKL_AST_NODE_FREE (PKL_AST_INDEXER_ENTITY (ast));
+ PKL_AST_NODE_FREE (PKL_AST_INDEXER_INDEX (ast));
break;
case PKL_AST_TRIMMER:
- pkl_ast_node_free (PKL_AST_TRIMMER_ENTITY (ast));
- pkl_ast_node_free (PKL_AST_TRIMMER_FROM (ast));
- pkl_ast_node_free (PKL_AST_TRIMMER_TO (ast));
- pkl_ast_node_free (PKL_AST_TRIMMER_ADDEND (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRIMMER_ENTITY (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRIMMER_FROM (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRIMMER_TO (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRIMMER_ADDEND (ast));
break;
case PKL_AST_FUNC:
- free (PKL_AST_FUNC_NAME (ast));
- pkl_ast_node_free (PKL_AST_FUNC_RET_TYPE (ast));
- pkl_ast_node_free (PKL_AST_FUNC_BODY (ast));
- pkl_ast_node_free (PKL_AST_FUNC_FIRST_OPT_ARG (ast));
+ visit_and_free (PKL_AST_FUNC_NAME (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNC_RET_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNC_BODY (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNC_FIRST_OPT_ARG (ast));
for (t = PKL_AST_FUNC_ARGS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
case PKL_AST_FUNC_ARG:
- pkl_ast_node_free (PKL_AST_FUNC_ARG_TYPE (ast));
- pkl_ast_node_free (PKL_AST_FUNC_ARG_IDENTIFIER (ast));
- pkl_ast_node_free (PKL_AST_FUNC_ARG_INITIAL (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNC_ARG_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNC_ARG_IDENTIFIER (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNC_ARG_INITIAL (ast));
break;
case PKL_AST_STRING:
- free (PKL_AST_STRING_POINTER (ast));
+ visit_and_free (PKL_AST_STRING_POINTER (ast));
break;
case PKL_AST_IDENTIFIER:
- free (PKL_AST_IDENTIFIER_POINTER (ast));
+ visit_and_free (PKL_AST_IDENTIFIER_POINTER (ast));
break;
case PKL_AST_STRUCT_REF:
- pkl_ast_node_free (PKL_AST_STRUCT_REF_STRUCT (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_REF_IDENTIFIER (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_REF_STRUCT (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_REF_IDENTIFIER (ast));
break;
case PKL_AST_STRUCT_FIELD:
- pkl_ast_node_free (PKL_AST_STRUCT_FIELD_NAME (ast));
- pkl_ast_node_free (PKL_AST_STRUCT_FIELD_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_FIELD_NAME (ast));
+ PKL_AST_NODE_FREE (PKL_AST_STRUCT_FIELD_EXP (ast));
break;
case PKL_AST_STRUCT:
@@ -2439,14 +2475,14 @@ pkl_ast_node_free (pkl_ast_node ast)
for (t = PKL_AST_STRUCT_FIELDS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
case PKL_AST_ARRAY_INITIALIZER:
- pkl_ast_node_free (PKL_AST_ARRAY_INITIALIZER_INDEX (ast));
- pkl_ast_node_free (PKL_AST_ARRAY_INITIALIZER_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ARRAY_INITIALIZER_INDEX (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ARRAY_INITIALIZER_EXP (ast));
break;
case PKL_AST_ARRAY:
@@ -2454,92 +2490,91 @@ pkl_ast_node_free (pkl_ast_node ast)
for (t = PKL_AST_ARRAY_INITIALIZERS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
case PKL_AST_DECL:
- free (PKL_AST_DECL_SOURCE (ast));
- pkl_ast_node_free (PKL_AST_DECL_NAME (ast));
- pkl_ast_node_free (PKL_AST_DECL_INITIAL (ast));
+ visit_and_free (PKL_AST_DECL_SOURCE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_DECL_NAME (ast));
+ PKL_AST_NODE_FREE (PKL_AST_DECL_INITIAL (ast));
break;
case PKL_AST_OFFSET:
- pkl_ast_node_free (PKL_AST_OFFSET_MAGNITUDE (ast));
- pkl_ast_node_free (PKL_AST_OFFSET_UNIT (ast));
+ PKL_AST_NODE_FREE (PKL_AST_OFFSET_MAGNITUDE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_OFFSET_UNIT (ast));
break;
case PKL_AST_CAST:
- pkl_ast_node_free (PKL_AST_CAST_TYPE (ast));
- pkl_ast_node_free (PKL_AST_CAST_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_CAST_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_CAST_EXP (ast));
break;
case PKL_AST_ISA:
- pkl_ast_node_free (PKL_AST_ISA_TYPE (ast));
- pkl_ast_node_free (PKL_AST_ISA_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ISA_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ISA_EXP (ast));
break;
case PKL_AST_MAP:
- pkl_ast_node_free (PKL_AST_MAP_TYPE (ast));
- pkl_ast_node_free (PKL_AST_MAP_IOS (ast));
- pkl_ast_node_free (PKL_AST_MAP_OFFSET (ast));
+ PKL_AST_NODE_FREE (PKL_AST_MAP_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_MAP_IOS (ast));
+ PKL_AST_NODE_FREE (PKL_AST_MAP_OFFSET (ast));
break;
case PKL_AST_CONS:
- pkl_ast_node_free (PKL_AST_CONS_TYPE (ast));
- pkl_ast_node_free (PKL_AST_CONS_VALUE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_CONS_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_CONS_VALUE (ast));
break;
case PKL_AST_FUNCALL:
- pkl_ast_node_free (PKL_AST_FUNCALL_FUNCTION (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNCALL_FUNCTION (ast));
for (t = PKL_AST_FUNCALL_ARGS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
case PKL_AST_FUNCALL_ARG:
- pkl_ast_node_free (PKL_AST_FUNCALL_ARG_EXP (ast));
- pkl_ast_node_free (PKL_AST_FUNCALL_ARG_NAME (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNCALL_ARG_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FUNCALL_ARG_NAME (ast));
break;
case PKL_AST_VAR:
- pkl_ast_node_free (PKL_AST_VAR_NAME (ast));
- if (!PKL_AST_VAR_IS_RECURSIVE (ast))
- pkl_ast_node_free (PKL_AST_VAR_DECL (ast));
+ PKL_AST_NODE_FREE (PKL_AST_VAR_NAME (ast));
+ PKL_AST_NODE_FREE (PKL_AST_VAR_DECL (ast));
break;
case PKL_AST_INCRDECR:
- pkl_ast_node_free (PKL_AST_INCRDECR_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_INCRDECR_EXP (ast));
break;
case PKL_AST_LAMBDA:
- pkl_ast_node_free (PKL_AST_LAMBDA_FUNCTION (ast));
+ PKL_AST_NODE_FREE (PKL_AST_LAMBDA_FUNCTION (ast));
break;
case PKL_AST_ASM_EXP:
- pkl_ast_node_free (PKL_AST_ASM_EXP_TYPE (ast));
- pkl_ast_node_free (PKL_AST_ASM_EXP_TEMPLATE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ASM_EXP_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ASM_EXP_TEMPLATE (ast));
for (t = PKL_AST_ASM_EXP_INPUTS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
@@ -2549,97 +2584,97 @@ pkl_ast_node_free (pkl_ast_node ast)
for (t = PKL_AST_COMP_STMT_STMTS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
case PKL_AST_ASS_STMT:
- pkl_ast_node_free (PKL_AST_ASS_STMT_LVALUE (ast));
- pkl_ast_node_free (PKL_AST_ASS_STMT_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ASS_STMT_LVALUE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ASS_STMT_EXP (ast));
break;
case PKL_AST_IF_STMT:
- pkl_ast_node_free (PKL_AST_IF_STMT_EXP (ast));
- pkl_ast_node_free (PKL_AST_IF_STMT_THEN_STMT (ast));
- pkl_ast_node_free (PKL_AST_IF_STMT_ELSE_STMT (ast));
+ PKL_AST_NODE_FREE (PKL_AST_IF_STMT_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_IF_STMT_THEN_STMT (ast));
+ PKL_AST_NODE_FREE (PKL_AST_IF_STMT_ELSE_STMT (ast));
break;
case PKL_AST_LOOP_STMT:
- pkl_ast_node_free (PKL_AST_LOOP_STMT_ITERATOR (ast));
- pkl_ast_node_free (PKL_AST_LOOP_STMT_CONDITION (ast));
- pkl_ast_node_free (PKL_AST_LOOP_STMT_BODY (ast));
- pkl_ast_node_free (PKL_AST_LOOP_STMT_HEAD (ast));
- pkl_ast_node_free (PKL_AST_LOOP_STMT_TAIL (ast));
+ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_ITERATOR (ast));
+ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_CONDITION (ast));
+ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_BODY (ast));
+ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_HEAD (ast));
+ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_TAIL (ast));
break;
case PKL_AST_LOOP_STMT_ITERATOR:
- pkl_ast_node_free (PKL_AST_LOOP_STMT_ITERATOR_DECL (ast));
- pkl_ast_node_free (PKL_AST_LOOP_STMT_ITERATOR_CONTAINER (ast));
+ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_ITERATOR_DECL (ast));
+ PKL_AST_NODE_FREE (PKL_AST_LOOP_STMT_ITERATOR_CONTAINER (ast));
break;
case PKL_AST_RETURN_STMT:
- pkl_ast_node_free (PKL_AST_RETURN_STMT_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_RETURN_STMT_EXP (ast));
break;
case PKL_AST_EXP_STMT:
- pkl_ast_node_free (PKL_AST_EXP_STMT_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_EXP_STMT_EXP (ast));
break;
case PKL_AST_TRY_STMT:
- pkl_ast_node_free (PKL_AST_TRY_STMT_BODY (ast));
- pkl_ast_node_free (PKL_AST_TRY_STMT_HANDLER (ast));
- pkl_ast_node_free (PKL_AST_TRY_STMT_ARG (ast));
- pkl_ast_node_free (PKL_AST_TRY_STMT_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_BODY (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_HANDLER (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_ARG (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_EXP (ast));
break;
case PKL_AST_TRY_STMT_BODY:
- pkl_ast_node_free (PKL_AST_TRY_STMT_BODY_CODE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_BODY_CODE (ast));
break;
case PKL_AST_TRY_STMT_HANDLER:
- pkl_ast_node_free (PKL_AST_TRY_STMT_HANDLER_CODE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TRY_STMT_HANDLER_CODE (ast));
break;
case PKL_AST_FORMAT_ARG:
- free (PKL_AST_FORMAT_ARG_SUFFIX (ast));
- free (PKL_AST_FORMAT_ARG_BEGIN_SC (ast));
- free (PKL_AST_FORMAT_ARG_END_SC (ast));
- pkl_ast_node_free (PKL_AST_FORMAT_ARG_EXP (ast));
+ visit_and_free (PKL_AST_FORMAT_ARG_SUFFIX (ast));
+ visit_and_free (PKL_AST_FORMAT_ARG_BEGIN_SC (ast));
+ visit_and_free (PKL_AST_FORMAT_ARG_END_SC (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FORMAT_ARG_EXP (ast));
break;
case PKL_AST_FORMAT:
{
- free (PKL_AST_FORMAT_PREFIX (ast));
+ visit_and_free (PKL_AST_FORMAT_PREFIX (ast));
for (t = PKL_AST_FORMAT_ARGS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
for (t = PKL_AST_FORMAT_TYPES (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
- pkl_ast_node_free (PKL_AST_FORMAT_FMT (ast));
+ PKL_AST_NODE_FREE (PKL_AST_FORMAT_FMT (ast));
break;
}
case PKL_AST_PRINT_STMT:
{
- pkl_ast_node_free (PKL_AST_PRINT_STMT_STR_EXP (ast));
- pkl_ast_node_free (PKL_AST_PRINT_STMT_FORMAT (ast));
+ PKL_AST_NODE_FREE (PKL_AST_PRINT_STMT_STR_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_PRINT_STMT_FORMAT (ast));
break;
}
@@ -2649,22 +2684,22 @@ pkl_ast_node_free (pkl_ast_node ast)
case PKL_AST_RAISE_STMT:
- pkl_ast_node_free (PKL_AST_RAISE_STMT_EXP (ast));
+ PKL_AST_NODE_FREE (PKL_AST_RAISE_STMT_EXP (ast));
break;
case PKL_AST_ASM_STMT:
- pkl_ast_node_free (PKL_AST_ASM_STMT_TEMPLATE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_ASM_STMT_TEMPLATE (ast));
for (t = PKL_AST_ASM_STMT_INPUTS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
for (t = PKL_AST_ASM_STMT_OUTPUTS (ast); t; t = n)
{
n = PKL_AST_CHAIN (t);
- pkl_ast_node_free (t);
+ PKL_AST_NODE_FREE (t);
}
break;
@@ -2679,10 +2714,30 @@ pkl_ast_node_free (pkl_ast_node ast)
assert (0);
}
- pkl_ast_node_free (PKL_AST_TYPE (ast));
+ PKL_AST_NODE_FREE (PKL_AST_TYPE (ast));
+
+ /* Free this node, to match the mark above. */
free (ast);
+
+#undef visit_and_free
}
+/* Free all allocated resources used by AST. Note that nodes marked
+ as "registered", as well as their children, are not disposed. */
+
+void
+pkl_ast_node_free (pkl_ast_node ast)
+{
+ gl_set_t visitations = gl_set_create_empty (GL_LINKEDHASH_SET,
+ NULL, NULL, NULL);
+ PKL_AST_NODE_FREE (ast);
+ gl_set_free (visitations);
+}
+
+/* This macro shouldn't be invoked outside of the implementation of the
+ node_free walker, other users should be calling pkl_ast_node_free. */
+#undef PKL_AST_NODE_FREE
+
/* Allocate and initialize a new AST and return it. */
pkl_ast
@@ -3198,7 +3253,7 @@ pkl_ast_print_1 (FILE *fp, pkl_ast_node ast, int indent)
PRINT_AST_SUBAST (name, STRUCT_TYPE_FIELD_NAME);
PRINT_AST_SUBAST (type, STRUCT_TYPE_FIELD_TYPE);
PRINT_AST_IMM (computed_p, STRUCT_TYPE_FIELD_COMPUTED_P, "%d");
- PRINT_AST_SUBAST (type, STRUCT_TYPE_FIELD_SIZE);
+ PRINT_AST_SUBAST (size, STRUCT_TYPE_FIELD_SIZE);
PRINT_AST_SUBAST (exp, STRUCT_TYPE_FIELD_CONSTRAINT);
PRINT_AST_SUBAST (exp, STRUCT_TYPE_FIELD_INITIALIZER);
PRINT_AST_SUBAST (exp, STRUCT_TYPE_FIELD_LABEL);
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 20a4ffa8..de61ea44 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -2041,6 +2041,8 @@ EXTRA_DIST = \
poke.pkl/raise-6.pk \
poke.pkl/raise-diag-1.pk \
poke.pkl/rand-1.pk \
+ poke.pkl/recursion-bad-1.pk \
+ poke.pkl/recursion-bad-2.pk \
poke.pkl/redef-diag-1.pk \
poke.pkl/redef-diag-2.pk \
poke.pkl/redef-diag-3.pk \
diff --git a/testsuite/poke.pkl/recursion-bad-1.pk
b/testsuite/poke.pkl/recursion-bad-1.pk
new file mode 100644
index 00000000..0793a595
--- /dev/null
+++ b/testsuite/poke.pkl/recursion-bad-1.pk
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* https://sourceware.org/bugzilla/show_bug.cgi?id=25379 */
+{ fun foo = void: { foo (); } /* { dg-error "syntax error" } */
diff --git a/testsuite/poke.pkl/recursion-bad-2.pk
b/testsuite/poke.pkl/recursion-bad-2.pk
new file mode 100644
index 00000000..26deb983
--- /dev/null
+++ b/testsuite/poke.pkl/recursion-bad-2.pk
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* Test that an error while typifying does not result in bad recursive frees.
+*/
+"xxx" in [1]; /* { dg-error "" } */
+
+fun fact = (uint<4> a) uint<64>:
+ {
+ if (a == 0)
+ return 1;
+ return a * fact (a);
+ }
--
2.38.1