Linux Audio

Check our new training course

Loading...
/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include <zephyr.h>
#include <ztest.h>


#define STACKSIZE       (2048 + CONFIG_TEST_EXTRA_STACKSIZE)

ZTEST_BMEM static int count;
ZTEST_BMEM static int ret = TC_PASS;

void check_input(const char *name, const char *input);

/**
 *
 * print_loop
 *
 * This function calls check_input 6 times with the input name and a short
 * string, which is printed properly by check_input.
 *
 * @param name    caller identification string
 *
 * @return N/A
 */

void print_loop(const char *name)
{
	while (count < 6) {
		/* A short input string to check_input.  It will pass. */
		check_input(name, "Stack ok");
		count++;
	}
}

/**
 *
 * check_input
 *
 * This function copies the input string to a buffer of 16 characters and
 * prints the name and buffer as a string.  If the input string is longer
 * than the buffer, an error condition is detected.
 *
 * When stack protection feature is enabled (see prj.conf file), the
 * system error handler is invoked and reports a "Stack Check Fail" error.
 * When stack protection feature is not enabled, the system crashes with
 * error like: Trying to execute code outside RAM or ROM.
 *
 * @return N/A
 */

void check_input(const char *name, const char *input)
{
	/* Stack will overflow when input is more than 16 characters */
	char buf[16];

	strcpy(buf, input);
	TC_PRINT("%s: %s\n", name, buf);
}

/**
 *
 * This thread passes a long string to check_input function.  It terminates due
 * to stack overflow and reports "Stack Check Fail" when stack protection
 * feature is enabled.  Hence it will not execute the print_loop function
 * and will not set ret to TC_FAIL.
 *
 * @return N/A
 */
void alternate_thread(void)
{
	TC_PRINT("Starts %s\n", __func__);
	check_input(__func__,
		    "Input string is too long and stack overflowed!\n");
	/*
	 * Expect this thread to terminate due to stack check fail and will not
	 * execute pass here.
	 */
	print_loop(__func__);

	ret = TC_FAIL;
}



K_THREAD_STACK_DEFINE(alt_thread_stack_area, STACKSIZE);
static struct k_thread alt_thread_data;

/**
 * @brief test Stack Protector feature using canary
 *
 * @details This is the test program to test stack protection using canary.
 * The main thread starts a second thread, which generates a stack check
 * failure.
 * By design, the second thread will not complete its execution and
 * will not set ret to TC_FAIL.
 * This is the entry point to the test stack protection feature.
 * It starts the thread that tests stack protection, then prints out
 * a few messages before terminating.
 *
 * @ingroup kernel_memprotect_tests
 */

void test_stackprot(void)
{
	zassert_true(ret == TC_PASS, NULL);
	print_loop(__func__);
}

void test_create_alt_thread(void)
{
	/* Start thread */
	k_thread_create(&alt_thread_data, alt_thread_stack_area, STACKSIZE,
			(k_thread_entry_t)alternate_thread, NULL, NULL, NULL,
			K_PRIO_COOP(1), K_USER, K_NO_WAIT);
}

void test_main(void)
{
	ztest_test_suite(stackprot,
			 ztest_unit_test(test_create_alt_thread),
			 ztest_user_unit_test(test_stackprot));
	ztest_run_test_suite(stackprot);
}