1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright © 2022 Keith Packard
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials provided
16  *    with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #define _DEFAULT_SOURCE
37 #include <stdint.h>
38 #include <assert.h>
39 #include <stdlib.h>
40 
41 /*
42  * Validate lock usage in libc by creating fake locks
43  * to be used during testing
44  */
45 
46 #define _LOCK_T intptr_t*
47 
48 intptr_t __lock___libc_recursive_mutex;
49 
50 #define MAX_LOCKS 32
51 
52 static intptr_t locks[MAX_LOCKS];
53 static int lock_id;
54 
55 /* Create a new dynamic non-recursive lock */
__retarget_lock_init(_LOCK_T * lock)56 void __retarget_lock_init(_LOCK_T *lock)
57 {
58         assert(lock_id < MAX_LOCKS);
59         *lock = &locks[lock_id++];
60         **lock = 0;
61 }
62 
63 /* Create a new dynamic recursive lock */
__retarget_lock_init_recursive(_LOCK_T * lock)64 void __retarget_lock_init_recursive(_LOCK_T *lock)
65 {
66         *lock = &locks[lock_id++];
67         **lock = 0;
68 }
69 
70 /* Close dynamic non-recursive lock */
__retarget_lock_close(_LOCK_T lock)71 void __retarget_lock_close(_LOCK_T lock)
72 {
73         assert(*lock == 0);
74 }
75 
76 /* Close dynamic recursive lock */
__retarget_lock_close_recursive(_LOCK_T lock)77 void __retarget_lock_close_recursive(_LOCK_T lock)
78 {
79         assert(*lock == 0);
80 }
81 
82 /* Acquiure non-recursive lock */
__retarget_lock_acquire(_LOCK_T lock)83 void __retarget_lock_acquire(_LOCK_T lock)
84 {
85         assert(*lock == 0);
86         *lock = 1;
87 }
88 
89 /* Acquiure recursive lock */
__retarget_lock_acquire_recursive(_LOCK_T lock)90 void __retarget_lock_acquire_recursive(_LOCK_T lock)
91 {
92         assert(*lock >= 0);
93         ++(*lock);
94 }
95 
96 /* Try acquiring non-recursive lock */
__retarget_lock_try_acquire(_LOCK_T lock)97 int __retarget_lock_try_acquire(_LOCK_T lock)
98 {
99         assert(*lock == 0);
100         *lock = 1;
101 }
102 
103 /* Try acquiring recursive lock */
__retarget_lock_try_acquire_recursive(_LOCK_T lock)104 int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
105 {
106         assert(*lock >= 0);
107         ++(*lock);
108 }
109 
110 /* Release non-recursive lock */
__retarget_lock_release(_LOCK_T lock)111 void __retarget_lock_release(_LOCK_T lock)
112 {
113         assert(*lock == 1);
114         *lock = 0;
115 }
116 
117 /* Release recursive lock */
__retarget_lock_release_recursive(_LOCK_T lock)118 void __retarget_lock_release_recursive(_LOCK_T lock)
119 {
120         assert(*lock > 0);
121         --(*lock);
122 }
123 
124 #ifdef _PICO_EXIT
125 #define LIBC_LOCK_EXIT_COUNT 0
126 #else
127 /*
128  * Legacy onexit handler holds libc lock while calling hooks
129  */
130 #define LIBC_LOCK_EXIT_COUNT 1
131 #endif
132 
lock_validate(int ret,void * arg)133 static void lock_validate(int ret, void *arg)
134 {
135         int i;
136         (void) ret;
137         (void) arg;
138         for (i = 0; i < MAX_LOCKS; i++)
139                 assert(locks[i] == 0);
140 
141         assert(__lock___libc_recursive_mutex == LIBC_LOCK_EXIT_COUNT);
142 }
143 
144 __attribute__((constructor))
add_lock_validate(void)145 static void add_lock_validate(void)
146 {
147     on_exit(lock_validate, NULL);
148 }
149