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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#include "test_functions.h"

#include "gate/tests.h"
#include "gate/functions.h"
#include "gate/callstacks.h"
#include "gate/console.h"

static int volatile callstack_run_checkpoint = 0;

static gate_result_t test_callstack_entry_point(void* ptr)
{
    gate_console_t* con = (gate_console_t*)ptr;
    gate_stream_t* strm = (gate_stream_t*)con;
    gate_stream_println_cstr(strm, "Hello World");
    callstack_run_checkpoint = 1;
    return GATE_RESULT_OK;
}

static int volatile callstack_fork_checkpoint_1 = 0;
static int volatile callstack_fork_checkpoint_2 = 0;

static gate_result_t callstack_fork_entry1(void* arg)
{
    gate_callstack_jmpbuf_t* ptr_fork_anchor = (gate_callstack_jmpbuf_t*)arg;

    callstack_fork_checkpoint_1 = 1;

    gate_callstack_jump(ptr_fork_anchor);
    return 123;
}

static gate_result_t callstack_fork_entry1_no_jump(void* arg)
{
    gate_callstack_jmpbuf_t* ptr_fork_anchor = (gate_callstack_jmpbuf_t*)arg;

    GATE_TEST_CHECK(ptr_fork_anchor != NULL);
    callstack_fork_checkpoint_1 = 1;
    return 123;
}


static gate_result_t callstack_fork_entry2(void* arg)
{
    gate_callstack_jmpbuf_t* ptr_fork_anchor = (gate_callstack_jmpbuf_t*)arg;

    GATE_TEST_CHECK(ptr_fork_anchor != NULL);
    callstack_fork_checkpoint_2 = 2;
    return 456;
}

GATE_TEST_FUNCTION(test_callstack)
{
    gate_callstack_jmpbuf_t fork_anchor;
    gate_size_t stack_size = 0; /* default */
    void* stack_ptr = NULL;
    void* param = gate_console();
    gate_result_t callstack_run_result;
    gate_result_t retval = GATE_RESULT_FAILED;

    GATE_TEST_UNIT_BEGIN(test_callstack);

    callstack_run_checkpoint = 0;
    GATE_TEST_REQUIRE_OK(gate_callstack_create(&stack_size, &stack_ptr));
    callstack_run_result = gate_callstack_run(stack_ptr, stack_size, NULL, &test_callstack_entry_point, param, &retval);
    if (callstack_run_result == GATE_RESULT_NOTSUPPORTED)
    {
        /* callstack switching is not supported on this platform, tests are meaningless */
    }
    else
    {
        GATE_TEST_CHECK_OK(callstack_run_result);
        GATE_TEST_CHECK_OK(retval);
        GATE_TEST_CHECK(callstack_run_checkpoint == 1);	/* other callstack invocation should have changed the value */
    }
    GATE_TEST_CHECK_OK(gate_callstack_destroy(stack_ptr, stack_size));

    callstack_fork_checkpoint_1 = 0;
    callstack_fork_checkpoint_2 = 0;
    retval = gate_callstack_fork(&fork_anchor, &callstack_fork_entry1_no_jump, &fork_anchor, &callstack_fork_entry2, &fork_anchor);
    GATE_TEST_CHECK(callstack_fork_checkpoint_1 == 1); /* expect reached */
    GATE_TEST_CHECK(callstack_fork_checkpoint_2 == 0); /* expect not reached */
    GATE_TEST_CHECK(retval == 123);


    callstack_fork_checkpoint_1 = 0;
    callstack_fork_checkpoint_2 = 0;
    retval = gate_callstack_fork(&fork_anchor, &callstack_fork_entry1, &fork_anchor, &callstack_fork_entry2, &fork_anchor);
    GATE_TEST_CHECK(callstack_fork_checkpoint_1 == 1); /* expect reached */
    GATE_TEST_CHECK(callstack_fork_checkpoint_2 == 2); /* expect reached */
    GATE_TEST_CHECK(retval == 456);

    GATE_TEST_UNIT_END;
}

#define ARG_A 0xa0
#define ARG_B 0xb000
#define ARG_C 0xc0000000
#define ARG_D 0xd000000000000000ULL
#define ARG_RESULT (ARG_D + ARG_C + ARG_B + ARG_A)

static gate_int32_t generic_function(gate_uint8_t a, gate_uint16_t b, gate_uint32_t c, gate_uint64_t d, gate_uint64_t* result)
{
    GATE_TEST_TRACE_VALUE(a);
    GATE_TEST_CHECK_EQUAL(a, ARG_A);
    GATE_TEST_TRACE_VALUE(b);
    GATE_TEST_CHECK_EQUAL(b, ARG_B);
    GATE_TEST_TRACE_VALUE(c);
    GATE_TEST_CHECK_EQUAL(c, ARG_C);
    GATE_TEST_TRACE_VALUE(d);
    GATE_TEST_CHECK_EQUAL(d, ARG_D);
    *result = (gate_uint64_t)a
        + (gate_uint64_t)b
        + (gate_uint64_t)c
        + (gate_uint64_t)d;
    return -1;
}


