Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

#include "test.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include <exception>

#define fprintf(...)

void log(void* ignored)
{
	//printf("Cleanup called on %s\n", *(char**)ignored);
}
#define CLEANUP\
	__attribute__((cleanup(log))) __attribute__((unused))\
		const char *f = __func__;

/**
 * Simple struct to test throwing.
 */
struct foo
{
	int i;
};

struct bar : foo
{
	float bar;
};


/**
 * Non-pod type to test throwing
 */
class non_pod {
public:
    non_pod(int i): x(i) {}
    int x;
};


static int cleanup_count;
/**
 * Simple structure declared with a destructor.  Destroying this object will
 * increment cleanup count.  The destructor should be called automatically if
 * an instance of cl is allocated with automatic storage.
 */
struct cl
{
	int i;
	~cl() { fprintf(stderr, "cl destroyed: %d\n", i); cleanup_count++; }
};
/**
 * Test that one cl was destroyed when running the argument.
 */
#define TEST_CLEANUP(x) do {\
		int cleanups = cleanup_count;\
		{ x; }\
		TEST(cleanup_count == cleanups+1, "Cleanup ran correctly");\
	} while(0)

int inner(int i)
{
	CLEANUP
	switch (i)
	{
		case 0: throw (int)1.0;
		case 1: throw (float)1.0;
		case 2: fprintf(stderr, "Throwing int64_t\n");throw (int64_t)1;
		case 3: { foo f = {2} ; throw f; }
		case 4: { bar f; f.i = 2 ; f.bar=1 ; throw f; }
        case 5: throw non_pod(3);
	}
	return -1;
}

int outer(int i) throw(float, int, foo, non_pod)
{
	//CLEANUP
	inner(i);
	return 1;
}

static void test_const(void)
{
	int a = 1;
	try
	{
		throw a;
	}
	catch (const int b)
	{
		TEST(a == b, "Caught int as const int");
	}
	catch(...)
	{
		TEST(0, "Failed to catch int as const int");
	}
	try
	{
		throw &a;
	}
	catch (const int *b)
	{
		TEST(&a == b, "Caught int* as const int*");
	}
	catch(...)
	{
		TEST(0, "Failed to catch int* as const int*");
	}
}

static void test_catch(int s) 
{
	cl c;
	c.i = 12;
	fprintf(stderr, "Entering try\n");
	try
	{
		outer(s);
	}
	catch(int i)
	{
		fprintf(stderr, "Caught int %d in test %d\n", i, s);
		TEST((s == 0 && i == 1) || (s == 2 && i == 0), "Caught int");
		return;
	}
	catch (float f)
	{
		fprintf(stderr, "Caught float %f!\n", f);
		TEST(s == 1 && f == 1, "Caught float");
		return;
	}
	catch (foo f)
	{
		fprintf(stderr, "Caught struct {%d}!\n", f.i);
		TEST((s == 3 || s == 4) && f.i == 2, "Caught struct");
		return;
	}
    catch (non_pod np) {
        fprintf(stderr, "Caught non_pod {%d}!\n", np.x);
        TEST(s == 5 && np.x == 3, "Caught non_pod");
        return;
    }
	//abort();
	TEST(0, "Unreachable line reached");
}

void test_nested1(void)
{
	CLEANUP;
	cl c;
	c.i = 123;
	try 
	{
		outer(0);
	}
	catch (int a)
	{
		try
		{
			TEST(a == 1, "Caught int");
			outer(1);
		}
		catch (float f)
		{
			TEST(f == 1, "Caught float inside outer catch block");
			throw;
		}
	}
}

void test_nested()
{
	try
	{
		test_nested1();
	}
	catch (float f)
	{
		fprintf(stderr, "Caught re-thrown float\n");
		TEST(f == 1, "Caught re-thrown float");
	}
}

static int violations = 0;
static void throw_zero()
{
	violations++;
	fprintf(stderr, "Throwing 0\n");
	throw 0;
}

extern "C" void __cxa_bad_cast();

void test_exceptions(void)
{
	std::set_unexpected(throw_zero);
	TEST_CLEANUP(test_catch(0));
	TEST_CLEANUP(test_catch(1));
	TEST_CLEANUP(test_catch(3));
	TEST_CLEANUP(test_catch(4));
	TEST_CLEANUP(test_catch(5));
	TEST_CLEANUP(test_nested());
	try{
		test_catch(2);
		TEST(violations == 1, "Exactly one exception spec violation");
	}
	catch (int64_t i) {
		TEST(0, "Caught int64_t, but that violates an exception spec");
	}
	int a;
	try {
		throw &a;
	}
	catch (const int *b)
	{
		TEST(&a==b, "Caught const int from thrown int");
	}
	try {
		throw &a;
	}
	catch (int *b)
	{
		TEST(&a==b, "Caught int from thrown int");
	}
	try
	{
		__cxa_bad_cast();
	}
	catch (std::exception b)
	{
		TEST(1, "Caught bad cast");
	}
	catch (...)
	{
		TEST(0, "Bad cast was not caught correctly");
	}
	test_const();


	//printf("Test: %s\n",
}