Esempio n. 1
0
void
test_add (void)
{
	char   **env = NULL, **ret;
	size_t   len = 0;

	TEST_FUNCTION ("environ_add");

	/* Check that we can add a variable to a new environment table
	 * and that it is appended to the array.
	 */
	TEST_FEATURE ("with empty table");
	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
		}

		ret = environ_add (&env, NULL, &len, TRUE, "FOO=BAR");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);

			TEST_EQ (len, 0);
			TEST_EQ_P (env[0], NULL);

			nih_free (env);
			continue;
		}

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 1);
		TEST_ALLOC_PARENT (env[0], env);
		TEST_ALLOC_SIZE (env[0], 8);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_P (env[1], NULL);

		nih_free (env);
	}


	/* Check that we can add a variable to an environment table with
	 * existing different entries and that it is appended to the array.
	 */
	TEST_FEATURE ("with new variable");
	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
		}

		ret = environ_add (&env, NULL, &len, TRUE,
				   "FRODO=BAGGINS");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);

			TEST_EQ (len, 2);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_P (env[2], NULL);

			nih_free (env);
			continue;
		}

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 3);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_ALLOC_PARENT (env[2], env);
		TEST_ALLOC_SIZE (env[2], 14);
		TEST_EQ_STR (env[2], "FRODO=BAGGINS");
		TEST_EQ_P (env[3], NULL);

		nih_free (env);
	}


	/* Check that we can add a variable from the environment to the table
	 * and that it is appended to the array.
	 */
	TEST_FEATURE ("with new variable from environment");
	putenv ("FRODO=BAGGINS");

	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
		}

		ret = environ_add (&env, NULL, &len, TRUE,
				   "FRODO");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);

			TEST_EQ (len, 2);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_P (env[2], NULL);

			nih_free (env);
			continue;
		}

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 3);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_ALLOC_PARENT (env[2], env);
		TEST_ALLOC_SIZE (env[2], 14);
		TEST_EQ_STR (env[2], "FRODO=BAGGINS");
		TEST_EQ_P (env[3], NULL);

		nih_free (env);
	}

	unsetenv ("FRODO");


	/* Check that when we attempt to add a variable that's not in the
	 * environment, the table is not extended.
	 */
	TEST_FEATURE ("with new variable unset in environment");
	unsetenv ("FRODO");

	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
		}

		ret = environ_add (&env, NULL, &len, TRUE,
				   "FRODO");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);

			TEST_EQ (len, 2);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_P (env[2], NULL);

			nih_free (env);
			continue;
		}

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 2);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_EQ_P (env[2], NULL);

		nih_free (env);
	}


	/* Check that we can replace a variable in the environment table
	 * when one already exists with the same or different value.
	 */
	TEST_FEATURE ("with replacement variable");
	TEST_ALLOC_FAIL {
		char *old_env;

		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "FRODO=BAGGINS"));
		}

		old_env = env[1];
		TEST_FREE_TAG (old_env);

		ret = environ_add (&env, NULL, &len, TRUE,
				   "BAR=WIBBLE");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);
			TEST_NOT_FREE (old_env);

			TEST_EQ (len, 3);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_STR (env[2], "FRODO=BAGGINS");
			TEST_EQ_P (env[3], NULL);

			nih_free (env);
			continue;
		}

		TEST_FREE (old_env);

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 3);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_ALLOC_PARENT (env[1], env);
		TEST_ALLOC_SIZE (env[1], 11);
		TEST_EQ_STR (env[1], "BAR=WIBBLE");
		TEST_EQ_STR (env[2], "FRODO=BAGGINS");
		TEST_EQ_P (env[3], NULL);

		nih_free (env);
	}


	/* Check that we can replace a variable from the environment in the
	 * environment table when one already exists with the same or
	 * different value.
	 */
	TEST_FEATURE ("with replacement variable from environment");
	putenv ("BAR=WIBBLE");

	TEST_ALLOC_FAIL {
		char *old_env;

		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "FRODO=BAGGINS"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BILBO=TOOK"));
		}

		old_env = env[1];
		TEST_FREE_TAG (old_env);

		ret = environ_add (&env, NULL, &len, TRUE, "BAR");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);
			TEST_NOT_FREE (old_env);

			TEST_EQ (len, 4);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_STR (env[2], "FRODO=BAGGINS");
			TEST_EQ_STR (env[3], "BILBO=TOOK");
			TEST_EQ_P (env[4], NULL);

			nih_free (env);
			continue;
		}

		TEST_FREE (old_env);

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 4);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_ALLOC_PARENT (env[1], env);
		TEST_ALLOC_SIZE (env[1], 11);
		TEST_EQ_STR (env[1], "BAR=WIBBLE");
		TEST_EQ_STR (env[2], "FRODO=BAGGINS");
		TEST_EQ_STR (env[3], "BILBO=TOOK");
		TEST_EQ_P (env[4], NULL);

		nih_free (env);
	}

	unsetenv ("BAR");


	/* Check that when we attempt to replace a variable that's unset
	 * in the environment, the existing variable is removed from the
	 * table.
	 */
	TEST_FEATURE ("with replacement variable unset in environment");
	unsetenv ("BAR");

	TEST_ALLOC_FAIL {
		char *old_env;

		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "FRODO=BAGGINS"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BILBO=TOOK"));
		}

		old_env = env[1];
		TEST_FREE_TAG (old_env);

		ret = environ_add (&env, NULL, &len, TRUE, "BAR");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);
			TEST_NOT_FREE (old_env);

			TEST_EQ (len, 4);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_STR (env[2], "FRODO=BAGGINS");
			TEST_EQ_STR (env[3], "BILBO=TOOK");
			TEST_EQ_P (env[4], NULL);

			nih_free (env);
			continue;
		}

		TEST_FREE (old_env);

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 3);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "FRODO=BAGGINS");
		TEST_EQ_STR (env[2], "BILBO=TOOK");
		TEST_EQ_P (env[3], NULL);

		nih_free (env);
	}

	unsetenv ("BAR");


	/* Check that we can add a variable to an environment table with
	 * existing different entries and that it is appended to the array,
	 * even if replace is FALSE.
	 */
	TEST_FEATURE ("with new variable but no replace");
	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
		}

		ret = environ_add (&env, NULL, &len, FALSE,
				   "FRODO=BAGGINS");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);

			TEST_EQ (len, 2);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_P (env[2], NULL);

			nih_free (env);
			continue;
		}

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 3);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_ALLOC_PARENT (env[2], env);
		TEST_ALLOC_SIZE (env[2], 14);
		TEST_EQ_STR (env[2], "FRODO=BAGGINS");
		TEST_EQ_P (env[3], NULL);

		nih_free (env);
	}


	/* Check that when a variable already exists in the environment
	 * table, and we're not replacing, the original value is left
	 * untouched.
	 */
	TEST_FEATURE ("with existing variable");
	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "FRODO=BAGGINS"));
		}

		ret = environ_add (&env, NULL, &len, FALSE,
				   "BAR=WIBBLE");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);

			TEST_EQ (len, 3);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_STR (env[2], "FRODO=BAGGINS");
			TEST_EQ_P (env[3], NULL);

			nih_free (env);
			continue;
		}

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 3);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_EQ_STR (env[2], "FRODO=BAGGINS");
		TEST_EQ_P (env[3], NULL);

		nih_free (env);
	}


	/* Check that when a variable from the environment already exists in
	 * the environment table, and we're not replacing, the original value
	 * is left untouched.
	 */
	TEST_FEATURE ("with existing variable from environment");
	putenv ("BAR=WIBBLE");

	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "FRODO=BAGGINS"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BILBO=TOOK"));
		}

		ret = environ_add (&env, NULL, &len, FALSE, "BAR");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);

			TEST_EQ (len, 4);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_STR (env[2], "FRODO=BAGGINS");
			TEST_EQ_STR (env[3], "BILBO=TOOK");
			TEST_EQ_P (env[4], NULL);

			nih_free (env);
			continue;
		}

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 4);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_EQ_STR (env[2], "FRODO=BAGGINS");
		TEST_EQ_STR (env[3], "BILBO=TOOK");
		TEST_EQ_P (env[4], NULL);

		nih_free (env);
	}

	unsetenv ("BAR");


	/* Check that when a variable from the environment is unset it
	 * does not remove an existing variable in the environment table
	 * if we're not replacing.
	 */
	TEST_FEATURE ("with existing variable unset in environment");
	unsetenv ("BAR");

	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (nih_str_array_add (&env, NULL, &len,
						   "FOO=BAR"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BAR=BAZ"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "FRODO=BAGGINS"));
			assert (nih_str_array_add (&env, NULL, &len,
						   "BILBO=TOOK"));
		}

		ret = environ_add (&env, NULL, &len, FALSE, "BAR");

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);

			TEST_EQ (len, 4);
			TEST_EQ_STR (env[0], "FOO=BAR");
			TEST_EQ_STR (env[1], "BAR=BAZ");
			TEST_EQ_STR (env[2], "FRODO=BAGGINS");
			TEST_EQ_STR (env[3], "BILBO=TOOK");
			TEST_EQ_P (env[4], NULL);

			nih_free (env);
			continue;
		}

		TEST_NE_P (ret, NULL);

		TEST_EQ (len, 4);
		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_EQ_STR (env[2], "FRODO=BAGGINS");
		TEST_EQ_STR (env[3], "BILBO=TOOK");
		TEST_EQ_P (env[4], NULL);

		nih_free (env);
	}

	unsetenv ("BAR");
}
Esempio n. 2
0
void
test_append (void)
{
	char   **env = NULL, **new_env, **ret;
	size_t   len = 0;

	TEST_FUNCTION ("environ_append");

	/* Check that we can append all new entries onto the end of an
	 * existing environment table, without modifying the entries passed.
	 */
	TEST_FEATURE ("with new entries");
	new_env = nih_str_array_new (NULL);
	assert (environ_add (&new_env, NULL, NULL, TRUE, "MILK=white"));
	assert (environ_add (&new_env, NULL, NULL, TRUE, "TEA=green"));

	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (environ_add (&env, NULL, &len, TRUE, "FOO=BAR"));
			assert (environ_add (&env, NULL, &len, TRUE, "BAR=BAZ"));
		}

		ret = environ_append (&env, NULL, &len, TRUE, new_env);

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);
			nih_free (env);
			continue;
		}

		TEST_EQ_P (ret, env);
		TEST_EQ (len, 4);

		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_EQ_STR (env[2], "MILK=white");
		TEST_EQ_STR (env[3], "TEA=green");
		TEST_EQ_P (env[4], NULL);

		nih_free (env);
	}

	nih_free (new_env);


	/* Check that if entries are being replaced, those values from the
	 * new table replace the values in the old table.
	 */
	TEST_FEATURE ("with replacement entries");
	new_env = nih_str_array_new (NULL);
	assert (environ_add (&new_env, NULL, NULL, TRUE, "MILK=white"));
	assert (environ_add (&new_env, NULL, NULL, TRUE, "TEA=green"));
	assert (environ_add (&new_env, NULL, NULL, TRUE, "FOO=apricot"));

	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (environ_add (&env, NULL, &len, TRUE, "FOO=BAR"));
			assert (environ_add (&env, NULL, &len, TRUE, "BAR=BAZ"));
		}

		ret = environ_append (&env, NULL, &len, TRUE, new_env);

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);
			nih_free (env);
			continue;
		}

		TEST_EQ_P (ret, env);
		TEST_EQ (len, 4);

		TEST_EQ_STR (env[0], "FOO=apricot");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_EQ_STR (env[2], "MILK=white");
		TEST_EQ_STR (env[3], "TEA=green");
		TEST_EQ_P (env[4], NULL);

		nih_free (env);
	}

	nih_free (new_env);


	/* Check that if entries are being preserved, those values from the
	 * new table are ignored.
	 */
	TEST_FEATURE ("with preserve existing entries");
	new_env = nih_str_array_new (NULL);
	assert (environ_add (&new_env, NULL, NULL, TRUE, "MILK=white"));
	assert (environ_add (&new_env, NULL, NULL, TRUE, "TEA=green"));
	assert (environ_add (&new_env, NULL, NULL, TRUE, "FOO=apricot"));

	TEST_ALLOC_FAIL {
		TEST_ALLOC_SAFE {
			len = 0;
			env = nih_str_array_new (NULL);
			assert (environ_add (&env, NULL, &len, TRUE, "FOO=BAR"));
			assert (environ_add (&env, NULL, &len, TRUE, "BAR=BAZ"));
		}

		ret = environ_append (&env, NULL, &len, FALSE, new_env);

		if (test_alloc_failed) {
			TEST_EQ_P (ret, NULL);
			nih_free (env);
			continue;
		}

		TEST_EQ_P (ret, env);
		TEST_EQ (len, 4);

		TEST_EQ_STR (env[0], "FOO=BAR");
		TEST_EQ_STR (env[1], "BAR=BAZ");
		TEST_EQ_STR (env[2], "MILK=white");
		TEST_EQ_STR (env[3], "TEA=green");
		TEST_EQ_P (env[4], NULL);

		nih_free (env);
	}

	nih_free (new_env);
}
Esempio n. 3
0
int main(int argc, char *argv[])
{
    node_t *env_handle = NULL, *ARGV;
    int status = 0;
    memory_state_t ms;

    node_memstate_init(&ms, libc_malloc_wrap, libc_free_wrap, NULL);

    if(argc < 2) {
        goto cleanup;
    }

    dbgtrace_setstream(g_stream_stdout);
    dbgtrace_enable( 0
                     //| TC_MEM_ALLOC
                     //| TC_GC_TRACING
                     //| TC_MEM_RC
                     //| TC_GC_VERBOSE
                     //| TC_NODE_GC
                     //| TC_NODE_INIT
                     //| TC_EVAL
                     //| TC_FMC_ALLOC
                   );

    /* initialize environment */
    env_handle = node_lockroot(node_handle_new(&ms, NULL));

    {
        node_t *name, *val;
        name = node_symbol_new(&ms, "_load-lib");
        val = node_foreign_new(&ms, foreign_loadlib);
        environ_add(env_handle, name, val);

        name = node_symbol_new(&ms, "_read-eval");
        val = node_foreign_new(&ms, foreign_read_eval);
        environ_add(env_handle, name, val);

        // NB: argv[0] is interp name
        ARGV = generate_argv(&ms, argc-1, argv+1);
        environ_add(env_handle, node_symbol_new(&ms, "ARGV"), ARGV);

        environ_add_builtins(env_handle, startenv, ARR_LEN(startenv));
    }

    {
        node_t *eval_in_hdl, *eval_out_hdl;
        eval_err_t eval_stat;

        eval_in_hdl = node_lockroot(node_handle_new(&ms, NULL));
        eval_out_hdl = node_lockroot(node_handle_new(&ms, NULL));

        /* bootstrap routine:
          ( _read-eval ( quote ARGV[0] ) )

          ( _read-eval . ( ( quote . ( ARGV[0] . () ) ) . () ) )
        */
        {
            node_t *quote_call;

            quote_call = node_cons_new(&ms,
                                       node_symbol_new(&ms, "quote"),
                                       node_cons_new(&ms,
                                               node_cons_car(ARGV),
                                               NULL
                                                    )
                                      );

            node_handle_update(eval_in_hdl,
                               node_cons_new(&ms,
                                             node_symbol_new(&ms, "_read-eval"),
                                             node_cons_new(&ms,
                                                     quote_call,
                                                     NULL
                                                          )
                                            )
                              );
        }

        eval_stat = eval(&ms, env_handle, eval_in_hdl, eval_out_hdl);
        if(eval_stat != EVAL_OK) {
            status = eval_stat;
        }

        node_droproot(eval_in_hdl);
        node_droproot(eval_out_hdl);
    }

cleanup:
    if(getenv("PAREN_FINALENV")) {
        environ_print(env_handle, g_stream_stdout);
    }

    if(getenv("PAREN_MEMSTAT")) {
        printf("total alloc: %llu total free: %llu iters: %llu cycles: %llu\n",
               (unsigned long long) memory_gc_count_total(&ms),
               (unsigned long long) memory_gc_count_free(&ms),
               (unsigned long long) memory_gc_count_iters(&ms),
               (unsigned long long) memory_gc_count_cycles(&ms));
    }

    if(getenv("PAREN_LEAK_CHECK")) {
        uintptr_t total_alloc, free_alloc;
        memory_gc_cycle(&ms);
        memory_gc_cycle(&ms);
        total_alloc = memory_gc_count_total(&ms);
        free_alloc = memory_gc_count_free(&ms);
        if(total_alloc != free_alloc) {
            printf("warning: %llu allocations remain at exit!\n",
                   (unsigned long long) (total_alloc - free_alloc));
        }
    }

    if(getenv("PAREN_DUMPMEM")) {
        memory_gc_print_state(&ms, g_stream_stdout);
    }

    memory_state_reset(&ms);

    return status;
}