Пример #1
0
void
test_local (void)
{
	void *parent;
	void *_ptr;

	TEST_GROUP ("nih_local");


	/* Make sure that when a variable goes out of scope, it's freed. */
	TEST_FEATURE ("with variable going out of scope");
	do {
		nih_local void *ptr;

		ptr = nih_alloc (NULL, 100);

		nih_alloc_set_destructor (ptr, destructor_called);
		destructor_was_called = 0;
	} while (0);

	TEST_TRUE (destructor_was_called);


	/* Make sure that if a variable is referenced while in scope, it
	 * is not freed.
	 */
	TEST_FEATURE ("with referenced variable");
	parent = nih_alloc (NULL, 100);

	do {
		nih_local void *ptr;

		ptr = nih_alloc (NULL, 100);
		nih_ref (ptr, parent);
		_ptr = ptr;

		nih_alloc_set_destructor (ptr, destructor_called);
		destructor_was_called = 0;
	} while (0);

	TEST_FALSE (destructor_was_called);
	TEST_ALLOC_PARENT (_ptr, parent);

	nih_free (parent);


	/* Make sure we don't need to allocate the variable. */
	TEST_FEATURE ("with NULL variable");
	do {
		nih_local void *ptr = NULL;
	} while (0);
}
Пример #2
0
/**
 * type_var_new:
 * @parent: parent object for new structure,
 * @type: C type,
 * @name: variable name.
 *
 * Allocates and returns a new TypeVar structure with the C type @type
 * and variable name @name, the strucure is not placed into any linked
 * list but will be removed from its containing list when freed.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned structure.  When all parents
 * of the returned structure are freed, the returned structure will also be
 * freed.
 *
 * Returns: the new TypeVar structure or NULL if insufficient memory.
 **/
TypeVar *
type_var_new (const void *parent,
	      const char *type,
	      const char *name)
{
	TypeVar *var;

	nih_assert (type != NULL);
	nih_assert (name != NULL);

	var = nih_new (parent, TypeVar);
	if (! var)
		return NULL;

	nih_list_init (&var->entry);

	var->type = nih_strdup (var, type);
	if (! var->type) {
		nih_free (var);
		return NULL;
	}

	var->name = nih_strdup (var, name);
	if (! var->name) {
		nih_free (var);
		return NULL;
	}

	var->array = FALSE;

	nih_alloc_set_destructor (var, nih_list_destroy);

	return var;
}
Пример #3
0
/**
 * nih_error_steal:
 *
 * Returns the last unhandled error from the current context, and removes
 * it from the error context.  To re-raise, it must be given to
 * nih_error_raise_error().
 *
 * Returns: error object from current context.
 **/
NihError *
nih_error_steal (void)
{
	NihError *error;

	nih_assert (context_stack != NULL);
	nih_assert (CURRENT_CONTEXT->error != NULL);

	error = CURRENT_CONTEXT->error;
	CURRENT_CONTEXT->error = NULL;

	nih_alloc_set_destructor (error, NULL);

	return error;
}
Пример #4
0
/**
 * session_new:
 * @parent: parent,
 * @chroot: full chroot path,
 * @user: user id.
 *
 * Create a new session.
 *
 * Return new Session, or NULL on error.
 **/
Session *
session_new (const void *parent,
	     const char *chroot,
	     uid_t       user)
{
	Session *session;

	nih_assert ((chroot != NULL) || (user != 0));

	session_init ();

	session = nih_new (parent, Session);
	if (! session)
		return NULL;

	nih_list_init (&session->entry);

	if (chroot) {
		session->chroot = nih_strdup (session, chroot);
		if (! session->chroot) {
			nih_free (session);
			return NULL;
		}
	} else {
		session->chroot = NULL;
	}

	session->user = user;

	session->conf_path = NULL;

	nih_alloc_set_destructor (session, nih_list_destroy);

	nih_list_add (sessions, &session->entry);

	return session;
}
Пример #5
0
/**
 * _nih_error_raise_error:
 * @filename: filename where the error was raised,
 * @line: line number of @filename where the error was raised,
 * @function: function name the error was raised within,
 * @error: existing object to raise.
 *
 * Raises the existing error object in the current error context,
 * if an unhandled error already exists then an error message is emmitted
 * through the logging system; you should try to avoid this.
 *
 * This is normally used to raise a taken error that has not been handled,
 * or to raise a custom error object.
 *
 * The destructor of @error will be overwritten so that the context can
 * be cleared when the error is freed.
 *
 * This function should never be called directly, instead use the
 * nih_error_raise_error() macro to pass the correct arguments for @filename,
 * @line and @function.
 **/
