summaryrefslogtreecommitdiffstats
path: root/tests/lib/stack-test.c
blob: bed59aaa76cc33ac68b7e9804e0e31a7043f258b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* SPDX-License-Identifier: GPL-2.0-only */

#include <tests/test.h>
#include <lib.h>
#include <symbols.h>


#if CONFIG_STACK_SIZE == 0
# define STACK_SIZE 0x1000
#else
# define STACK_SIZE CONFIG_STACK_SIZE
#endif

/* Value used for stack initialization. Change if implementation changes. */
#define STACK_GUARD_VALUE 0xDEADBEEF

__weak extern u8 _stack[];
__weak extern u8 _estack[];
TEST_REGION(stack, STACK_SIZE);


static void fill_stack(u32 value)
{
	u32 *stack = (u32 *)_stack;
	for (size_t i = 0; i < STACK_SIZE / sizeof(u32); ++i)
		stack[i] = value;
}

/* Fill stack region with guard value.  */
static void clean_stack(void)
{
	fill_stack(STACK_GUARD_VALUE);
}

static int setup_stack_test(void **state)
{
	void *top_of_stack = _stack + sizeof(_stack);

	clean_stack();
	*state = top_of_stack;

	return 0;
}

static void test_empty_stack(void **state)
{
	void *top_of_stack = *state;

	/* Expect success when checking empty stack. */
	assert_int_equal(0, checkstack(top_of_stack, 0));
}

static void test_almost_full_stack(void **state)
{
	void *top_of_stack = *state;
	u32 *stack = (u32 *)_stack;

	/* Fill stack with random value except last word */
	for (size_t i = 1; i < STACK_SIZE / sizeof(u32); ++i)
		stack[i] = 0xAA11FF44;

	/* Expect success when checking almost-full stack,
	   because last guard value is present */
	assert_int_equal(0, checkstack(top_of_stack, 0));
}

static void test_full_stack(void **state)
{
	void *top_of_stack = *state;

	/* Fill stack with value different than stack guard */
	fill_stack(0x600DB015);

	/* Expect failure when checking full stack as absence of guard value at the end of
	   the stack indicates stack overrun. */
	expect_assert_failure(checkstack(top_of_stack, 0));
}

static void test_partialy_filled_stack(void **state)
{
	void *top_of_stack = *state;
	u32 *stack = (u32 *)_stack;
	size_t i = STACK_SIZE / sizeof(u32) / 2;

	for (; i < STACK_SIZE / sizeof(u32); ++i)
		stack[i] = 0x4321ABDC + i;

	/* Expect success when checking partially-filled stack,
	   because only part of stack is filled with non-guard value. */
	assert_int_equal(0, checkstack(top_of_stack, 0));
}

static void test_alternately_filled_stack(void **state)
{
	void *top_of_stack = *state;
	u32 *stack = (u32 *)_stack;
	size_t i;

	for (i = 0; i < STACK_SIZE / sizeof(u32); i += 2)
		stack[i] = STACK_GUARD_VALUE;

	for (i = 1; i < STACK_SIZE / sizeof(u32); i += 2)
		stack[i] = 0x42420707;

	assert_int_equal(0, checkstack(top_of_stack, 0));
}

static void test_incorrectly_initialized_stack(void **state)
{
	void *top_of_stack = *state;
	u32 *stack = (u32 *)_stack;

	/* Remove last stack guard value */
	stack[0] = 0xFF00FF11;

	/* Expect failure when there is no last stack guard value even if no other value was
	   changed. */
	expect_assert_failure(checkstack(top_of_stack, 0));
}

int main(void)
{
	const struct CMUnitTest tests[] = {
		cmocka_unit_test_setup(test_empty_stack, setup_stack_test),
		cmocka_unit_test_setup(test_almost_full_stack, setup_stack_test),
		cmocka_unit_test_setup(test_full_stack, setup_stack_test),
		cmocka_unit_test_setup(test_partialy_filled_stack, setup_stack_test),
		cmocka_unit_test_setup(test_alternately_filled_stack, setup_stack_test),
		cmocka_unit_test_setup(test_incorrectly_initialized_stack, setup_stack_test),
	};

	return cmocka_run_group_tests(tests, NULL, NULL);
}