1a8e1175bSopenharmony_ci/** Mutex usage verification framework. */
2a8e1175bSopenharmony_ci
3a8e1175bSopenharmony_ci/*
4a8e1175bSopenharmony_ci *  Copyright The Mbed TLS Contributors
5a8e1175bSopenharmony_ci *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6a8e1175bSopenharmony_ci */
7a8e1175bSopenharmony_ci
8a8e1175bSopenharmony_ci#include <test/helpers.h>
9a8e1175bSopenharmony_ci#include <test/threading_helpers.h>
10a8e1175bSopenharmony_ci#include <test/macros.h>
11a8e1175bSopenharmony_ci
12a8e1175bSopenharmony_ci#include "mbedtls/threading.h"
13a8e1175bSopenharmony_ci
14a8e1175bSopenharmony_ci#if defined(MBEDTLS_THREADING_C)
15a8e1175bSopenharmony_ci
16a8e1175bSopenharmony_ci#if defined(MBEDTLS_THREADING_PTHREAD)
17a8e1175bSopenharmony_ci
18a8e1175bSopenharmony_cistatic int threading_thread_create_pthread(mbedtls_test_thread_t *thread, void *(*thread_func)(
19a8e1175bSopenharmony_ci                                               void *), void *thread_data)
20a8e1175bSopenharmony_ci{
21a8e1175bSopenharmony_ci    if (thread == NULL || thread_func == NULL) {
22a8e1175bSopenharmony_ci        return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
23a8e1175bSopenharmony_ci    }
24a8e1175bSopenharmony_ci
25a8e1175bSopenharmony_ci    if (pthread_create(&thread->thread, NULL, thread_func, thread_data)) {
26a8e1175bSopenharmony_ci        return MBEDTLS_ERR_THREADING_THREAD_ERROR;
27a8e1175bSopenharmony_ci    }
28a8e1175bSopenharmony_ci
29a8e1175bSopenharmony_ci    return 0;
30a8e1175bSopenharmony_ci}
31a8e1175bSopenharmony_ci
32a8e1175bSopenharmony_cistatic int threading_thread_join_pthread(mbedtls_test_thread_t *thread)
33a8e1175bSopenharmony_ci{
34a8e1175bSopenharmony_ci    if (thread == NULL) {
35a8e1175bSopenharmony_ci        return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
36a8e1175bSopenharmony_ci    }
37a8e1175bSopenharmony_ci
38a8e1175bSopenharmony_ci    if (pthread_join(thread->thread, NULL) != 0) {
39a8e1175bSopenharmony_ci        return MBEDTLS_ERR_THREADING_THREAD_ERROR;
40a8e1175bSopenharmony_ci    }
41a8e1175bSopenharmony_ci
42a8e1175bSopenharmony_ci    return 0;
43a8e1175bSopenharmony_ci}
44a8e1175bSopenharmony_ci
45a8e1175bSopenharmony_ciint (*mbedtls_test_thread_create)(mbedtls_test_thread_t *thread, void *(*thread_func)(void *),
46a8e1175bSopenharmony_ci                                  void *thread_data) = threading_thread_create_pthread;
47a8e1175bSopenharmony_ciint (*mbedtls_test_thread_join)(mbedtls_test_thread_t *thread) = threading_thread_join_pthread;
48a8e1175bSopenharmony_ci
49a8e1175bSopenharmony_ci#endif /* MBEDTLS_THREADING_PTHREAD */
50a8e1175bSopenharmony_ci
51a8e1175bSopenharmony_ci#if defined(MBEDTLS_THREADING_ALT)
52a8e1175bSopenharmony_ci
53a8e1175bSopenharmony_cistatic int threading_thread_create_fail(mbedtls_test_thread_t *thread,
54a8e1175bSopenharmony_ci                                        void *(*thread_func)(void *),
55a8e1175bSopenharmony_ci                                        void *thread_data)
56a8e1175bSopenharmony_ci{
57a8e1175bSopenharmony_ci    (void) thread;
58a8e1175bSopenharmony_ci    (void) thread_func;
59a8e1175bSopenharmony_ci    (void) thread_data;
60a8e1175bSopenharmony_ci
61a8e1175bSopenharmony_ci    return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
62a8e1175bSopenharmony_ci}
63a8e1175bSopenharmony_ci
64a8e1175bSopenharmony_cistatic int threading_thread_join_fail(mbedtls_test_thread_t *thread)
65a8e1175bSopenharmony_ci{
66a8e1175bSopenharmony_ci    (void) thread;
67a8e1175bSopenharmony_ci
68a8e1175bSopenharmony_ci    return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
69a8e1175bSopenharmony_ci}
70a8e1175bSopenharmony_ci
71a8e1175bSopenharmony_ciint (*mbedtls_test_thread_create)(mbedtls_test_thread_t *thread, void *(*thread_func)(void *),
72a8e1175bSopenharmony_ci                                  void *thread_data) = threading_thread_create_fail;
73a8e1175bSopenharmony_ciint (*mbedtls_test_thread_join)(mbedtls_test_thread_t *thread) = threading_thread_join_fail;
74a8e1175bSopenharmony_ci
75a8e1175bSopenharmony_ci#endif /* MBEDTLS_THREADING_ALT */
76a8e1175bSopenharmony_ci
77a8e1175bSopenharmony_ci#if defined(MBEDTLS_TEST_MUTEX_USAGE)
78a8e1175bSopenharmony_ci
79a8e1175bSopenharmony_ci#include "mbedtls/threading.h"
80a8e1175bSopenharmony_ci
81a8e1175bSopenharmony_ci/** Mutex usage verification framework.
82a8e1175bSopenharmony_ci *
83a8e1175bSopenharmony_ci * The mutex usage verification code below aims to detect bad usage of
84a8e1175bSopenharmony_ci * Mbed TLS's mutex abstraction layer at runtime. Note that this is solely
85a8e1175bSopenharmony_ci * about the use of the mutex itself, not about checking whether the mutex
86a8e1175bSopenharmony_ci * correctly protects whatever it is supposed to protect.
87a8e1175bSopenharmony_ci *
88a8e1175bSopenharmony_ci * The normal usage of a mutex is:
89a8e1175bSopenharmony_ci * ```
90a8e1175bSopenharmony_ci * digraph mutex_states {
91a8e1175bSopenharmony_ci *   "UNINITIALIZED"; // the initial state
92a8e1175bSopenharmony_ci *   "IDLE";
93a8e1175bSopenharmony_ci *   "FREED";
94a8e1175bSopenharmony_ci *   "LOCKED";
95a8e1175bSopenharmony_ci *   "UNINITIALIZED" -> "IDLE" [label="init"];
96a8e1175bSopenharmony_ci *   "FREED" -> "IDLE" [label="init"];
97a8e1175bSopenharmony_ci *   "IDLE" -> "LOCKED" [label="lock"];
98a8e1175bSopenharmony_ci *   "LOCKED" -> "IDLE" [label="unlock"];
99a8e1175bSopenharmony_ci *   "IDLE" -> "FREED" [label="free"];
100a8e1175bSopenharmony_ci * }
101a8e1175bSopenharmony_ci * ```
102a8e1175bSopenharmony_ci *
103a8e1175bSopenharmony_ci * All bad transitions that can be unambiguously detected are reported.
104a8e1175bSopenharmony_ci * An attempt to use an uninitialized mutex cannot be detected in general
105a8e1175bSopenharmony_ci * since the memory content may happen to denote a valid state. For the same
106a8e1175bSopenharmony_ci * reason, a double init cannot be detected.
107a8e1175bSopenharmony_ci * All-bits-zero is the state of a freed mutex, which is distinct from an
108a8e1175bSopenharmony_ci * initialized mutex, so attempting to use zero-initialized memory as a mutex
109a8e1175bSopenharmony_ci * without calling the init function is detected.
110a8e1175bSopenharmony_ci *
111a8e1175bSopenharmony_ci * The framework attempts to detect missing calls to init and free by counting
112a8e1175bSopenharmony_ci * calls to init and free. If there are more calls to init than free, this
113a8e1175bSopenharmony_ci * means that a mutex is not being freed somewhere, which is a memory leak
114a8e1175bSopenharmony_ci * on platforms where a mutex consumes resources other than the
115a8e1175bSopenharmony_ci * mbedtls_threading_mutex_t object itself. If there are more calls to free
116a8e1175bSopenharmony_ci * than init, this indicates a missing init, which is likely to be detected
117a8e1175bSopenharmony_ci * by an attempt to lock the mutex as well. A limitation of this framework is
118a8e1175bSopenharmony_ci * that it cannot detect scenarios where there is exactly the same number of
119a8e1175bSopenharmony_ci * calls to init and free but the calls don't match. A bug like this is
120a8e1175bSopenharmony_ci * unlikely to happen uniformly throughout the whole test suite though.
121a8e1175bSopenharmony_ci *
122a8e1175bSopenharmony_ci * If an error is detected, this framework will report what happened and the
123a8e1175bSopenharmony_ci * test case will be marked as failed. Unfortunately, the error report cannot
124a8e1175bSopenharmony_ci * indicate the exact location of the problematic call. To locate the error,
125a8e1175bSopenharmony_ci * use a debugger and set a breakpoint on mbedtls_test_mutex_usage_error().
126a8e1175bSopenharmony_ci */
127a8e1175bSopenharmony_cienum value_of_mutex_state_field {
128a8e1175bSopenharmony_ci    /* Potential values for the state field of mbedtls_threading_mutex_t.
129a8e1175bSopenharmony_ci     * Note that MUTEX_FREED must be 0 and MUTEX_IDLE must be 1 for
130a8e1175bSopenharmony_ci     * compatibility with threading_mutex_init_pthread() and
131a8e1175bSopenharmony_ci     * threading_mutex_free_pthread(). MUTEX_LOCKED could be any nonzero
132a8e1175bSopenharmony_ci     * value. */
133a8e1175bSopenharmony_ci    MUTEX_FREED = 0, //! < Set by mbedtls_test_wrap_mutex_free
134a8e1175bSopenharmony_ci    MUTEX_IDLE = 1, //! < Set by mbedtls_test_wrap_mutex_init and by mbedtls_test_wrap_mutex_unlock
135a8e1175bSopenharmony_ci    MUTEX_LOCKED = 2, //! < Set by mbedtls_test_wrap_mutex_lock
136a8e1175bSopenharmony_ci};
137a8e1175bSopenharmony_ci
138a8e1175bSopenharmony_citypedef struct {
139a8e1175bSopenharmony_ci    void (*init)(mbedtls_threading_mutex_t *);
140a8e1175bSopenharmony_ci    void (*free)(mbedtls_threading_mutex_t *);
141a8e1175bSopenharmony_ci    int (*lock)(mbedtls_threading_mutex_t *);
142a8e1175bSopenharmony_ci    int (*unlock)(mbedtls_threading_mutex_t *);
143a8e1175bSopenharmony_ci} mutex_functions_t;
144a8e1175bSopenharmony_cistatic mutex_functions_t mutex_functions;
145a8e1175bSopenharmony_ci
146a8e1175bSopenharmony_ci/**
147a8e1175bSopenharmony_ci *  The mutex used to guard live_mutexes below and access to the status variable
148a8e1175bSopenharmony_ci *  in every mbedtls_threading_mutex_t.
149a8e1175bSopenharmony_ci *  Note that we are not reporting any errors when locking and unlocking this
150a8e1175bSopenharmony_ci *  mutex. This is for a couple of reasons:
151a8e1175bSopenharmony_ci *
152a8e1175bSopenharmony_ci *  1. We have no real way of reporting any errors with this mutex - we cannot
153a8e1175bSopenharmony_ci *  report it back to the caller, as the failure was not that of the mutex
154a8e1175bSopenharmony_ci *  passed in. We could fail the test, but again this would indicate a problem
155a8e1175bSopenharmony_ci *  with the test code that did not exist.
156a8e1175bSopenharmony_ci *
157a8e1175bSopenharmony_ci *  2. Any failure to lock is unlikely to be intermittent, and will thus not
158a8e1175bSopenharmony_ci *  give false test results - the overall result would be to turn off the
159a8e1175bSopenharmony_ci *  testing. This is not a situation that is likely to happen with normal
160a8e1175bSopenharmony_ci *  testing and we still have TSan to fall back on should this happen.
161a8e1175bSopenharmony_ci */
162a8e1175bSopenharmony_cimbedtls_threading_mutex_t mbedtls_test_mutex_mutex;
163a8e1175bSopenharmony_ci
164a8e1175bSopenharmony_ci/**
165a8e1175bSopenharmony_ci *  The total number of calls to mbedtls_mutex_init(), minus the total number
166a8e1175bSopenharmony_ci *  of calls to mbedtls_mutex_free().
167a8e1175bSopenharmony_ci *
168a8e1175bSopenharmony_ci *  Do not read or write without holding mbedtls_test_mutex_mutex (above). Reset
169a8e1175bSopenharmony_ci *  to 0 after each test case.
170a8e1175bSopenharmony_ci */
171a8e1175bSopenharmony_cistatic int live_mutexes;
172a8e1175bSopenharmony_ci
173a8e1175bSopenharmony_cistatic void mbedtls_test_mutex_usage_error(mbedtls_threading_mutex_t *mutex,
174a8e1175bSopenharmony_ci                                           const char *msg)
175a8e1175bSopenharmony_ci{
176a8e1175bSopenharmony_ci    (void) mutex;
177a8e1175bSopenharmony_ci
178a8e1175bSopenharmony_ci    mbedtls_test_set_mutex_usage_error(msg);
179a8e1175bSopenharmony_ci    mbedtls_fprintf(stdout, "[mutex: %s] ", msg);
180a8e1175bSopenharmony_ci    /* Don't mark the test as failed yet. This way, if the test fails later
181a8e1175bSopenharmony_ci     * for a functional reason, the test framework will report the message
182a8e1175bSopenharmony_ci     * and location for this functional reason. If the test passes,
183a8e1175bSopenharmony_ci     * mbedtls_test_mutex_usage_check() will mark it as failed. */
184a8e1175bSopenharmony_ci}
185a8e1175bSopenharmony_ci
186a8e1175bSopenharmony_cistatic int mbedtls_test_mutex_can_test(mbedtls_threading_mutex_t *mutex)
187a8e1175bSopenharmony_ci{
188a8e1175bSopenharmony_ci    /* If we attempt to run tests on this mutex then we are going to run into a
189a8e1175bSopenharmony_ci     * couple of problems:
190a8e1175bSopenharmony_ci     * 1. If any test on this mutex fails, we are going to deadlock when
191a8e1175bSopenharmony_ci     * reporting that failure, as we already hold the mutex at that point.
192a8e1175bSopenharmony_ci     * 2. Given the 'global' position of the initialization and free of this
193a8e1175bSopenharmony_ci     * mutex, it will be shown as leaked on the first test run. */
194a8e1175bSopenharmony_ci    if (mutex == mbedtls_test_get_info_mutex()) {
195a8e1175bSopenharmony_ci        return 0;
196a8e1175bSopenharmony_ci    }
197a8e1175bSopenharmony_ci
198a8e1175bSopenharmony_ci    return 1;
199a8e1175bSopenharmony_ci}
200a8e1175bSopenharmony_ci
201a8e1175bSopenharmony_cistatic void mbedtls_test_wrap_mutex_init(mbedtls_threading_mutex_t *mutex)
202a8e1175bSopenharmony_ci{
203a8e1175bSopenharmony_ci    mutex_functions.init(mutex);
204a8e1175bSopenharmony_ci
205a8e1175bSopenharmony_ci    if (mbedtls_test_mutex_can_test(mutex)) {
206a8e1175bSopenharmony_ci        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
207a8e1175bSopenharmony_ci            mutex->state = MUTEX_IDLE;
208a8e1175bSopenharmony_ci            ++live_mutexes;
209a8e1175bSopenharmony_ci
210a8e1175bSopenharmony_ci            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
211a8e1175bSopenharmony_ci        }
212a8e1175bSopenharmony_ci    }
213a8e1175bSopenharmony_ci}
214a8e1175bSopenharmony_ci
215a8e1175bSopenharmony_cistatic void mbedtls_test_wrap_mutex_free(mbedtls_threading_mutex_t *mutex)
216a8e1175bSopenharmony_ci{
217a8e1175bSopenharmony_ci    if (mbedtls_test_mutex_can_test(mutex)) {
218a8e1175bSopenharmony_ci        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
219a8e1175bSopenharmony_ci
220a8e1175bSopenharmony_ci            switch (mutex->state) {
221a8e1175bSopenharmony_ci                case MUTEX_FREED:
222a8e1175bSopenharmony_ci                    mbedtls_test_mutex_usage_error(mutex, "free without init or double free");
223a8e1175bSopenharmony_ci                    break;
224a8e1175bSopenharmony_ci                case MUTEX_IDLE:
225a8e1175bSopenharmony_ci                    mutex->state = MUTEX_FREED;
226a8e1175bSopenharmony_ci                    --live_mutexes;
227a8e1175bSopenharmony_ci                    break;
228a8e1175bSopenharmony_ci                case MUTEX_LOCKED:
229a8e1175bSopenharmony_ci                    mbedtls_test_mutex_usage_error(mutex, "free without unlock");
230a8e1175bSopenharmony_ci                    break;
231a8e1175bSopenharmony_ci                default:
232a8e1175bSopenharmony_ci                    mbedtls_test_mutex_usage_error(mutex, "corrupted state");
233a8e1175bSopenharmony_ci                    break;
234a8e1175bSopenharmony_ci            }
235a8e1175bSopenharmony_ci
236a8e1175bSopenharmony_ci            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
237a8e1175bSopenharmony_ci        }
238a8e1175bSopenharmony_ci    }
239a8e1175bSopenharmony_ci
240a8e1175bSopenharmony_ci    mutex_functions.free(mutex);
241a8e1175bSopenharmony_ci}
242a8e1175bSopenharmony_ci
243a8e1175bSopenharmony_cistatic int mbedtls_test_wrap_mutex_lock(mbedtls_threading_mutex_t *mutex)
244a8e1175bSopenharmony_ci{
245a8e1175bSopenharmony_ci    /* Lock the passed in mutex first, so that the only way to change the state
246a8e1175bSopenharmony_ci     * is to hold the passed in and internal mutex - otherwise we create a race
247a8e1175bSopenharmony_ci     * condition. */
248a8e1175bSopenharmony_ci    int ret = mutex_functions.lock(mutex);
249a8e1175bSopenharmony_ci
250a8e1175bSopenharmony_ci    if (mbedtls_test_mutex_can_test(mutex)) {
251a8e1175bSopenharmony_ci        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
252a8e1175bSopenharmony_ci            switch (mutex->state) {
253a8e1175bSopenharmony_ci                case MUTEX_FREED:
254a8e1175bSopenharmony_ci                    mbedtls_test_mutex_usage_error(mutex, "lock without init");
255a8e1175bSopenharmony_ci                    break;
256a8e1175bSopenharmony_ci                case MUTEX_IDLE:
257a8e1175bSopenharmony_ci                    if (ret == 0) {
258a8e1175bSopenharmony_ci                        mutex->state = MUTEX_LOCKED;
259a8e1175bSopenharmony_ci                    }
260a8e1175bSopenharmony_ci                    break;
261a8e1175bSopenharmony_ci                case MUTEX_LOCKED:
262a8e1175bSopenharmony_ci                    mbedtls_test_mutex_usage_error(mutex, "double lock");
263a8e1175bSopenharmony_ci                    break;
264a8e1175bSopenharmony_ci                default:
265a8e1175bSopenharmony_ci                    mbedtls_test_mutex_usage_error(mutex, "corrupted state");
266a8e1175bSopenharmony_ci                    break;
267a8e1175bSopenharmony_ci            }
268a8e1175bSopenharmony_ci
269a8e1175bSopenharmony_ci            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
270a8e1175bSopenharmony_ci        }
271a8e1175bSopenharmony_ci    }
272a8e1175bSopenharmony_ci
273a8e1175bSopenharmony_ci    return ret;
274a8e1175bSopenharmony_ci}
275a8e1175bSopenharmony_ci
276a8e1175bSopenharmony_cistatic int mbedtls_test_wrap_mutex_unlock(mbedtls_threading_mutex_t *mutex)
277a8e1175bSopenharmony_ci{
278a8e1175bSopenharmony_ci    /* Lock the internal mutex first and change state, so that the only way to
279a8e1175bSopenharmony_ci     * change the state is to hold the passed in and internal mutex - otherwise
280a8e1175bSopenharmony_ci     * we create a race condition. */
281a8e1175bSopenharmony_ci    if (mbedtls_test_mutex_can_test(mutex)) {
282a8e1175bSopenharmony_ci        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
283a8e1175bSopenharmony_ci            switch (mutex->state) {
284a8e1175bSopenharmony_ci                case MUTEX_FREED:
285a8e1175bSopenharmony_ci                    mbedtls_test_mutex_usage_error(mutex, "unlock without init");
286a8e1175bSopenharmony_ci                    break;
287a8e1175bSopenharmony_ci                case MUTEX_IDLE:
288a8e1175bSopenharmony_ci                    mbedtls_test_mutex_usage_error(mutex, "unlock without lock");
289a8e1175bSopenharmony_ci                    break;
290a8e1175bSopenharmony_ci                case MUTEX_LOCKED:
291a8e1175bSopenharmony_ci                    mutex->state = MUTEX_IDLE;
292a8e1175bSopenharmony_ci                    break;
293a8e1175bSopenharmony_ci                default:
294a8e1175bSopenharmony_ci                    mbedtls_test_mutex_usage_error(mutex, "corrupted state");
295a8e1175bSopenharmony_ci                    break;
296a8e1175bSopenharmony_ci            }
297a8e1175bSopenharmony_ci            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
298a8e1175bSopenharmony_ci        }
299a8e1175bSopenharmony_ci    }
300a8e1175bSopenharmony_ci
301a8e1175bSopenharmony_ci    return mutex_functions.unlock(mutex);
302a8e1175bSopenharmony_ci}
303a8e1175bSopenharmony_ci
304a8e1175bSopenharmony_civoid mbedtls_test_mutex_usage_init(void)
305a8e1175bSopenharmony_ci{
306a8e1175bSopenharmony_ci    mutex_functions.init = mbedtls_mutex_init;
307a8e1175bSopenharmony_ci    mutex_functions.free = mbedtls_mutex_free;
308a8e1175bSopenharmony_ci    mutex_functions.lock = mbedtls_mutex_lock;
309a8e1175bSopenharmony_ci    mutex_functions.unlock = mbedtls_mutex_unlock;
310a8e1175bSopenharmony_ci    mbedtls_mutex_init = &mbedtls_test_wrap_mutex_init;
311a8e1175bSopenharmony_ci    mbedtls_mutex_free = &mbedtls_test_wrap_mutex_free;
312a8e1175bSopenharmony_ci    mbedtls_mutex_lock = &mbedtls_test_wrap_mutex_lock;
313a8e1175bSopenharmony_ci    mbedtls_mutex_unlock = &mbedtls_test_wrap_mutex_unlock;
314a8e1175bSopenharmony_ci
315a8e1175bSopenharmony_ci    mutex_functions.init(&mbedtls_test_mutex_mutex);
316a8e1175bSopenharmony_ci}
317a8e1175bSopenharmony_ci
318a8e1175bSopenharmony_civoid mbedtls_test_mutex_usage_check(void)
319a8e1175bSopenharmony_ci{
320a8e1175bSopenharmony_ci    if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
321a8e1175bSopenharmony_ci        if (live_mutexes != 0) {
322a8e1175bSopenharmony_ci            /* A positive number (more init than free) means that a mutex resource
323a8e1175bSopenharmony_ci             * is leaking (on platforms where a mutex consumes more than the
324a8e1175bSopenharmony_ci             * mbedtls_threading_mutex_t object itself). The (hopefully) rare
325a8e1175bSopenharmony_ci             * case of a negative number means a missing init somewhere. */
326a8e1175bSopenharmony_ci            mbedtls_fprintf(stdout, "[mutex: %d leaked] ", live_mutexes);
327a8e1175bSopenharmony_ci            live_mutexes = 0;
328a8e1175bSopenharmony_ci            mbedtls_test_set_mutex_usage_error("missing free");
329a8e1175bSopenharmony_ci        }
330a8e1175bSopenharmony_ci        if (mbedtls_test_get_mutex_usage_error() != NULL &&
331a8e1175bSopenharmony_ci            mbedtls_test_get_result() != MBEDTLS_TEST_RESULT_FAILED) {
332a8e1175bSopenharmony_ci            /* Functionally, the test passed. But there was a mutex usage error,
333a8e1175bSopenharmony_ci             * so mark the test as failed after all. */
334a8e1175bSopenharmony_ci            mbedtls_test_fail("Mutex usage error", __LINE__, __FILE__);
335a8e1175bSopenharmony_ci        }
336a8e1175bSopenharmony_ci        mbedtls_test_set_mutex_usage_error(NULL);
337a8e1175bSopenharmony_ci
338a8e1175bSopenharmony_ci        mutex_functions.unlock(&mbedtls_test_mutex_mutex);
339a8e1175bSopenharmony_ci    }
340a8e1175bSopenharmony_ci}
341a8e1175bSopenharmony_ci
342a8e1175bSopenharmony_civoid mbedtls_test_mutex_usage_end(void)
343a8e1175bSopenharmony_ci{
344a8e1175bSopenharmony_ci    mbedtls_mutex_init = mutex_functions.init;
345a8e1175bSopenharmony_ci    mbedtls_mutex_free = mutex_functions.free;
346a8e1175bSopenharmony_ci    mbedtls_mutex_lock = mutex_functions.lock;
347a8e1175bSopenharmony_ci    mbedtls_mutex_unlock = mutex_functions.unlock;
348a8e1175bSopenharmony_ci
349a8e1175bSopenharmony_ci    mutex_functions.free(&mbedtls_test_mutex_mutex);
350a8e1175bSopenharmony_ci}
351a8e1175bSopenharmony_ci
352a8e1175bSopenharmony_ci#endif /* MBEDTLS_TEST_MUTEX_USAGE */
353a8e1175bSopenharmony_ci
354a8e1175bSopenharmony_ci#endif /* MBEDTLS_THREADING_C */
355