void
_nih_error_raise_error (const char *filename,
			int         line,
			const char *function,
			NihError *  error)
{
	nih_assert (filename != NULL);
	nih_assert (line > 0);
	nih_assert (function != NULL);
	nih_assert (error != NULL);
	nih_assert (error->number > 0);
	nih_assert (error->message != NULL);

	nih_error_init ();
	nih_error_clear ();

	error->filename = filename;
	error->line = line;
	error->function = function;

	CURRENT_CONTEXT->error = error;

	nih_alloc_set_destructor (error, nih_error_destroy);
}
Пример #6
0
void
test_unref (void)
{
	void *ptr1;
	void *ptr2;
	void *ptr3;

	TEST_FUNCTION ("nih_unref");


	/* Check that we can remove a reference from an object with multiple
	 * parents, which means the object will not be freed.
	 */
	TEST_FEATURE ("with multiple parents");
	ptr1 = nih_alloc (NULL, 100);
	memset (ptr1, 'x', 100);

	ptr2 = nih_alloc (ptr1, 100);
	memset (ptr2, 'y', 100);

	ptr3 = nih_alloc (NULL, 100);
	memset (ptr2, 'z', 100);

	nih_ref (ptr2, ptr3);

	nih_alloc_set_destructor (ptr2, destructor_called);
	destructor_was_called = 0;

	nih_unref (ptr2, ptr1);

	TEST_FALSE (destructor_was_called);
	TEST_ALLOC_PARENT (ptr2, ptr3);

	nih_free (ptr1);
	nih_free (ptr3);


	/* Check that when we remove the last reference from an object,
	 * the object is freed.
	 */
	TEST_FEATURE ("with last parent");
	ptr1 = nih_alloc (NULL, 100);
	memset (ptr1, 'x', 100);

	ptr2 = nih_alloc (ptr1, 100);
	memset (ptr2, 'y', 100);

	nih_alloc_set_destructor (ptr2, destructor_called);
	destructor_was_called = 0;

	nih_unref (ptr2, ptr1);

	TEST_TRUE (destructor_was_called);

	nih_free (ptr1);


	/* Check that we have to remove the NULL reference from an object
	 * for it to be freed.
	 */
	TEST_FEATURE ("with only NULL parent");
	ptr1 = nih_alloc (NULL, 100);
	memset (ptr1, 'x', 100);

	nih_alloc_set_destructor (ptr1, destructor_called);
	destructor_was_called = 0;

	nih_unref (ptr1, NULL);

	TEST_TRUE (destructor_was_called);


	/* Check that we can remove the NULL reference leaving a reference
	 * to a different object.
	 */
	TEST_FEATURE ("with no parent and other parent");
	ptr1 = nih_alloc (NULL, 100);
	memset (ptr1, 'x', 100);

	ptr2 = nih_alloc (NULL, 100);
	memset (ptr2, 'y', 100);

	nih_ref (ptr2, ptr1);

	nih_alloc_set_destructor (ptr2, destructor_called);
	destructor_was_called = 0;

	nih_unref (ptr2, NULL);

	TEST_FALSE (destructor_was_called);

	TEST_ALLOC_PARENT (ptr2, ptr1);
	TEST_FALSE (nih_alloc_parent (ptr2, NULL));

	nih_free (ptr1);


	/* Check that an object with multiple NULL references must have
	 * them both removed before it will be freed.
	 */
	TEST_FEATURE ("with multiple NULL parents");
	ptr1 = nih_alloc (NULL, 100);
	memset (ptr1, 'x', 100);

	nih_ref (ptr1, NULL);

	nih_alloc_set_destructor (ptr1, destructor_called);
	destructor_was_called = 0;

	nih_unref (ptr1, NULL);

	TEST_FALSE (destructor_was_called);

	nih_unref (ptr1, NULL);

	TEST_TRUE (destructor_was_called);


	/* Check that an object with multiple identical references must have
	 * them both removed before it will be freed.
	 */
	TEST_FEATURE ("with multiple identical parents");
	ptr1 = nih_alloc (NULL, 100);
	memset (ptr1, 'x', 100);

	ptr2 = nih_alloc (ptr1, 100);
	memset (ptr2, 'y', 100);

	nih_ref (ptr2, ptr1);

	nih_alloc_set_destructor (ptr2, destructor_called);
	destructor_was_called = 0;

	nih_unref (ptr2, ptr1);

	TEST_FALSE (destructor_was_called);

	nih_unref (ptr2, ptr1);

	TEST_TRUE (destructor_was_called);

	nih_free (ptr1);
}
Пример #7
0
void
test_discard (void)
{
	void *ptr1;
	void *ptr2;
	int   ret;

	TEST_FUNCTION ("nih_discard");

	/* Check that nih_discard works if the block has no parent, freeing
	 * the object.  The destructor should get called and nih_discard
	 * should return that return value.
	 */
	TEST_FEATURE ("with no parent");
	ptr1 = nih_alloc (NULL, 10);
	nih_alloc_set_destructor (ptr1, destructor_called);
	destructor_was_called = 0;
	ret = nih_discard (ptr1);

	TEST_TRUE (destructor_was_called);
	TEST_EQ (ret, 2);


	/* Check that nih_discard does nothing it the block has a parent.
	 */
	TEST_FEATURE ("with parent");
	ptr2 = nih_alloc (NULL, 20);

	ptr1 = nih_alloc (ptr2, 10);
	nih_alloc_set_destructor (ptr1, destructor_called);
	destructor_was_called = 0;
	ret = nih_discard (ptr1);

	TEST_FALSE (destructor_was_called);
	TEST_EQ (ret, 0);

	nih_free (ptr2);


	/* Check that the destructor on any children also gets called, which
	 * is as good a indication as any that the children are being freed.
	 */
	TEST_FEATURE ("with destructor on child");
	ptr1 = nih_alloc (NULL, 10);
	ptr2 = nih_alloc (ptr1, 10);
	nih_alloc_set_destructor (ptr2, child_destructor_called);
	child_destructor_was_called = 0;
	ret = nih_discard (ptr1);

	TEST_TRUE (child_destructor_was_called);
	TEST_EQ (ret, 0);


	/* Check that both destructors on parent and children are called,
	 * and that the return value from nih_discard is that of the parent's.
	 */
	TEST_FEATURE ("with child and destructors");
	ptr1 = nih_alloc (NULL, 10);
	ptr2 = nih_alloc (ptr1, 10);
	nih_alloc_set_destructor (ptr1, destructor_called);
	nih_alloc_set_destructor (ptr2, child_destructor_called);
	destructor_was_called = 0;
	child_destructor_was_called = 0;
	ret = nih_discard (ptr1);

	TEST_TRUE (destructor_was_called);
	TEST_TRUE (child_destructor_was_called);
	TEST_EQ (ret, 2);
}
Пример #8
0
void
test_free (void)
{
	void *  ptr1;
	void *  ptr2;
	Parent *parent;
	int     ret;

	TEST_FUNCTION ("nih_free");

	/* Check that nih_free works if the block has no parent.  The
	 * destructor should get called and nih_free should return that
	 * return value.
	 */
	TEST_FEATURE ("with no parent");
	ptr1 = nih_alloc (NULL, 10);
	nih_alloc_set_destructor (ptr1, destructor_called);
	destructor_was_called = 0;
	ret = nih_free (ptr1);

	TEST_TRUE (destructor_was_called);
	TEST_EQ (ret, 2);


	/* Check that nih_free works if the block has a parent.  The
	 * destructor should get called and nih_free should return that
	 * return value.
	 */
	TEST_FEATURE ("with parent");
	ptr2 = nih_alloc (NULL, 20);

	ptr1 = nih_alloc (ptr2, 10);
	nih_alloc_set_destructor (ptr1, destructor_called);
	destructor_was_called = 0;
	ret = nih_free (ptr1);

	TEST_TRUE (destructor_was_called);
	TEST_EQ (ret, 2);

	nih_free (ptr2);


	/* Check that the destructor on any children also gets called, which
	 * is as good a indication as any that the children are being freed.
	 */
	TEST_FEATURE ("with destructor on child");
	ptr1 = nih_alloc (NULL, 10);
	ptr2 = nih_alloc (ptr1, 10);
	nih_alloc_set_destructor (ptr2, child_destructor_called);
	child_destructor_was_called = 0;
	ret = nih_free (ptr1);

	TEST_TRUE (child_destructor_was_called);
	TEST_EQ (ret, 0);


	/* Check that both destructors on parent and children are called,
	 * and that the return value from nih_free is that of the parent's.
	 */
	TEST_FEATURE ("with child and destructors");
	ptr1 = nih_alloc (NULL, 10);
	ptr2 = nih_alloc (ptr1, 10);
	nih_alloc_set_destructor (ptr1, destructor_called);
	nih_alloc_set_destructor (ptr2, child_destructor_called);
	destructor_was_called = 0;
	child_destructor_was_called = 0;
	ret = nih_free (ptr1);

	TEST_TRUE (destructor_was_called);
	TEST_TRUE (child_destructor_was_called);
	TEST_EQ (ret, 2);


	/* Check that a child of an object may be included in a sibling
	 * linked list allocated earlier.  At the point the child destructor
	 * is called, the sibling must not have been freed otherwise it
	 * cannot cut itself out.
	 */
	TEST_FEATURE ("with child in older sibling list");
	parent = nih_new (NULL, Parent);

	__nih_malloc = my_list_head_malloc;
	parent->list = nih_new (parent, NihList);
	nih_list_init (parent->list);
	__nih_malloc = malloc;

	parent->child = nih_new (parent, Child);
	nih_list_init (&parent->child->entry);

	nih_list_add (parent->list, &parent->child->entry);
	nih_alloc_set_destructor (parent->child, child_destructor_test);

	__nih_free = my_list_head_free;
	nih_free (parent);
	__nih_free = free;


	/* Check that a child of an object may be included in a sibling
	 * linked list allocated later.  At the point the child destructor
	 * is called, the sibling must not have been freed otherwise it
	 * cannot cut itself out.
	 */
	TEST_FEATURE ("with child in younger sibling list");
	parent = nih_new (NULL, Parent);

	parent->child = nih_new (parent, Child);
	nih_list_init (&parent->child->entry);

	__nih_malloc = my_list_head_malloc;
	parent->list = nih_new (parent, NihList);
	nih_list_init (parent->list);
	__nih_malloc = malloc;

	nih_list_add (parent->list, &parent->child->entry);
	nih_alloc_set_destructor (parent->child, child_destructor_test);

	__nih_free = my_list_head_free;
	nih_free (parent);
	__nih_free = free;
}