quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

metatest.c (16662B)


      1 /** \file metatest.c
      2  *
      3  *  \brief Test features of the test framework.
      4  *
      5  * When you run this program, it runs a single "meta-test". A meta-test
      6  * performs an operation which should be caught as a failure by our
      7  * test framework. The meta-test passes if this program calls `exit` with
      8  * a nonzero status, or aborts, or is terminated by a signal, or if the
      9  * framework running the program considers the run an error (this happens
     10  * with Valgrind for a memory leak). The non-success of the meta-test
     11  * program means that the test failure has been caught correctly.
     12  *
     13  * Some failures are purely functional: the logic of the code causes the
     14  * test result to be set to FAIL. Other failures come from extra
     15  * instrumentation which is not present in a normal build; for example,
     16  * Asan or Valgrind to detect memory leaks. This is reflected by the
     17  * "platform" associated with each meta-test.
     18  *
     19  * Use the companion script `tests/scripts/run-metatests.sh` to run all
     20  * the meta-tests for a given platform and validate that they trigger a
     21  * detected failure as expected.
     22  */
     23 
     24 /*
     25  *  Copyright The Mbed TLS Contributors
     26  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
     27  */
     28 
     29 
     30 #include <mbedtls/debug.h>
     31 #include <mbedtls/platform.h>
     32 #include <mbedtls/platform_util.h>
     33 #include "test/helpers.h"
     34 #include "test/threading_helpers.h"
     35 #include "test/macros.h"
     36 #include "test/memory.h"
     37 #include "common.h"
     38 
     39 #include <stdio.h>
     40 #include <string.h>
     41 
     42 #if defined(MBEDTLS_THREADING_C)
     43 #include <mbedtls/threading.h>
     44 #endif
     45 
     46 
     47 /* This is an external variable, so the compiler doesn't know that we're never
     48  * changing its value.
     49  */
     50 volatile int false_but_the_compiler_does_not_know = 0;
     51 
     52 /* Hide calls to calloc/free from static checkers such as
     53  * `gcc-12 -Wuse-after-free`, to avoid compile-time complaints about
     54  * code where we do mean to cause a runtime error. */
     55 void * (* volatile calloc_but_the_compiler_does_not_know)(size_t, size_t) = mbedtls_calloc;
     56 void(*volatile free_but_the_compiler_does_not_know)(void *) = mbedtls_free;
     57 
     58 /* Set n bytes at the address p to all-bits-zero, in such a way that
     59  * the compiler should not know that p is all-bits-zero. */
     60 static void set_to_zero_but_the_compiler_does_not_know(volatile void *p, size_t n)
     61 {
     62     memset((void *) p, false_but_the_compiler_does_not_know, n);
     63 }
     64 
     65 /* Simulate an access to the given object, to avoid compiler optimizations
     66  * in code that prepares or consumes the object. */
     67 static void do_nothing_with_object(void *p)
     68 {
     69     (void) p;
     70 }
     71 void(*volatile do_nothing_with_object_but_the_compiler_does_not_know)(void *) =
     72     do_nothing_with_object;
     73 
     74 
     75 /****************************************************************/
     76 /* Test framework features */
     77 /****************************************************************/
     78 
     79 static void meta_test_fail(const char *name)
     80 {
     81     (void) name;
     82     mbedtls_test_fail("Forced test failure", __LINE__, __FILE__);
     83 }
     84 
     85 static void meta_test_not_equal(const char *name)
     86 {
     87     int left = 20;
     88     int right = 10;
     89 
     90     (void) name;
     91 
     92     TEST_EQUAL(left, right);
     93 exit:
     94     ;
     95 }
     96 
     97 static void meta_test_not_le_s(const char *name)
     98 {
     99     int left = 20;
    100     int right = 10;
    101 
    102     (void) name;
    103 
    104     TEST_LE_S(left, right);
    105 exit:
    106     ;
    107 }
    108 
    109 static void meta_test_not_le_u(const char *name)
    110 {
    111     size_t left = 20;
    112     size_t right = 10;
    113 
    114     (void) name;
    115 
    116     TEST_LE_U(left, right);
    117 exit:
    118     ;
    119 }
    120 
    121 /****************************************************************/
    122 /* Platform features */
    123 /****************************************************************/
    124 
    125 static void null_pointer_dereference(const char *name)
    126 {
    127     (void) name;
    128     volatile char *volatile p;
    129     set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p));
    130     /* Undefined behavior (read from null data pointer) */
    131     mbedtls_printf("%p -> %u\n", (void *) p, (unsigned) *p);
    132 }
    133 
    134 static void null_pointer_call(const char *name)
    135 {
    136     (void) name;
    137     unsigned(*volatile p)(void);
    138     set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p));
    139     /* Undefined behavior (execute null function pointer) */
    140     /* The pointer representation may be truncated, but we don't care:
    141      * the only point of printing it is to have some use of the pointer
    142      * to dissuade the compiler from optimizing it away. */
    143     mbedtls_printf("%lx() -> %u\n", (unsigned long) (uintptr_t) p, p());
    144 }
    145 
    146 
    147 /****************************************************************/
    148 /* Memory */
    149 /****************************************************************/
    150 
    151 static void read_after_free(const char *name)
    152 {
    153     (void) name;
    154     volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
    155     *p = 'a';
    156     free_but_the_compiler_does_not_know((void *) p);
    157     /* Undefined behavior (read after free) */
    158     mbedtls_printf("%u\n", (unsigned) *p);
    159 }
    160 
    161 static void double_free(const char *name)
    162 {
    163     (void) name;
    164     volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
    165     *p = 'a';
    166     free_but_the_compiler_does_not_know((void *) p);
    167     /* Undefined behavior (double free) */
    168     free_but_the_compiler_does_not_know((void *) p);
    169 }
    170 
    171 static void read_uninitialized_stack(const char *name)
    172 {
    173     (void) name;
    174     char buf[1];
    175     if (false_but_the_compiler_does_not_know) {
    176         buf[0] = '!';
    177     }
    178     char *volatile p = buf;
    179     if (*p != 0) {
    180         /* Unspecified result (read from uninitialized memory) */
    181         mbedtls_printf("%u\n", (unsigned) *p);
    182     }
    183 }
    184 
    185 static void memory_leak(const char *name)
    186 {
    187     (void) name;
    188     volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
    189     mbedtls_printf("%u\n", (unsigned) *p);
    190     /* Leak of a heap object */
    191 }
    192 
    193 /* name = "test_memory_poison_%(start)_%(offset)_%(count)_%(direction)"
    194  * Poison a region starting at start from an 8-byte aligned origin,
    195  * encompassing count bytes. Access the region at offset from the start.
    196  * %(start), %(offset) and %(count) are decimal integers.
    197  * %(direction) is either the character 'r' for read or 'w' for write.
    198  */
    199 static void test_memory_poison(const char *name)
    200 {
    201     size_t start = 0, offset = 0, count = 0;
    202     char direction = 'r';
    203     if (sscanf(name,
    204                "%*[^0-9]%" MBEDTLS_PRINTF_SIZET
    205                "%*[^0-9]%" MBEDTLS_PRINTF_SIZET
    206                "%*[^0-9]%" MBEDTLS_PRINTF_SIZET
    207                "_%c",
    208                &start, &offset, &count, &direction) != 4) {
    209         mbedtls_fprintf(stderr, "%s: Bad name format: %s\n", __func__, name);
    210         return;
    211     }
    212 
    213     union {
    214         long long ll;
    215         unsigned char buf[32];
    216     } aligned;
    217     memset(aligned.buf, 'a', sizeof(aligned.buf));
    218 
    219     if (start > sizeof(aligned.buf)) {
    220         mbedtls_fprintf(stderr,
    221                         "%s: start=%" MBEDTLS_PRINTF_SIZET
    222                         " > size=%" MBEDTLS_PRINTF_SIZET,
    223                         __func__, start, sizeof(aligned.buf));
    224         return;
    225     }
    226     if (start + count > sizeof(aligned.buf)) {
    227         mbedtls_fprintf(stderr,
    228                         "%s: start+count=%" MBEDTLS_PRINTF_SIZET
    229                         " > size=%" MBEDTLS_PRINTF_SIZET,
    230                         __func__, start + count, sizeof(aligned.buf));
    231         return;
    232     }
    233     if (offset >= count) {
    234         mbedtls_fprintf(stderr,
    235                         "%s: offset=%" MBEDTLS_PRINTF_SIZET
    236                         " >= count=%" MBEDTLS_PRINTF_SIZET,
    237                         __func__, offset, count);
    238         return;
    239     }
    240 
    241     MBEDTLS_TEST_MEMORY_POISON(aligned.buf + start, count);
    242 
    243     if (direction == 'w') {
    244         aligned.buf[start + offset] = 'b';
    245         do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf);
    246     } else {
    247         do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf);
    248         mbedtls_printf("%u\n", (unsigned) aligned.buf[start + offset]);
    249     }
    250 }
    251 
    252 
    253 /****************************************************************/
    254 /* Threading */
    255 /****************************************************************/
    256 
    257 static void mutex_lock_not_initialized(const char *name)
    258 {
    259     (void) name;
    260 #if defined(MBEDTLS_THREADING_C)
    261     mbedtls_threading_mutex_t mutex;
    262     memset(&mutex, 0, sizeof(mutex));
    263     /* This mutex usage error is detected by our test framework's mutex usage
    264      * verification framework. See framework/tests/src/threading_helpers.c. Other
    265      * threading implementations (e.g. pthread without our instrumentation)
    266      * might consider this normal usage. */
    267     TEST_ASSERT(mbedtls_mutex_lock(&mutex) == 0);
    268 exit:
    269     ;
    270 #endif
    271 }
    272 
    273 static void mutex_unlock_not_initialized(const char *name)
    274 {
    275     (void) name;
    276 #if defined(MBEDTLS_THREADING_C)
    277     mbedtls_threading_mutex_t mutex;
    278     memset(&mutex, 0, sizeof(mutex));
    279     /* This mutex usage error is detected by our test framework's mutex usage
    280      * verification framework. See framework/tests/src/threading_helpers.c. Other
    281      * threading implementations (e.g. pthread without our instrumentation)
    282      * might consider this normal usage. */
    283     TEST_ASSERT(mbedtls_mutex_unlock(&mutex) == 0);
    284 exit:
    285     ;
    286 #endif
    287 }
    288 
    289 static void mutex_free_not_initialized(const char *name)
    290 {
    291     (void) name;
    292 #if defined(MBEDTLS_THREADING_C)
    293     mbedtls_threading_mutex_t mutex;
    294     memset(&mutex, 0, sizeof(mutex));
    295     /* This mutex usage error is detected by our test framework's mutex usage
    296      * verification framework. See framework/tests/src/threading_helpers.c. Other
    297      * threading implementations (e.g. pthread without our instrumentation)
    298      * might consider this normal usage. */
    299     mbedtls_mutex_free(&mutex);
    300 #endif
    301 }
    302 
    303 static void mutex_double_init(const char *name)
    304 {
    305     (void) name;
    306 #if defined(MBEDTLS_THREADING_C)
    307     mbedtls_threading_mutex_t mutex;
    308     mbedtls_mutex_init(&mutex);
    309     /* This mutex usage error is detected by our test framework's mutex usage
    310      * verification framework. See framework/tests/src/threading_helpers.c. Other
    311      * threading implementations (e.g. pthread without our instrumentation)
    312      * might consider this normal usage. */
    313     mbedtls_mutex_init(&mutex);
    314     mbedtls_mutex_free(&mutex);
    315 #endif
    316 }
    317 
    318 static void mutex_double_free(const char *name)
    319 {
    320     (void) name;
    321 #if defined(MBEDTLS_THREADING_C)
    322     mbedtls_threading_mutex_t mutex;
    323     mbedtls_mutex_init(&mutex);
    324     mbedtls_mutex_free(&mutex);
    325     /* This mutex usage error is detected by our test framework's mutex usage
    326      * verification framework. See framework/tests/src/threading_helpers.c. Other
    327      * threading implementations (e.g. pthread without our instrumentation)
    328      * might consider this normal usage. */
    329     mbedtls_mutex_free(&mutex);
    330 #endif
    331 }
    332 
    333 static void mutex_leak(const char *name)
    334 {
    335     (void) name;
    336 #if defined(MBEDTLS_THREADING_C)
    337     mbedtls_threading_mutex_t mutex;
    338     mbedtls_mutex_init(&mutex);
    339 #endif
    340     /* This mutex usage error is detected by our test framework's mutex usage
    341      * verification framework. See framework/tests/src/threading_helpers.c. Other
    342      * threading implementations (e.g. pthread without our instrumentation)
    343      * might consider this normal usage. */
    344 }
    345 
    346 
    347 /****************************************************************/
    348 /* Command line entry point */
    349 /****************************************************************/
    350 
    351 typedef struct {
    352     /** Command line argument that will trigger that metatest.
    353      *
    354      * Conventionally matches "[a-z0-9_]+". */
    355     const char *name;
    356 
    357     /** Platform under which that metatest is valid.
    358      *
    359      * - "any": should work anywhere.
    360      * - "asan": triggers ASan (Address Sanitizer).
    361      * - "msan": triggers MSan (Memory Sanitizer).
    362      * - "pthread": requires MBEDTLS_THREADING_PTHREAD and MBEDTLS_TEST_HOOKS,
    363      *   which enables MBEDTLS_TEST_MUTEX_USAGE internally in the test
    364      *   framework (see framework/tests/src/threading_helpers.c).
    365      */
    366     const char *platform;
    367 
    368     /** Function that performs the metatest.
    369      *
    370      * The function receives the name as an argument. This allows using the
    371      * same function to perform multiple variants of a test based on the name.
    372      *
    373      * When executed on a conforming platform, the function is expected to
    374      * either cause a test failure (mbedtls_test_fail()), or cause the
    375      * program to abort in some way (e.g. by causing a segfault or by
    376      * triggering a sanitizer).
    377      *
    378      * When executed on a non-conforming platform, the function may return
    379      * normally or may have unpredictable behavior.
    380      */
    381     void (*entry_point)(const char *name);
    382 } metatest_t;
    383 
    384 /* The list of available meta-tests. Remember to register new functions here!
    385  *
    386  * Note that we always compile all the functions, so that `metatest --list`
    387  * will always list all the available meta-tests.
    388  *
    389  * See the documentation of metatest_t::platform for the meaning of
    390  * platform values.
    391  */
    392 metatest_t metatests[] = {
    393     { "test_fail", "any", meta_test_fail },
    394     { "test_not_equal", "any", meta_test_not_equal },
    395     { "test_not_le_s", "any", meta_test_not_le_s },
    396     { "test_not_le_u", "any", meta_test_not_le_u },
    397     { "null_dereference", "any", null_pointer_dereference },
    398     { "null_call", "any", null_pointer_call },
    399     { "read_after_free", "asan", read_after_free },
    400     { "double_free", "asan", double_free },
    401     { "read_uninitialized_stack", "msan", read_uninitialized_stack },
    402     { "memory_leak", "asan", memory_leak },
    403     { "test_memory_poison_0_0_8_r", "poison", test_memory_poison },
    404     { "test_memory_poison_0_0_8_w", "poison", test_memory_poison },
    405     { "test_memory_poison_0_7_8_r", "poison", test_memory_poison },
    406     { "test_memory_poison_0_7_8_w", "poison", test_memory_poison },
    407     { "test_memory_poison_0_0_1_r", "poison", test_memory_poison },
    408     { "test_memory_poison_0_0_1_w", "poison", test_memory_poison },
    409     { "test_memory_poison_0_1_2_r", "poison", test_memory_poison },
    410     { "test_memory_poison_0_1_2_w", "poison", test_memory_poison },
    411     { "test_memory_poison_7_0_8_r", "poison", test_memory_poison },
    412     { "test_memory_poison_7_0_8_w", "poison", test_memory_poison },
    413     { "test_memory_poison_7_7_8_r", "poison", test_memory_poison },
    414     { "test_memory_poison_7_7_8_w", "poison", test_memory_poison },
    415     { "test_memory_poison_7_0_1_r", "poison", test_memory_poison },
    416     { "test_memory_poison_7_0_1_w", "poison", test_memory_poison },
    417     { "test_memory_poison_7_1_2_r", "poison", test_memory_poison },
    418     { "test_memory_poison_7_1_2_w", "poison", test_memory_poison },
    419     { "mutex_lock_not_initialized", "pthread", mutex_lock_not_initialized },
    420     { "mutex_unlock_not_initialized", "pthread", mutex_unlock_not_initialized },
    421     { "mutex_free_not_initialized", "pthread", mutex_free_not_initialized },
    422     { "mutex_double_init", "pthread", mutex_double_init },
    423     { "mutex_double_free", "pthread", mutex_double_free },
    424     { "mutex_leak", "pthread", mutex_leak },
    425     { NULL, NULL, NULL }
    426 };
    427 
    428 static void help(FILE *out, const char *argv0)
    429 {
    430     mbedtls_fprintf(out, "Usage: %s list|TEST\n", argv0);
    431     mbedtls_fprintf(out, "Run a meta-test that should cause a test failure.\n");
    432     mbedtls_fprintf(out, "With 'list', list the available tests and their platform requirement.\n");
    433 }
    434 
    435 int main(int argc, char *argv[])
    436 {
    437     const char *argv0 = argc > 0 ? argv[0] : "metatest";
    438     if (argc != 2) {
    439         help(stderr, argv0);
    440         mbedtls_exit(MBEDTLS_EXIT_FAILURE);
    441     }
    442 
    443     /* Support "-help", "--help", "--list", etc. */
    444     const char *command = argv[1];
    445     while (*command == '-') {
    446         ++command;
    447     }
    448 
    449     if (strcmp(argv[1], "help") == 0) {
    450         help(stdout, argv0);
    451         mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
    452     }
    453     if (strcmp(argv[1], "list") == 0) {
    454         for (const metatest_t *p = metatests; p->name != NULL; p++) {
    455             mbedtls_printf("%s %s\n", p->name, p->platform);
    456         }
    457         mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
    458     }
    459 
    460 #if defined(MBEDTLS_TEST_MUTEX_USAGE)
    461     mbedtls_test_mutex_usage_init();
    462 #endif
    463 
    464     for (const metatest_t *p = metatests; p->name != NULL; p++) {
    465         if (strcmp(argv[1], p->name) == 0) {
    466             mbedtls_printf("Running metatest %s...\n", argv[1]);
    467             p->entry_point(argv[1]);
    468 #if defined(MBEDTLS_TEST_MUTEX_USAGE)
    469             mbedtls_test_mutex_usage_check();
    470 #endif
    471             int result = (int) mbedtls_test_get_result();
    472 
    473             mbedtls_printf("Running metatest %s... done, result=%d\n",
    474                            argv[1], result);
    475             mbedtls_exit(result == MBEDTLS_TEST_RESULT_SUCCESS ?
    476                          MBEDTLS_EXIT_SUCCESS :
    477                          MBEDTLS_EXIT_FAILURE);
    478         }
    479     }
    480 
    481     mbedtls_fprintf(stderr, "%s: FATAL: No such metatest: %s\n",
    482                     argv0, command);
    483     mbedtls_exit(MBEDTLS_EXIT_FAILURE);
    484 }