GATE_TEST_FUNCTION(test_function_generic_call)
{
    gate_function_argument_t args[5];
    gate_function_argument_t retval;

    gate_result_t ret;
    gate_uint64_t result = 0xdeadbeaf;

    GATE_TEST_UNIT_BEGIN(test_function_generic_call);

    args[0].arg_type = GATE_FUNCTION_ARG_UCHAR;
    args[0].arg_value.u_chr = ARG_A;
    args[1].arg_type = GATE_FUNCTION_ARG_USHORT;
    args[1].arg_value.u_short = ARG_B;
    args[2].arg_type = GATE_FUNCTION_ARG_ULONG;
    args[2].arg_value.u_long = ARG_C;
    args[3].arg_type = GATE_FUNCTION_ARG_ULONGLONG;
    args[3].arg_value.u_long_long = ARG_D;
    args[4].arg_type = GATE_FUNCTION_ARG_POINTER;
    args[4].arg_value.ptr = &result;
    retval.arg_type = GATE_FUNCTION_ARG_SLONG;
    retval.arg_value.s_long = 0;

    ret = gate_function_invoke_generic((gate_funcptr_t)&generic_function, 0, args, 5, &retval);
    GATE_TEST_REQUIRE_OK(ret);
    GATE_TEST_CHECK_EQUAL(result, ARG_RESULT);

    GATE_TEST_UNIT_END;
}



static gate_result_t no_fault_entry(void* arg)
{
    GATE_UNUSED_ARG(arg);
    return GATE_RESULT_OK;
}


static gate_result_t seg_fault_entry(void* arg)
{
    int volatile* volatile ptr = (int volatile*)arg;
    volatile int n = *ptr;
    *ptr = n;
    return GATE_RESULT_OK;
}
static volatile int zero = 0;
static gate_result_t div_fault_entry(void* arg)
{
    int volatile value = 42;
    int volatile result;

    (void)arg;
    result = value / zero;<--- Division by zero<--- Variable 'result' is assigned a value that is never used.
    return GATE_RESULT_OK;
}
static volatile float zerof = 0.0f;
static gate_result_t float_fault_entry(void* arg)
{
    float value = 42.0f;
    float result;

    (void)arg;
    result = value / zerof;<--- Variable 'result' is assigned a value that is never used.
    return GATE_RESULT_OK;
}

static gate_result_t fault_handler(unsigned fault_code, void* fault_arg)
{
    unsigned* volatile ptr = (unsigned*)fault_arg;<--- Variable 'ptr' is not assigned a value.<--- Uninitialized variable: ptr
    GATE_TEST_CHECK(fault_arg != NULL);
    *ptr = fault_code;<--- Uninitialized variable: ptr
    return GATE_RESULT_OK;
}

static void test_function_fault_succeed(gate_entrypoint_t entry, void* arg)
{
    gate_result_t result;
    unsigned fault_code = 0;
    GATE_UNUSED_ARG(arg);

    result = gate_function_invoke_guarded(entry, NULL, &fault_handler, &fault_code);
    GATE_TEST_CHECK_RESULT(GATE_RESULT_OK, result);
    GATE_TEST_CHECK_EQUAL(fault_code, 0);
}

static void test_function_fault_fail(gate_entrypoint_t entry, void* arg, unsigned expected_fault)
{
    gate_result_t result;
    unsigned fault_code = 0;
    GATE_UNUSED_ARG(arg);

    result = gate_function_invoke_guarded(entry, NULL, &fault_handler, &fault_code);
    GATE_TEST_CHECK_RESULT(GATE_RESULT_BADINSTRUCTION, result);
    GATE_TEST_CHECK_EQUAL(fault_code, expected_fault);

    GATE_TEST_TRACE_MESSAGE("Result codes");
    GATE_TEST_TRACE_VALUE(fault_code);
    GATE_TEST_TRACE_VALUE(expected_fault);

    return;
}


GATE_TEST_FUNCTION(test_function_fault_guard)
{

    GATE_TEST_UNIT_BEGIN(test_function_fault_guard);

    /* NOTICE: Fault guard code triggers debuggers and unit test executors (like CTest).
       So this test is not executed by default */
#if defined(GATECORE_TEST_EXECUTE_FAULT_GUARD)

#if !defined(GATE_SYS_BSD)
    test_function_fault_succeed(&no_fault_entry, NULL);
#if !defined(GATE_SYS_DOS)
    test_function_fault_fail(&seg_fault_entry, NULL, GATE_FUNCTION_FAULT_ADDRESS);
    test_function_fault_fail(&div_fault_entry, NULL, GATE_FUNCTION_FAULT_ARITHMETIC);
#endif
    /*test_function_fault_fail(&float_fault_entry, NULL, GATE_FUNCTION_FAULT_FLOAT);*/
#endif

#endif

    GATE_TEST_UNIT_END;
}