1 | /* |
2 | * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"). |
5 | * You may not use this file except in compliance with the License. |
6 | * A copy of the License is located at |
7 | * |
8 | * http://aws.amazon.com/apache2.0 |
9 | * |
10 | * or in the "license" file accompanying this file. This file is distributed |
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
12 | * express or implied. See the License for the specific language governing |
13 | * permissions and limitations under the License. |
14 | */ |
15 | |
16 | #include <aws/common/common.h> |
17 | #include <aws/common/logging.h> |
18 | #include <aws/common/math.h> |
19 | |
20 | #include <stdarg.h> |
21 | #include <stdlib.h> |
22 | |
23 | #ifdef _WIN32 |
24 | # include <Windows.h> |
25 | #endif |
26 | |
27 | #ifdef __MACH__ |
28 | # include <CoreFoundation/CoreFoundation.h> |
29 | #endif |
30 | |
31 | /* turn off unused named parameter warning on msvc.*/ |
32 | #ifdef _MSC_VER |
33 | # pragma warning(push) |
34 | # pragma warning(disable : 4100) |
35 | #endif |
36 | |
37 | void aws_secure_zero(void *pBuf, size_t bufsize) { |
38 | #if defined(_WIN32) |
39 | SecureZeroMemory(pBuf, bufsize); |
40 | #else |
41 | /* We cannot use memset_s, even on a C11 compiler, because that would require |
42 | * that __STDC_WANT_LIB_EXT1__ be defined before the _first_ inclusion of string.h. |
43 | * |
44 | * We'll try to work around this by using inline asm on GCC-like compilers, |
45 | * and by exposing the buffer pointer in a volatile local pointer elsewhere. |
46 | */ |
47 | # if defined(__GNUC__) || defined(__clang__) |
48 | memset(pBuf, 0, bufsize); |
49 | /* This inline asm serves to convince the compiler that the buffer is (somehow) still |
50 | * used after the zero, and therefore that the optimizer can't eliminate the memset. |
51 | */ |
52 | __asm__ __volatile__("" /* The asm doesn't actually do anything. */ |
53 | : /* no outputs */ |
54 | /* Tell the compiler that the asm code has access to the pointer to the buffer, |
55 | * and therefore it might be reading the (now-zeroed) buffer. |
56 | * Without this. clang/LLVM 9.0.0 optimizes away a memset of a stack buffer. |
57 | */ |
58 | : "r" (pBuf) |
59 | /* Also clobber memory. While this seems like it might be unnecessary - after all, |
60 | * it's enough that the asm might read the buffer, right? - in practice GCC 7.3.0 |
61 | * seems to optimize a zero of a stack buffer without it. |
62 | */ |
63 | : "memory" ); |
64 | # else // not GCC/clang |
65 | /* We don't have access to inline asm, since we're on a non-GCC platform. Move the pointer |
66 | * through a volatile pointer in an attempt to confuse the optimizer. |
67 | */ |
68 | volatile void *pVolBuf = pBuf; |
69 | memset(pVolBuf, 0, bufsize); |
70 | # endif // #else not GCC/clang |
71 | #endif // #else not windows |
72 | } |
73 | |
74 | #define AWS_DEFINE_ERROR_INFO_COMMON(C, ES) [(C)-0x0000] = AWS_DEFINE_ERROR_INFO(C, ES, "aws-c-common") |
75 | /* clang-format off */ |
76 | static struct aws_error_info errors[] = { |
77 | AWS_DEFINE_ERROR_INFO_COMMON( |
78 | AWS_ERROR_SUCCESS, |
79 | "Success." ), |
80 | AWS_DEFINE_ERROR_INFO_COMMON( |
81 | AWS_ERROR_OOM, |
82 | "Out of memory." ), |
83 | AWS_DEFINE_ERROR_INFO_COMMON( |
84 | AWS_ERROR_UNKNOWN, |
85 | "Unknown error." ), |
86 | AWS_DEFINE_ERROR_INFO_COMMON( |
87 | AWS_ERROR_SHORT_BUFFER, |
88 | "Buffer is not large enough to hold result." ), |
89 | AWS_DEFINE_ERROR_INFO_COMMON( |
90 | AWS_ERROR_OVERFLOW_DETECTED, |
91 | "Fixed size value overflow was detected." ), |
92 | AWS_DEFINE_ERROR_INFO_COMMON( |
93 | AWS_ERROR_UNSUPPORTED_OPERATION, |
94 | "Unsupported operation." ), |
95 | AWS_DEFINE_ERROR_INFO_COMMON( |
96 | AWS_ERROR_INVALID_BUFFER_SIZE, |
97 | "Invalid buffer size." ), |
98 | AWS_DEFINE_ERROR_INFO_COMMON( |
99 | AWS_ERROR_INVALID_HEX_STR, |
100 | "Invalid hex string." ), |
101 | AWS_DEFINE_ERROR_INFO_COMMON( |
102 | AWS_ERROR_INVALID_BASE64_STR, |
103 | "Invalid base64 string." ), |
104 | AWS_DEFINE_ERROR_INFO_COMMON( |
105 | AWS_ERROR_INVALID_INDEX, |
106 | "Invalid index for list access." ), |
107 | AWS_DEFINE_ERROR_INFO_COMMON( |
108 | AWS_ERROR_THREAD_INVALID_SETTINGS, |
109 | "Invalid thread settings." ), |
110 | AWS_DEFINE_ERROR_INFO_COMMON( |
111 | AWS_ERROR_THREAD_INSUFFICIENT_RESOURCE, |
112 | "Insufficent resources for thread." ), |
113 | AWS_DEFINE_ERROR_INFO_COMMON( |
114 | AWS_ERROR_THREAD_NO_PERMISSIONS, |
115 | "Insufficient permissions for thread operation." ), |
116 | AWS_DEFINE_ERROR_INFO_COMMON( |
117 | AWS_ERROR_THREAD_NOT_JOINABLE, |
118 | "Thread not joinable." ), |
119 | AWS_DEFINE_ERROR_INFO_COMMON( |
120 | AWS_ERROR_THREAD_NO_SUCH_THREAD_ID, |
121 | "No such thread ID." ), |
122 | AWS_DEFINE_ERROR_INFO_COMMON( |
123 | AWS_ERROR_THREAD_DEADLOCK_DETECTED, |
124 | "Deadlock detected in thread." ), |
125 | AWS_DEFINE_ERROR_INFO_COMMON( |
126 | AWS_ERROR_MUTEX_NOT_INIT, |
127 | "Mutex not initialized." ), |
128 | AWS_DEFINE_ERROR_INFO_COMMON( |
129 | AWS_ERROR_MUTEX_TIMEOUT, |
130 | "Mutex operation timed out." ), |
131 | AWS_DEFINE_ERROR_INFO_COMMON( |
132 | AWS_ERROR_MUTEX_CALLER_NOT_OWNER, |
133 | "The caller of a mutex operation was not the owner." ), |
134 | AWS_DEFINE_ERROR_INFO_COMMON( |
135 | AWS_ERROR_MUTEX_FAILED, |
136 | "Mutex operation failed." ), |
137 | AWS_DEFINE_ERROR_INFO_COMMON( |
138 | AWS_ERROR_COND_VARIABLE_INIT_FAILED, |
139 | "Condition variable initialization failed." ), |
140 | AWS_DEFINE_ERROR_INFO_COMMON( |
141 | AWS_ERROR_COND_VARIABLE_TIMED_OUT, |
142 | "Condition variable wait timed out." ), |
143 | AWS_DEFINE_ERROR_INFO_COMMON( |
144 | AWS_ERROR_COND_VARIABLE_ERROR_UNKNOWN, |
145 | "Condition variable unknown error." ), |
146 | AWS_DEFINE_ERROR_INFO_COMMON( |
147 | AWS_ERROR_CLOCK_FAILURE, |
148 | "Clock operation failed." ), |
149 | AWS_DEFINE_ERROR_INFO_COMMON( |
150 | AWS_ERROR_LIST_EMPTY, |
151 | "Empty list." ), |
152 | AWS_DEFINE_ERROR_INFO_COMMON( |
153 | AWS_ERROR_DEST_COPY_TOO_SMALL, |
154 | "Destination of copy is too small." ), |
155 | AWS_DEFINE_ERROR_INFO_COMMON( |
156 | AWS_ERROR_LIST_EXCEEDS_MAX_SIZE, |
157 | "A requested operation on a list would exceed it's max size." ), |
158 | AWS_DEFINE_ERROR_INFO_COMMON( |
159 | AWS_ERROR_LIST_STATIC_MODE_CANT_SHRINK, |
160 | "Attempt to shrink a list in static mode." ), |
161 | AWS_DEFINE_ERROR_INFO_COMMON( |
162 | AWS_ERROR_PRIORITY_QUEUE_FULL, |
163 | "Attempt to add items to a full preallocated queue in static mode." ), |
164 | AWS_DEFINE_ERROR_INFO_COMMON( |
165 | AWS_ERROR_PRIORITY_QUEUE_EMPTY, |
166 | "Attempt to pop an item from an empty queue." ), |
167 | AWS_DEFINE_ERROR_INFO_COMMON( |
168 | AWS_ERROR_PRIORITY_QUEUE_BAD_NODE, |
169 | "Bad node handle passed to remove." ), |
170 | AWS_DEFINE_ERROR_INFO_COMMON( |
171 | AWS_ERROR_HASHTBL_ITEM_NOT_FOUND, |
172 | "Item not found in hash table." ), |
173 | AWS_DEFINE_ERROR_INFO_COMMON( |
174 | AWS_ERROR_INVALID_DATE_STR, |
175 | "Date string is invalid and cannot be parsed." |
176 | ), |
177 | AWS_DEFINE_ERROR_INFO_COMMON( |
178 | AWS_ERROR_INVALID_ARGUMENT, |
179 | "An invalid argument was passed to a function." |
180 | ), |
181 | AWS_DEFINE_ERROR_INFO_COMMON( |
182 | AWS_ERROR_RANDOM_GEN_FAILED, |
183 | "A call to the random number generator failed. Retry later." |
184 | ), |
185 | AWS_DEFINE_ERROR_INFO_COMMON( |
186 | AWS_ERROR_MALFORMED_INPUT_STRING, |
187 | "An input string was passed to a parser and the string was incorrectly formatted." |
188 | ), |
189 | AWS_DEFINE_ERROR_INFO_COMMON( |
190 | AWS_ERROR_UNIMPLEMENTED, |
191 | "A function was called, but is not implemented." |
192 | ), |
193 | AWS_DEFINE_ERROR_INFO_COMMON( |
194 | AWS_ERROR_INVALID_STATE, |
195 | "An invalid state was encountered." |
196 | ), |
197 | AWS_DEFINE_ERROR_INFO_COMMON( |
198 | AWS_ERROR_ENVIRONMENT_GET, |
199 | "System call failure when getting an environment variable." |
200 | ), |
201 | AWS_DEFINE_ERROR_INFO_COMMON( |
202 | AWS_ERROR_ENVIRONMENT_SET, |
203 | "System call failure when setting an environment variable." |
204 | ), |
205 | AWS_DEFINE_ERROR_INFO_COMMON( |
206 | AWS_ERROR_ENVIRONMENT_UNSET, |
207 | "System call failure when unsetting an environment variable." |
208 | ), |
209 | AWS_DEFINE_ERROR_INFO_COMMON( |
210 | AWS_ERROR_SYS_CALL_FAILURE, |
211 | "System call failure" ), |
212 | AWS_DEFINE_ERROR_INFO_COMMON( |
213 | AWS_ERROR_FILE_INVALID_PATH, |
214 | "Invalid file path." ), |
215 | AWS_DEFINE_ERROR_INFO_COMMON( |
216 | AWS_ERROR_MAX_FDS_EXCEEDED, |
217 | "The maximum number of fds has been exceeded." ), |
218 | AWS_DEFINE_ERROR_INFO_COMMON( |
219 | AWS_ERROR_NO_PERMISSION, |
220 | "User does not have permission to perform the requested action." ), |
221 | AWS_DEFINE_ERROR_INFO_COMMON( |
222 | AWS_ERROR_STREAM_UNSEEKABLE, |
223 | "Stream does not support seek operations" ), |
224 | AWS_DEFINE_ERROR_INFO_COMMON( |
225 | AWS_ERROR_C_STRING_BUFFER_NOT_NULL_TERMINATED, |
226 | "A c-string like buffer was passed but a null terminator was not found within the bounds of the buffer." ), |
227 | AWS_DEFINE_ERROR_INFO_COMMON( |
228 | AWS_ERROR_STRING_MATCH_NOT_FOUND, |
229 | "The specified substring was not present in the input string." ), |
230 | }; |
231 | /* clang-format on */ |
232 | |
233 | static struct aws_error_info_list s_list = { |
234 | .error_list = errors, |
235 | .count = AWS_ARRAY_SIZE(errors), |
236 | }; |
237 | |
238 | static struct aws_log_subject_info s_common_log_subject_infos[] = { |
239 | DEFINE_LOG_SUBJECT_INFO( |
240 | AWS_LS_COMMON_GENERAL, |
241 | "aws-c-common" , |
242 | "Subject for aws-c-common logging that doesn't belong to any particular category" ), |
243 | DEFINE_LOG_SUBJECT_INFO( |
244 | AWS_LS_COMMON_TASK_SCHEDULER, |
245 | "task-scheduler" , |
246 | "Subject for task scheduler or task specific logging." ), |
247 | DEFINE_LOG_SUBJECT_INFO(AWS_LS_COMMON_MEMTRACE, "memtrace" , "Output from the aws_mem_trace_dump function" ), |
248 | }; |
249 | |
250 | static struct aws_log_subject_info_list s_common_log_subject_list = { |
251 | .subject_list = s_common_log_subject_infos, |
252 | .count = AWS_ARRAY_SIZE(s_common_log_subject_infos), |
253 | }; |
254 | |
255 | static bool s_common_library_initialized = false; |
256 | |
257 | void aws_common_library_init(struct aws_allocator *allocator) { |
258 | (void)allocator; |
259 | |
260 | if (!s_common_library_initialized) { |
261 | s_common_library_initialized = true; |
262 | aws_register_error_info(&s_list); |
263 | aws_register_log_subject_info_list(&s_common_log_subject_list); |
264 | } |
265 | } |
266 | |
267 | void aws_common_library_clean_up(void) { |
268 | if (s_common_library_initialized) { |
269 | s_common_library_initialized = false; |
270 | aws_unregister_error_info(&s_list); |
271 | aws_unregister_log_subject_info_list(&s_common_log_subject_list); |
272 | } |
273 | } |
274 | |
275 | void aws_common_fatal_assert_library_initialized(void) { |
276 | if (!s_common_library_initialized) { |
277 | fprintf( |
278 | stderr, "%s" , "aws_common_library_init() must be called before using any functionality in aws-c-common." ); |
279 | |
280 | AWS_FATAL_ASSERT(s_common_library_initialized); |
281 | } |
282 | } |
283 | |
284 | #ifdef _MSC_VER |
285 | # pragma warning(pop) |
286 | #endif |
287 | |