diff options
author | Anderson Toshiyuki Sasaki <ansasaki@redhat.com> | 2018-07-04 13:55:24 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2018-08-03 16:43:03 +0200 |
commit | 5443863723964b0b7ea810f76e1abe170aa38e4e (patch) | |
tree | 9dc5be69af808294afb86e0f7ee4fbc034e7976e /tests/unittests | |
parent | edcdef94eeb3d43ab61017ce3527976b012d2a13 (diff) | |
download | libssh-5443863723964b0b7ea810f76e1abe170aa38e4e.tar.gz libssh-5443863723964b0b7ea810f76e1abe170aa38e4e.tar.xz libssh-5443863723964b0b7ea810f76e1abe170aa38e4e.zip |
tests: Add test for buffer running on threads
The test run buffer tests on multiple threads.
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Diffstat (limited to 'tests/unittests')
-rw-r--r-- | tests/unittests/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/unittests/torture_threads_buffer.c | 596 |
2 files changed, 599 insertions, 0 deletions
diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index aa67b033..e384f578 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -37,6 +37,9 @@ if (UNIX AND NOT WIN32) target_link_libraries(torture_rand Threads::Threads) add_cmocka_test(torture_threads_init torture_threads_init.c ${TORTURE_LIBRARY}) target_link_libraries(torture_threads_init Threads::Threads) + add_cmocka_test(torture_threads_buffer torture_threads_buffer.c ${TORTURE_LIBRARY}) + target_link_libraries(torture_threads_buffer Threads::Threads) + # Not working correctly #if (WITH_SERVER) # add_cmocka_test(torture_server_x11 torture_server_x11.c ${TORTURE_LIBRARY}) diff --git a/tests/unittests/torture_threads_buffer.c b/tests/unittests/torture_threads_buffer.c new file mode 100644 index 00000000..f8a68cea --- /dev/null +++ b/tests/unittests/torture_threads_buffer.c @@ -0,0 +1,596 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2018 by Anderson Toshiyuki Sasaki <ansasaki@redhat.com> + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#define LIBSSH_STATIC + +#include "torture.h" +#define DEBUG_BUFFER +#include "buffer.c" + +#include <pthread.h> + +#define NUM_THREADS 20 + +#define BUFFER_LIMIT (8 * 1024 * 1024) + +static int run_on_threads(void *(*func)(void *)) +{ + pthread_t threads[NUM_THREADS]; + int rc; + int i; + + for (i = 0; i < NUM_THREADS; ++i) { + rc = pthread_create(&threads[i], NULL, func, NULL); + assert_int_equal(rc, 0); + } + + for (i = 0; i < NUM_THREADS; ++i) { + void *p = NULL; + uint64_t *result = NULL; + + rc = pthread_join(threads[i], &p); + assert_int_equal(rc, 0); + + result = (uint64_t *)p; + assert_null(result); + } + + return rc; +} + +/* + * Test if the continuously growing buffer size never exceeds 2 time its + * real capacity + */ +static void *thread_growing_buffer(void *threadid) +{ + ssh_buffer buffer = NULL; + int i; + + /* Unused */ + (void) threadid; + + /* Setup */ + buffer = ssh_buffer_new(); + if (buffer == NULL) { + pthread_exit((void *)-1); + } + ssh_buffer_set_secure(buffer); + + for (i = 0; i < BUFFER_LIMIT; ++i) { + ssh_buffer_add_data(buffer,"A",1); + if (buffer->used >= 128) { + if (ssh_buffer_get_len(buffer) * 2 < buffer->allocated) { + assert_true(ssh_buffer_get_len(buffer) * 2 >= buffer->allocated); + } + } + } + + /* Teardown */ + ssh_buffer_free(buffer); + pthread_exit(NULL); +} + +static void torture_growing_buffer(void **state) +{ + int rc; + + /* Unused */ + (void) state; + + rc = run_on_threads(thread_growing_buffer); + assert_int_equal(rc, 0); +} + +/* + * Test if the continuously growing buffer size never exceeds 2 time its + * real capacity, when we remove 1 byte after each call (sliding window) + */ +static void *thread_growing_buffer_shifting(void *threadid) +{ + ssh_buffer buffer; + int i; + unsigned char c; + + /* Unused */ + (void) threadid; + + /* Setup */ + buffer = ssh_buffer_new(); + if (buffer == NULL) { + pthread_exit((void *)-1); + } + ssh_buffer_set_secure(buffer); + + + for (i = 0; i < 1024; ++i) { + ssh_buffer_add_data(buffer,"S",1); + } + + for (i = 0; i < BUFFER_LIMIT; ++i) { + ssh_buffer_get_u8(buffer,&c); + ssh_buffer_add_data(buffer,"A",1); + if (buffer->used >= 128) { + if (ssh_buffer_get_len(buffer) * 4 < buffer->allocated) { + assert_true(ssh_buffer_get_len(buffer) * 4 >= buffer->allocated); + /* Teardown */ + ssh_buffer_free(buffer); + pthread_exit(NULL); + } + } + } + + /* Teardown */ + ssh_buffer_free(buffer); + pthread_exit(NULL); +} + +static void torture_growing_buffer_shifting(void **state) +{ + int rc; + + /* Unused */ + (void) state; + + rc = run_on_threads(thread_growing_buffer_shifting); + assert_int_equal(rc, 0); +} + +/* + * Test the behavior of ssh_buffer_prepend_data + */ +static void *thread_buffer_prepend(void *threadid) +{ + ssh_buffer buffer = NULL; + uint32_t v; + + /* Unused */ + (void) threadid; + + /* Setup */ + buffer = ssh_buffer_new(); + if (buffer == NULL) { + pthread_exit((void *)-1); + } + ssh_buffer_set_secure(buffer); + + ssh_buffer_add_data(buffer, "abcdef", 6); + ssh_buffer_prepend_data(buffer, "xyz", 3); + assert_int_equal(ssh_buffer_get_len(buffer), 9); + assert_memory_equal(ssh_buffer_get(buffer), "xyzabcdef", 9); + + /* Now remove 4 bytes and see if we can replace them */ + ssh_buffer_get_u32(buffer, &v); + assert_int_equal(ssh_buffer_get_len(buffer), 5); + assert_memory_equal(ssh_buffer_get(buffer), "bcdef", 5); + + ssh_buffer_prepend_data(buffer, "aris", 4); + assert_int_equal(ssh_buffer_get_len(buffer), 9); + assert_memory_equal(ssh_buffer_get(buffer), "arisbcdef", 9); + + /* same thing but we add 5 bytes now */ + ssh_buffer_get_u32(buffer, &v); + assert_int_equal(ssh_buffer_get_len(buffer), 5); + assert_memory_equal(ssh_buffer_get(buffer), "bcdef", 5); + + ssh_buffer_prepend_data(buffer, "12345", 5); + assert_int_equal(ssh_buffer_get_len(buffer), 10); + assert_memory_equal(ssh_buffer_get(buffer), "12345bcdef", 10); + + /* Teardown */ + ssh_buffer_free(buffer); + pthread_exit(NULL); +} + +static void torture_buffer_prepend(void **state) +{ + int rc; + + /* Unused */ + (void) state; + + rc = run_on_threads(thread_buffer_prepend); + assert_int_equal(rc, 0); +} + +/* + * Test the behavior of ssh_buffer_get_ssh_string with invalid data + */ +static void *thread_ssh_buffer_get_ssh_string(void *threadid) +{ + ssh_buffer buffer = NULL; + size_t i, j, k, l; + int rc; + /* some values that can go wrong */ + uint32_t values[] = { + 0xffffffff, 0xfffffffe, 0xfffffffc, 0xffffff00, + 0x80000000, 0x80000004, 0x7fffffff}; + char data[128] = {0}; + + /* Unused */ + (void)threadid; + + memset(data, 'X', sizeof(data)); + + for (i = 0; i < ARRAY_SIZE(values); ++i) { + for (j = 0; j < (int)sizeof(data); ++j) { + for (k = 1; k < 5; ++k) { + buffer = ssh_buffer_new(); + assert_non_null(buffer); + + for (l = 0; l < k; ++l) { + rc = ssh_buffer_add_u32(buffer,htonl(values[i])); + assert_int_equal(rc, 0); + } + rc = ssh_buffer_add_data(buffer,data,j); + assert_int_equal(rc, 0); + for (l = 0; l < k; ++l) { + ssh_string str = ssh_buffer_get_ssh_string(buffer); + assert_null(str); + ssh_string_free(str); + } + ssh_buffer_free(buffer); + } + } + } + + pthread_exit(NULL); +} + +static void torture_ssh_buffer_get_ssh_string(void **state){ + int rc; + + /* Unused */ + (void) state; + + rc = run_on_threads(thread_ssh_buffer_get_ssh_string); + assert_int_equal(rc, 0); +} + +static void *thread_ssh_buffer_add_format(void *threadid) +{ + ssh_buffer buffer = NULL; + uint8_t b; + uint16_t w; + uint32_t d; + uint64_t q; + ssh_string s = NULL; + int rc; + size_t len; + uint8_t verif[] = "\x42\x13\x37\x0b\xad\xc0\xde\x13\x24\x35\x46" + "\xac\xbd\xce\xdf" + "\x00\x00\x00\x06" "libssh" + "\x00\x00\x00\x05" "rocks" + "So much" + "Fun!"; + + /* Unused */ + (void) threadid; + + /* Setup */ + buffer = ssh_buffer_new(); + if (buffer == NULL) { + pthread_exit((void *)-1); + } + ssh_buffer_set_secure(buffer); + + b = 0x42; + w = 0x1337; + d = 0xbadc0de; + q = 0x13243546acbdcedf; + s = ssh_string_from_char("libssh"); + rc = ssh_buffer_pack(buffer, + "bwdqSsPt", + b, + w, + d, + q, + s, + "rocks", + 7, + "So much", + "Fun!"); + assert_int_equal(rc, SSH_OK); + + len = ssh_buffer_get_len(buffer); + assert_int_equal(len, sizeof(verif) - 1); + assert_memory_equal(ssh_buffer_get(buffer), verif, sizeof(verif) -1); + + ssh_string_free(s); + + /* Teardown */ + ssh_buffer_free(buffer); + pthread_exit(NULL); +} + +static void torture_ssh_buffer_add_format(void **state){ + int rc; + + /* Unused */ + (void) state; + + rc = run_on_threads(thread_ssh_buffer_add_format); + assert_int_equal(rc, 0); +} + +static void *thread_ssh_buffer_get_format(void *threadid) { + ssh_buffer buffer; + uint8_t b = 0; + uint16_t w = 0; + uint32_t d = 0; + uint64_t q = 0; + ssh_string s = NULL; + char *s1 = NULL, *s2 = NULL; + int rc; + size_t len; + uint8_t verif[] = "\x42\x13\x37\x0b\xad\xc0\xde\x13\x24\x35\x46" + "\xac\xbd\xce\xdf" + "\x00\x00\x00\x06" "libssh" + "\x00\x00\x00\x05" "rocks" + "So much"; + + /* Unused */ + (void) threadid; + + /* Setup */ + buffer = ssh_buffer_new(); + if (buffer == NULL) { + pthread_exit((void *)-1); + } + ssh_buffer_set_secure(buffer); + + rc = ssh_buffer_add_data(buffer, verif, sizeof(verif) - 1); + assert_int_equal(rc, SSH_OK); + + rc = ssh_buffer_unpack(buffer, + "bwdqSsP", + &b, + &w, + &d, + &q, + &s, + &s1, + (size_t)7, + &s2); + assert_int_equal(rc, SSH_OK); + + assert_int_equal(b, 0x42); + assert_int_equal(w, 0x1337); + + assert_true(d == 0xbadc0de); + assert_true(q == 0x13243546acbdcedf); + + assert_true(s != NULL); + assert_int_equal(ssh_string_len(s), 6); + assert_memory_equal(ssh_string_data(s), "libssh", 6); + + assert_true(s1 != NULL); + assert_string_equal(s1, "rocks"); + + assert_true(s2 != NULL); + assert_memory_equal(s2, "So much", 7); + + len = ssh_buffer_get_len(buffer); + assert_int_equal(len, 0); + SAFE_FREE(s); + SAFE_FREE(s1); + SAFE_FREE(s2); + + /* Teardown */ + ssh_buffer_free(buffer); + pthread_exit(NULL); +} + +static void torture_ssh_buffer_get_format(void **state) +{ + int rc; + + /* Unused */ + (void) state; + + rc = run_on_threads(thread_ssh_buffer_get_format); + assert_int_equal(rc, 0); +} + +static void *thread_ssh_buffer_get_format_error(void *threadid) +{ + ssh_buffer buffer = NULL; + uint8_t b = 0; + uint16_t w = 0; + uint32_t d = 0; + uint64_t q = 0; + ssh_string s = NULL; + char *s1 = NULL, *s2 = NULL; + int rc; + uint8_t verif[] = "\x42\x13\x37\x0b\xad\xc0\xde\x13\x24\x35\x46" + "\xac\xbd\xce\xdf" + "\x00\x00\x00\x06" "libssh" + "\x00\x00\x00\x05" "rocks" + "So much"; + + /* Unused */ + (void) threadid; + + /* Setup */ + buffer = ssh_buffer_new(); + if (buffer == NULL) { + pthread_exit((void *)-1); + } + ssh_buffer_set_secure(buffer); + + rc = ssh_buffer_add_data(buffer, verif, sizeof(verif) - 1); + assert_int_equal(rc, SSH_OK); + rc = ssh_buffer_unpack(buffer, + "bwdqSsPb", + &b, + &w, + &d, + &q, + &s, + &s1, + (size_t)7, + &s2, + &b); + assert_int_equal(rc, SSH_ERROR); + + assert_true(s == NULL); + assert_true(s1 == NULL); + assert_true(s2 == NULL); + + /* Teardown */ + ssh_buffer_free(buffer); + pthread_exit(NULL); +} + +static void torture_ssh_buffer_get_format_error(void **state) +{ + int rc; + + /* Unused */ + (void) state; + + rc = run_on_threads(thread_ssh_buffer_get_format_error); + assert_int_equal(rc, 0); +} + +static void *thread_buffer_pack_badformat(void *threadid) +{ + ssh_buffer buffer = NULL; + uint8_t b = 42; + int rc; + + /* Unused */ + (void) threadid; + + /* Setup */ + buffer = ssh_buffer_new(); + if (buffer == NULL) { + pthread_exit((void *)-1); + } + ssh_buffer_set_secure(buffer); + + /* first with missing format */ + rc = ssh_buffer_pack(buffer, "b", b, b); + assert_int_equal(rc, SSH_ERROR); + ssh_buffer_reinit(buffer); + + /* with additional format */ + rc = ssh_buffer_pack(buffer, "bb", b); +#ifdef HAVE_GCC_NARG_MACRO + /* We can only detect errors if we have support for NARG macros */ + assert_int_equal(rc, SSH_ERROR); +#endif + + /* unpack with missing format */ + ssh_buffer_reinit(buffer); + + rc = ssh_buffer_pack(buffer, "bb", 42, 43); + assert_int_equal(rc, SSH_OK); + + rc = ssh_buffer_unpack(buffer, "b", &b, &b); + assert_int_equal(rc, SSH_ERROR); + + /* not doing the test with additional format as + * it could crash the process */ + + /* Teardown */ + ssh_buffer_free(buffer); + pthread_exit(NULL); +} + +static void torture_buffer_pack_badformat(void **state) +{ + int rc; + + /* Unused */ + (void) state; + + rc = run_on_threads(thread_buffer_pack_badformat); + assert_int_equal(rc, 0); +} + +#define NUM_TESTS 8 + +static void torture_mixed(void **state) +{ + pthread_t threads[NUM_TESTS][NUM_THREADS]; + int i; + int f; + int rc; + + /* Array of functions to run on threads */ + static void *(*funcs[NUM_TESTS])(void *) = { + thread_growing_buffer, + thread_growing_buffer_shifting, + thread_buffer_prepend, + thread_ssh_buffer_get_ssh_string, + thread_ssh_buffer_add_format, + thread_ssh_buffer_get_format, + thread_ssh_buffer_get_format_error, + thread_buffer_pack_badformat + }; + + (void) state; + + /* Call tests in a round-robin fashion */ + for (i = 0; i < NUM_THREADS; ++i) { + for (f = 0; f < NUM_TESTS; f++) { + rc = pthread_create(&threads[f][i], NULL, funcs[f], NULL); + assert_int_equal(rc, 0); + } + } + + for (f = 0; f < NUM_TESTS; f++) { + for (i = 0; i < NUM_THREADS; ++i) { + void *p = NULL; + uint64_t *result = NULL; + + rc = pthread_join(threads[f][i], &p); + assert_int_equal(rc, 0); + + result = (uint64_t *)p; + assert_null(result); + } + } +} + +int torture_run_tests(void) +{ + int rc; + struct CMUnitTest tests[] = { + cmocka_unit_test(torture_growing_buffer), + cmocka_unit_test(torture_growing_buffer_shifting), + cmocka_unit_test(torture_buffer_prepend), + cmocka_unit_test(torture_ssh_buffer_get_ssh_string), + cmocka_unit_test(torture_ssh_buffer_add_format), + cmocka_unit_test(torture_ssh_buffer_get_format), + cmocka_unit_test(torture_ssh_buffer_get_format_error), + cmocka_unit_test(torture_buffer_pack_badformat), + cmocka_unit_test(torture_mixed), + }; + + torture_filter_tests(tests); + rc = cmocka_run_group_tests(tests, NULL, NULL); + + return rc; +} |