Line data Source code
1 : /**
2 : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0.
4 : */
5 :
6 : #include <aws/common/common.h>
7 : #include <aws/common/logging.h>
8 : #include <aws/common/math.h>
9 : #include <aws/common/private/dlloads.h>
10 : #include <aws/common/private/thread_shared.h>
11 :
12 : #include <stdarg.h>
13 : #include <stdlib.h>
14 :
15 : #ifdef _WIN32
16 : # include <Windows.h>
17 : #else
18 : # include <dlfcn.h>
19 : #endif
20 :
21 : #ifdef __MACH__
22 : # include <CoreFoundation/CoreFoundation.h>
23 : #endif
24 :
25 : /* turn off unused named parameter warning on msvc.*/
26 : #ifdef _MSC_VER
27 : # pragma warning(push)
28 : # pragma warning(disable : 4100)
29 : #endif
30 :
31 : long (*g_set_mempolicy_ptr)(int, const unsigned long *, unsigned long) = NULL;
32 : int (*g_numa_available_ptr)(void) = NULL;
33 : int (*g_numa_num_configured_nodes_ptr)(void) = NULL;
34 : int (*g_numa_num_possible_cpus_ptr)(void) = NULL;
35 : int (*g_numa_node_of_cpu_ptr)(int cpu) = NULL;
36 :
37 : void *g_libnuma_handle = NULL;
38 :
39 324190 : void aws_secure_zero(void *pBuf, size_t bufsize) {
40 : #if defined(_WIN32)
41 : SecureZeroMemory(pBuf, bufsize);
42 : #else
43 : /* We cannot use memset_s, even on a C11 compiler, because that would require
44 324190 : * that __STDC_WANT_LIB_EXT1__ be defined before the _first_ inclusion of string.h.
45 324190 : *
46 324190 : * We'll try to work around this by using inline asm on GCC-like compilers,
47 324190 : * and by exposing the buffer pointer in a volatile local pointer elsewhere.
48 324190 : */
49 324190 : # if defined(__GNUC__) || defined(__clang__)
50 324190 : memset(pBuf, 0, bufsize);
51 324190 : /* This inline asm serves to convince the compiler that the buffer is (somehow) still
52 324190 : * used after the zero, and therefore that the optimizer can't eliminate the memset.
53 324190 : */
54 324190 : __asm__ __volatile__("" /* The asm doesn't actually do anything. */
55 324190 : : /* no outputs */
56 324190 : /* Tell the compiler that the asm code has access to the pointer to the buffer,
57 324190 : * and therefore it might be reading the (now-zeroed) buffer.
58 324190 : * Without this. clang/LLVM 9.0.0 optimizes away a memset of a stack buffer.
59 324190 : */
60 324190 : : "r"(pBuf)
61 324190 : /* Also clobber memory. While this seems like it might be unnecessary - after all,
62 324190 : * it's enough that the asm might read the buffer, right? - in practice GCC 7.3.0
63 324190 : * seems to optimize a zero of a stack buffer without it.
64 324190 : */
65 324190 : : "memory");
66 : # else // not GCC/clang
67 : /* We don't have access to inline asm, since we're on a non-GCC platform. Move the pointer
68 : * through a volatile pointer in an attempt to confuse the optimizer.
69 : */
70 : volatile void *pVolBuf = pBuf;
71 : memset(pVolBuf, 0, bufsize);
72 : # endif // #else not GCC/clang
73 : #endif // #else not windows
74 324190 : }
75 :
76 : #define AWS_DEFINE_ERROR_INFO_COMMON(C, ES) [(C)-0x0000] = AWS_DEFINE_ERROR_INFO(C, ES, "aws-c-common")
77 : /* clang-format off */
78 : static struct aws_error_info errors[] = {
79 : AWS_DEFINE_ERROR_INFO_COMMON(
80 : AWS_ERROR_SUCCESS,
81 : "Success."),
82 : AWS_DEFINE_ERROR_INFO_COMMON(
83 : AWS_ERROR_OOM,
84 : "Out of memory."),
85 : AWS_DEFINE_ERROR_INFO_COMMON(
86 : AWS_ERROR_NO_SPACE,
87 : "Out of space on disk."),
88 : AWS_DEFINE_ERROR_INFO_COMMON(
89 : AWS_ERROR_UNKNOWN,
90 : "Unknown error."),
91 : AWS_DEFINE_ERROR_INFO_COMMON(
92 : AWS_ERROR_SHORT_BUFFER,
93 : "Buffer is not large enough to hold result."),
94 : AWS_DEFINE_ERROR_INFO_COMMON(
95 : AWS_ERROR_OVERFLOW_DETECTED,
96 : "Fixed size value overflow was detected."),
97 : AWS_DEFINE_ERROR_INFO_COMMON(
98 : AWS_ERROR_UNSUPPORTED_OPERATION,
99 : "Unsupported operation."),
100 : AWS_DEFINE_ERROR_INFO_COMMON(
101 : AWS_ERROR_INVALID_BUFFER_SIZE,
102 : "Invalid buffer size."),
103 : AWS_DEFINE_ERROR_INFO_COMMON(
104 : AWS_ERROR_INVALID_HEX_STR,
105 : "Invalid hex string."),
106 : AWS_DEFINE_ERROR_INFO_COMMON(
107 : AWS_ERROR_INVALID_BASE64_STR,
108 : "Invalid base64 string."),
109 : AWS_DEFINE_ERROR_INFO_COMMON(
110 : AWS_ERROR_INVALID_INDEX,
111 : "Invalid index for list access."),
112 : AWS_DEFINE_ERROR_INFO_COMMON(
113 : AWS_ERROR_THREAD_INVALID_SETTINGS,
114 : "Invalid thread settings."),
115 : AWS_DEFINE_ERROR_INFO_COMMON(
116 : AWS_ERROR_THREAD_INSUFFICIENT_RESOURCE,
117 : "Insufficent resources for thread."),
118 : AWS_DEFINE_ERROR_INFO_COMMON(
119 : AWS_ERROR_THREAD_NO_PERMISSIONS,
120 : "Insufficient permissions for thread operation."),
121 : AWS_DEFINE_ERROR_INFO_COMMON(
122 : AWS_ERROR_THREAD_NOT_JOINABLE,
123 : "Thread not joinable."),
124 : AWS_DEFINE_ERROR_INFO_COMMON(
125 : AWS_ERROR_THREAD_NO_SUCH_THREAD_ID,
126 : "No such thread ID."),
127 : AWS_DEFINE_ERROR_INFO_COMMON(
128 : AWS_ERROR_THREAD_DEADLOCK_DETECTED,
129 : "Deadlock detected in thread."),
130 : AWS_DEFINE_ERROR_INFO_COMMON(
131 : AWS_ERROR_MUTEX_NOT_INIT,
132 : "Mutex not initialized."),
133 : AWS_DEFINE_ERROR_INFO_COMMON(
134 : AWS_ERROR_MUTEX_TIMEOUT,
135 : "Mutex operation timed out."),
136 : AWS_DEFINE_ERROR_INFO_COMMON(
137 : AWS_ERROR_MUTEX_CALLER_NOT_OWNER,
138 : "The caller of a mutex operation was not the owner."),
139 : AWS_DEFINE_ERROR_INFO_COMMON(
140 : AWS_ERROR_MUTEX_FAILED,
141 : "Mutex operation failed."),
142 : AWS_DEFINE_ERROR_INFO_COMMON(
143 : AWS_ERROR_COND_VARIABLE_INIT_FAILED,
144 : "Condition variable initialization failed."),
145 : AWS_DEFINE_ERROR_INFO_COMMON(
146 : AWS_ERROR_COND_VARIABLE_TIMED_OUT,
147 : "Condition variable wait timed out."),
148 : AWS_DEFINE_ERROR_INFO_COMMON(
149 : AWS_ERROR_COND_VARIABLE_ERROR_UNKNOWN,
150 : "Condition variable unknown error."),
151 : AWS_DEFINE_ERROR_INFO_COMMON(
152 : AWS_ERROR_CLOCK_FAILURE,
153 : "Clock operation failed."),
154 : AWS_DEFINE_ERROR_INFO_COMMON(
155 : AWS_ERROR_LIST_EMPTY,
156 : "Empty list."),
157 : AWS_DEFINE_ERROR_INFO_COMMON(
158 : AWS_ERROR_DEST_COPY_TOO_SMALL,
159 : "Destination of copy is too small."),
160 : AWS_DEFINE_ERROR_INFO_COMMON(
161 : AWS_ERROR_LIST_EXCEEDS_MAX_SIZE,
162 : "A requested operation on a list would exceed it's max size."),
163 : AWS_DEFINE_ERROR_INFO_COMMON(
164 : AWS_ERROR_LIST_STATIC_MODE_CANT_SHRINK,
165 : "Attempt to shrink a list in static mode."),
166 : AWS_DEFINE_ERROR_INFO_COMMON(
167 : AWS_ERROR_PRIORITY_QUEUE_FULL,
168 : "Attempt to add items to a full preallocated queue in static mode."),
169 : AWS_DEFINE_ERROR_INFO_COMMON(
170 : AWS_ERROR_PRIORITY_QUEUE_EMPTY,
171 : "Attempt to pop an item from an empty queue."),
172 : AWS_DEFINE_ERROR_INFO_COMMON(
173 : AWS_ERROR_PRIORITY_QUEUE_BAD_NODE,
174 : "Bad node handle passed to remove."),
175 : AWS_DEFINE_ERROR_INFO_COMMON(
176 : AWS_ERROR_HASHTBL_ITEM_NOT_FOUND,
177 : "Item not found in hash table."),
178 : AWS_DEFINE_ERROR_INFO_COMMON(
179 : AWS_ERROR_INVALID_DATE_STR,
180 : "Date string is invalid and cannot be parsed."
181 : ),
182 : AWS_DEFINE_ERROR_INFO_COMMON(
183 : AWS_ERROR_INVALID_ARGUMENT,
184 : "An invalid argument was passed to a function."
185 : ),
186 : AWS_DEFINE_ERROR_INFO_COMMON(
187 : AWS_ERROR_RANDOM_GEN_FAILED,
188 : "A call to the random number generator failed. Retry later."
189 : ),
190 : AWS_DEFINE_ERROR_INFO_COMMON(
191 : AWS_ERROR_MALFORMED_INPUT_STRING,
192 : "An input string was passed to a parser and the string was incorrectly formatted."
193 : ),
194 : AWS_DEFINE_ERROR_INFO_COMMON(
195 : AWS_ERROR_UNIMPLEMENTED,
196 : "A function was called, but is not implemented."
197 : ),
198 : AWS_DEFINE_ERROR_INFO_COMMON(
199 : AWS_ERROR_INVALID_STATE,
200 : "An invalid state was encountered."
201 : ),
202 : AWS_DEFINE_ERROR_INFO_COMMON(
203 : AWS_ERROR_ENVIRONMENT_GET,
204 : "System call failure when getting an environment variable."
205 : ),
206 : AWS_DEFINE_ERROR_INFO_COMMON(
207 : AWS_ERROR_ENVIRONMENT_SET,
208 : "System call failure when setting an environment variable."
209 : ),
210 : AWS_DEFINE_ERROR_INFO_COMMON(
211 : AWS_ERROR_ENVIRONMENT_UNSET,
212 : "System call failure when unsetting an environment variable."
213 : ),
214 : AWS_DEFINE_ERROR_INFO_COMMON(
215 : AWS_ERROR_SYS_CALL_FAILURE,
216 : "System call failure"),
217 : AWS_DEFINE_ERROR_INFO_COMMON(
218 : AWS_ERROR_FILE_INVALID_PATH,
219 : "Invalid file path."),
220 : AWS_DEFINE_ERROR_INFO_COMMON(
221 : AWS_ERROR_MAX_FDS_EXCEEDED,
222 : "The maximum number of fds has been exceeded."),
223 : AWS_DEFINE_ERROR_INFO_COMMON(
224 : AWS_ERROR_NO_PERMISSION,
225 : "User does not have permission to perform the requested action."),
226 : AWS_DEFINE_ERROR_INFO_COMMON(
227 : AWS_ERROR_STREAM_UNSEEKABLE,
228 : "Stream does not support seek operations"),
229 : AWS_DEFINE_ERROR_INFO_COMMON(
230 : AWS_ERROR_C_STRING_BUFFER_NOT_NULL_TERMINATED,
231 : "A c-string like buffer was passed but a null terminator was not found within the bounds of the buffer."),
232 : AWS_DEFINE_ERROR_INFO_COMMON(
233 : AWS_ERROR_STRING_MATCH_NOT_FOUND,
234 : "The specified substring was not present in the input string."),
235 : AWS_DEFINE_ERROR_INFO_COMMON(
236 : AWS_ERROR_DIVIDE_BY_ZERO,
237 : "Attempt to divide a number by zero."),
238 : };
239 : /* clang-format on */
240 :
241 : static struct aws_error_info_list s_list = {
242 : .error_list = errors,
243 : .count = AWS_ARRAY_SIZE(errors),
244 : };
245 :
246 : static struct aws_log_subject_info s_common_log_subject_infos[] = {
247 : DEFINE_LOG_SUBJECT_INFO(
248 : AWS_LS_COMMON_GENERAL,
249 : "aws-c-common",
250 : "Subject for aws-c-common logging that doesn't belong to any particular category"),
251 : DEFINE_LOG_SUBJECT_INFO(
252 : AWS_LS_COMMON_TASK_SCHEDULER,
253 : "task-scheduler",
254 : "Subject for task scheduler or task specific logging."),
255 : DEFINE_LOG_SUBJECT_INFO(AWS_LS_COMMON_THREAD, "thread", "Subject for logging thread related functions."),
256 : DEFINE_LOG_SUBJECT_INFO(AWS_LS_COMMON_XML_PARSER, "xml-parser", "Subject for xml parser specific logging."),
257 : DEFINE_LOG_SUBJECT_INFO(AWS_LS_COMMON_MEMTRACE, "memtrace", "Output from the aws_mem_trace_dump function"),
258 : };
259 :
260 : static struct aws_log_subject_info_list s_common_log_subject_list = {
261 : .subject_list = s_common_log_subject_infos,
262 : .count = AWS_ARRAY_SIZE(s_common_log_subject_infos),
263 : };
264 :
265 : static bool s_common_library_initialized = false;
266 :
267 0 : void aws_common_library_init(struct aws_allocator *allocator) {
268 0 : (void)allocator;
269 0 :
270 0 : if (!s_common_library_initialized) {
271 0 : s_common_library_initialized = true;
272 0 : aws_register_error_info(&s_list);
273 0 : aws_register_log_subject_info_list(&s_common_log_subject_list);
274 0 : aws_thread_initialize_thread_management();
275 0 :
276 0 : /* NUMA is funky and we can't rely on libnuma.so being available. We also don't want to take a hard dependency on it,
277 0 : * try and load it if we can. */
278 0 : #if !defined(_WIN32) && !defined(WIN32)
279 0 : /* libnuma defines set_mempolicy() as a WEAK symbol. Loading into the global symbol table overwrites symbols and
280 0 : assumptions due to the way loaders and dlload are often implemented and those symbols are defined by things
281 0 : like libpthread.so on some unix distros. Sorry about the memory usage here, but it's our only safe choice.
282 0 : Also, please don't do numa configurations if memory is your economic bottlneck. */
283 0 : g_libnuma_handle = dlopen("libnuma.so", RTLD_LOCAL);
284 0 :
285 0 : /* turns out so versioning is really inconsistent these days */
286 0 : if (!g_libnuma_handle) {
287 0 : g_libnuma_handle = dlopen("libnuma.so.1", RTLD_LOCAL);
288 0 : }
289 0 :
290 0 : if (!g_libnuma_handle) {
291 0 : g_libnuma_handle = dlopen("libnuma.so.2", RTLD_LOCAL);
292 0 : }
293 0 :
294 0 : if (g_libnuma_handle) {
295 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: libnuma.so loaded");
296 0 : *(void **)(&g_set_mempolicy_ptr) = dlsym(g_libnuma_handle, "set_mempolicy");
297 0 : if (g_set_mempolicy_ptr) {
298 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: set_mempolicy() loaded");
299 0 : } else {
300 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: set_mempolicy() failed to load");
301 0 : }
302 0 :
303 0 : *(void **)(&g_numa_available_ptr) = dlsym(g_libnuma_handle, "numa_available");
304 0 : if (g_numa_available_ptr) {
305 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: numa_available() loaded");
306 0 : } else {
307 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: numa_available() failed to load");
308 0 : }
309 0 :
310 0 : *(void **)(&g_numa_num_configured_nodes_ptr) = dlsym(g_libnuma_handle, "numa_num_configured_nodes");
311 0 : if (g_numa_num_configured_nodes_ptr) {
312 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: numa_num_configured_nodes() loaded");
313 0 : } else {
314 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: numa_num_configured_nodes() failed to load");
315 0 : }
316 0 :
317 0 : *(void **)(&g_numa_num_possible_cpus_ptr) = dlsym(g_libnuma_handle, "numa_num_possible_cpus");
318 0 : if (g_numa_num_possible_cpus_ptr) {
319 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: numa_num_possible_cpus() loaded");
320 0 : } else {
321 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: numa_num_possible_cpus() failed to load");
322 0 : }
323 0 :
324 0 : *(void **)(&g_numa_node_of_cpu_ptr) = dlsym(g_libnuma_handle, "numa_node_of_cpu");
325 0 : if (g_numa_node_of_cpu_ptr) {
326 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: numa_node_of_cpu() loaded");
327 0 : } else {
328 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: numa_node_of_cpu() failed to load");
329 0 : }
330 0 :
331 0 : } else {
332 0 : AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "static: libnuma.so failed to load");
333 0 : }
334 0 : #endif
335 0 : }
336 0 : }
337 :
338 0 : void aws_common_library_clean_up(void) {
339 0 : if (s_common_library_initialized) {
340 0 : s_common_library_initialized = false;
341 0 : aws_thread_join_all_managed();
342 0 : aws_unregister_error_info(&s_list);
343 0 : aws_unregister_log_subject_info_list(&s_common_log_subject_list);
344 0 : #if !defined(_WIN32) && !defined(WIN32)
345 0 : if (g_libnuma_handle) {
346 0 : dlclose(g_libnuma_handle);
347 0 : }
348 0 : #endif
349 0 : }
350 0 : }
351 :
352 0 : void aws_common_fatal_assert_library_initialized(void) {
353 0 : if (!s_common_library_initialized) {
354 0 : fprintf(
355 0 : stderr, "%s", "aws_common_library_init() must be called before using any functionality in aws-c-common.");
356 0 :
357 0 : AWS_FATAL_ASSERT(s_common_library_initialized);
358 0 : }
359 0 : }
360 :
361 : #ifdef _MSC_VER
362 : # pragma warning(pop)
363 : #endif
|