1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #ifdef HITLS_BSL_ERR
18
19 #include <stdbool.h>
20 #include "securec.h"
21 #include "bsl_log_internal.h"
22 #include "bsl_log.h"
23 #include "bsl_sal.h"
24 #include "avl.h"
25 #include "bsl_err.h"
26 #include "bsl_errno.h"
27 #include "bsl_binlog_id.h"
28 #include "bsl_err_internal.h"
29
30 #define ERR_FLAG_POP_MARK 0x01
31
32 /* Error information stack size */
33 #define SAL_MAX_ERROR_STACK 20
34
35 /* Error information stack */
36 typedef struct {
37 /* Current point location to the stack. When the value is -1, the stack is empty. */
38 uint16_t bottom; /* Stack bottom */
39 uint16_t top; /* Stack top */
40 /* Prevent error stacks from being cleared. Currently, this parameter is used in asynchronous cases. */
41 uint32_t flag;
42
43 /* Store the error code information of a specific thread */
44 int32_t errorStack[SAL_MAX_ERROR_STACK];
45
46 /* Error code flag, which is used to partially clear and prevent side channel attack. */
47 uint32_t errorFlags[SAL_MAX_ERROR_STACK];
48
49 /* store the error file name. */
50 const char *filename[SAL_MAX_ERROR_STACK];
51
52 /* store the line number of the file where the error occurs */
53 uint32_t line[SAL_MAX_ERROR_STACK];
54 } ErrorCodeStack;
55
56 /* Avl tree root node of the error stack. */
57 static BSL_AvlTree *g_avlRoot = NULL;
58
59 /* Error description root node */
60 static BSL_AvlTree *g_descRoot = NULL;
61
62 /* Current number of AVL nodes */
63 static uint32_t g_avlNodeCount = 0;
64
65 /* Maximum number of nodes allowed by the AVL tree */
66 static uint32_t g_maxAvlNodes = 0x0000FFFF;
67
68 /* Check the initialization status. 0 means false, if the value is not 0, it means true. Run once. */
69 static uint32_t g_isErrInit = 0;
70
71 /* Handle of the thread lock */
72 static BSL_SAL_ThreadLockHandle g_errLock = NULL;
73
ErrAutoInit(void)74 static void ErrAutoInit(void)
75 {
76 /* Attempting self-initialization in abnormal conditions */
77 (void)BSL_ERR_Init();
78 }
79
BSL_ERR_Init(void)80 int32_t BSL_ERR_Init(void)
81 {
82 if (g_errLock != NULL) {
83 return BSL_SUCCESS;
84 }
85
86 return BSL_SAL_ThreadLockNew(&g_errLock);
87 }
88
BSL_ERR_DeInit(void)89 void BSL_ERR_DeInit(void)
90 {
91 g_isErrInit = 0;
92 if (g_errLock == NULL) {
93 return;
94 }
95 BSL_SAL_ThreadLockFree(g_errLock);
96 g_errLock = NULL;
97 return;
98 }
99
StackReset(ErrorCodeStack * stack)100 static void StackReset(ErrorCodeStack *stack)
101 {
102 if (stack != NULL) {
103 (void)memset_s(stack, sizeof(*stack), 0, sizeof(*stack));
104 }
105 }
106
StackResetIndex(ErrorCodeStack * stack,uint32_t i)107 static void StackResetIndex(ErrorCodeStack *stack, uint32_t i)
108 {
109 bool invalid = stack == NULL || i >= SAL_MAX_ERROR_STACK;
110 if (!invalid) {
111 stack->errorStack[i] = 0;
112 stack->line[i] = 0;
113 stack->filename[i] = NULL;
114 stack->errorFlags[i] = 0;
115 }
116 }
117
StackDataFree(BSL_ElementData data)118 static void StackDataFree(BSL_ElementData data)
119 {
120 BSL_SAL_FREE(data);
121 }
122
GetStack(void)123 static ErrorCodeStack *GetStack(void)
124 {
125 const uint64_t threadId = BSL_SAL_ThreadGetId();
126 BSL_AvlTree *curNode = BSL_AVL_SearchNode(g_avlRoot, threadId);
127 if (curNode != NULL) {
128 /* If an error stack exists, directly returned. */
129 return curNode->data;
130 }
131 /* need to create an error stack */
132 if (g_avlNodeCount >= g_maxAvlNodes) {
133 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID05004, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
134 "New Avl Node failed.", 0, 0, 0, 0);
135 return NULL;
136 }
137 ErrorCodeStack *stack = (ErrorCodeStack *)BSL_SAL_Calloc(1, sizeof(ErrorCodeStack));
138 if (stack == NULL) {
139 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID05005, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
140 "CALLOC error code stack failed", 0, 0, 0, 0);
141 return NULL;
142 }
143 BSL_AvlTree *node = BSL_AVL_MakeLeafNode(stack);
144 if (node == NULL) {
145 StackDataFree(stack);
146 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID05006, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
147 "avl insert node failed, threadId %lu", threadId, 0, 0, 0);
148 return NULL;
149 }
150 g_avlNodeCount++;
151 /* upper layer has ensured that the threadId node does not exist. */
152 g_avlRoot = BSL_AVL_InsertNode(g_avlRoot, threadId, node);
153 return stack;
154 }
155
BSL_ERR_PushError(int32_t err,const char * file,uint32_t lineNo)156 void BSL_ERR_PushError(int32_t err, const char *file, uint32_t lineNo)
157 {
158 if (err == BSL_SUCCESS) {
159 /* push success is not allowed. */
160 return;
161 }
162
163 int32_t ret = BSL_SAL_ThreadWriteLock(g_errLock);
164 if (ret != BSL_SUCCESS) {
165 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID05007, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
166 "acquire lock failed when pushing error, threadId %llu, error code %d", BSL_SAL_ThreadGetId(), ret, 0, 0);
167 return;
168 }
169
170 ErrorCodeStack *stack = GetStack();
171 if (stack != NULL) {
172 if (stack->top == stack->bottom && stack->errorStack[stack->top] != 0) {
173 stack->bottom = (stack->bottom + 1) % SAL_MAX_ERROR_STACK;
174 }
175 stack->errorFlags[stack->top] = 0;
176 stack->errorStack[stack->top] = err;
177 stack->filename[stack->top] = file;
178 stack->line[stack->top] = lineNo;
179 stack->top = (stack->top + 1) % SAL_MAX_ERROR_STACK;
180 }
181
182 BSL_SAL_ThreadUnlock(g_errLock);
183 }
184
BSL_ERR_ClearError(void)185 void BSL_ERR_ClearError(void)
186 {
187 (void)BSL_SAL_ThreadRunOnce(&g_isErrInit, ErrAutoInit);
188
189 uint64_t threadId = BSL_SAL_ThreadGetId();
190 int32_t ret = BSL_SAL_ThreadWriteLock(g_errLock);
191 if (ret != BSL_SUCCESS) {
192 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID05008, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
193 "acquire lock failed when clearing error, threadId %llu", threadId, 0, 0, 0);
194 return;
195 }
196
197 BSL_AvlTree *curNode = BSL_AVL_SearchNode(g_avlRoot, threadId);
198 if (curNode != NULL) {
199 /* Will not be NULL. */
200 ErrorCodeStack *errStack = curNode->data;
201 if (errStack->flag == 0) {
202 StackReset(errStack);
203 }
204 }
205
206 BSL_SAL_ThreadUnlock(g_errLock);
207 }
208
BSL_ERR_RemoveErrorStack(bool isRemoveAll)209 void BSL_ERR_RemoveErrorStack(bool isRemoveAll)
210 {
211 (void)BSL_SAL_ThreadRunOnce(&g_isErrInit, ErrAutoInit);
212
213 int32_t ret = BSL_SAL_ThreadWriteLock(g_errLock);
214 if (ret != BSL_SUCCESS) {
215 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID05009, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
216 "acquire lock failed when removing error stack, threadId %llu", BSL_SAL_ThreadGetId(), 0, 0, 0);
217 return;
218 }
219
220 if (g_avlRoot != NULL) {
221 if (isRemoveAll) {
222 BSL_AVL_DeleteTree(g_avlRoot, StackDataFree);
223 g_avlNodeCount = 0;
224 g_avlRoot = NULL;
225 } else {
226 uint64_t threadId = BSL_SAL_ThreadGetId();
227 BSL_AvlTree *curNode = BSL_AVL_SearchNode(g_avlRoot, threadId);
228 if (curNode != NULL) {
229 g_avlNodeCount--;
230 g_avlRoot = BSL_AVL_DeleteNode(g_avlRoot, threadId, StackDataFree);
231 }
232 }
233 }
234
235 BSL_SAL_ThreadUnlock(g_errLock);
236 }
237
238 /* Obtain the index. 'last' indicates that the last or first error code is obtained. */
GetIndex(ErrorCodeStack * errStack,bool last)239 static uint16_t GetIndex(ErrorCodeStack *errStack, bool last)
240 {
241 uint16_t idx;
242
243 if (last) {
244 idx = errStack->top - 1;
245 if (idx >= SAL_MAX_ERROR_STACK) {
246 idx = SAL_MAX_ERROR_STACK - 1;
247 }
248 } else {
249 idx = errStack->bottom;
250 }
251
252 return idx;
253 }
254
255 /* If clr is true, the external operation is get. If clr is false, the external operation is peek.
256 The get operation cleans up after the error information is obtained, while the peek operation does not.
257 If last is true, the last error code at the top of the stack is obtained.
258 If last is false, the first error code at the bottom of the stack is obtained. */
GetErrorInfo(const char ** file,uint32_t * lineNo,bool clr,bool last)259 static int32_t GetErrorInfo(const char **file, uint32_t *lineNo, bool clr, bool last)
260 {
261 uint16_t idx;
262
263 int32_t ret = BSL_SAL_ThreadReadLock(g_errLock);
264 if (ret != BSL_SUCCESS) {
265 return BSL_ERR_ERR_ACQUIRE_READ_LOCK_FAIL;
266 }
267
268 if (g_avlRoot == NULL) {
269 /* If avlRoot is empty, no thread push error. Therefore, error should be success. */
270 BSL_SAL_ThreadUnlock(g_errLock);
271 return BSL_SUCCESS;
272 }
273
274 const uint64_t threadId = BSL_SAL_ThreadGetId();
275 BSL_AvlTree *curNode = BSL_AVL_SearchNode(g_avlRoot, threadId);
276 if (curNode == NULL) {
277 /* If curNode is empty, the current thread does not have push error. Therefore, error should be success. */
278 BSL_SAL_ThreadUnlock(g_errLock);
279 return BSL_SUCCESS;
280 }
281
282 ErrorCodeStack *errStack = curNode->data; /* will not be null */
283
284 idx = GetIndex(errStack, last);
285 if (errStack->errorStack[idx] == 0) { /* error stack is empty */
286 BSL_SAL_ThreadUnlock(g_errLock);
287 return BSL_SUCCESS;
288 }
289
290 int32_t errorCode = errStack->errorStack[idx]; /* Obtain the specified error ID. */
291 uint32_t fileLine = errStack->line[idx]; /* Obtain the specified line number. */
292 const char *f = errStack->filename[idx]; /* Obtain the specified file name. */
293 if (clr) {
294 StackResetIndex(errStack, idx);
295 if (last) {
296 errStack->top = idx;
297 } else {
298 errStack->bottom = (idx + 1) % SAL_MAX_ERROR_STACK;
299 }
300 }
301
302 BSL_SAL_ThreadUnlock(g_errLock);
303
304 if (file != NULL && lineNo != NULL) { /* both together, there's no point in getting only one of them. */
305 if (f == NULL) {
306 *file = "NA";
307 *lineNo = 0;
308 } else {
309 *file = f;
310 *lineNo = fileLine;
311 }
312 }
313
314 return errorCode;
315 }
316
GetLastErrorInfo(const char ** file,uint32_t * lineNo,bool clr)317 static int32_t GetLastErrorInfo(const char **file, uint32_t *lineNo, bool clr)
318 {
319 return GetErrorInfo(file, lineNo, clr, true);
320 }
321
GetFirstErrorInfo(const char ** file,uint32_t * lineNo,bool clr)322 static int32_t GetFirstErrorInfo(const char **file, uint32_t *lineNo, bool clr)
323 {
324 return GetErrorInfo(file, lineNo, clr, false);
325 }
326
BSL_ERR_GetLastErrorFileLine(const char ** file,uint32_t * lineNo)327 int32_t BSL_ERR_GetLastErrorFileLine(const char **file, uint32_t *lineNo)
328 {
329 return GetLastErrorInfo(file, lineNo, true);
330 }
331
BSL_ERR_PeekLastErrorFileLine(const char ** file,uint32_t * lineNo)332 int32_t BSL_ERR_PeekLastErrorFileLine(const char **file, uint32_t *lineNo)
333 {
334 return GetLastErrorInfo(file, lineNo, false);
335 }
336
BSL_ERR_GetLastError(void)337 int32_t BSL_ERR_GetLastError(void)
338 {
339 return GetLastErrorInfo(NULL, NULL, true);
340 }
341
BSL_ERR_GetErrorFileLine(const char ** file,uint32_t * lineNo)342 int32_t BSL_ERR_GetErrorFileLine(const char **file, uint32_t *lineNo)
343 {
344 return GetFirstErrorInfo(file, lineNo, true);
345 }
346
BSL_ERR_PeekErrorFileLine(const char ** file,uint32_t * lineNo)347 int32_t BSL_ERR_PeekErrorFileLine(const char **file, uint32_t *lineNo)
348 {
349 return GetFirstErrorInfo(file, lineNo, false);
350 }
351
BSL_ERR_GetError(void)352 int32_t BSL_ERR_GetError(void)
353 {
354 return GetFirstErrorInfo(NULL, NULL, true);
355 }
356
AddErrDesc(const BSL_ERR_Desc * desc)357 static int32_t AddErrDesc(const BSL_ERR_Desc *desc)
358 {
359 if (desc->error < 0) {
360 return BSL_INTERNAL_EXCEPTION;
361 }
362 BSL_AvlTree *curNode = BSL_AVL_SearchNode(g_descRoot, (uint64_t)desc->error);
363 if (curNode != NULL) {
364 curNode->data = (BSL_ElementData)(uintptr_t)(desc->string);
365 return BSL_SUCCESS;
366 }
367 BSL_AvlTree *node = BSL_AVL_MakeLeafNode((BSL_ElementData)(uintptr_t)(desc->string));
368 if (node == NULL) {
369 return BSL_INTERNAL_EXCEPTION;
370 }
371 g_descRoot = BSL_AVL_InsertNode(g_descRoot, (uint64_t)desc->error, node);
372 return BSL_SUCCESS;
373 }
374
BSL_ERR_AddErrStringBatch(const BSL_ERR_Desc * descList,uint32_t num)375 int32_t BSL_ERR_AddErrStringBatch(const BSL_ERR_Desc *descList, uint32_t num)
376 {
377 if (descList == NULL || num == 0) {
378 return BSL_NULL_INPUT;
379 }
380 int32_t ret = BSL_SAL_ThreadWriteLock(g_errLock);
381 if (ret != BSL_SUCCESS) {
382 return ret;
383 }
384 for (uint32_t i = 0; i < num; i++) {
385 ret = AddErrDesc(&descList[i]);
386 if (ret != BSL_SUCCESS) {
387 break;
388 }
389 }
390 BSL_SAL_ThreadUnlock(g_errLock);
391 return ret;
392 }
393
BSL_ERR_RemoveErrStringBatch(void)394 void BSL_ERR_RemoveErrStringBatch(void)
395 {
396 int32_t ret = BSL_SAL_ThreadWriteLock(g_errLock);
397 if (ret != BSL_SUCCESS) {
398 BSL_LOG_BINLOG_FIXLEN(BINLOG_ID05010, BSL_LOG_LEVEL_ERR, BSL_LOG_BINLOG_TYPE_RUN,
399 "acquire lock failed when removing error string, threadId %llu", BSL_SAL_ThreadGetId(), 0, 0, 0);
400 return;
401 }
402 if (g_descRoot != NULL) {
403 BSL_AVL_DeleteTree(g_descRoot, NULL);
404 g_descRoot = NULL;
405 }
406 BSL_SAL_ThreadUnlock(g_errLock);
407 }
408
BSL_ERR_GetString(int32_t error)409 const char *BSL_ERR_GetString(int32_t error)
410 {
411 if (error < 0) {
412 return NULL;
413 }
414 int32_t ret = BSL_SAL_ThreadWriteLock(g_errLock);
415 if (ret != BSL_SUCCESS) {
416 return NULL;
417 }
418 if (g_descRoot == NULL) {
419 BSL_SAL_ThreadUnlock(g_errLock);
420 return NULL;
421 }
422 BSL_AvlTree *curNode = BSL_AVL_SearchNode(g_descRoot, (uint64_t)error);
423 if (curNode == NULL) {
424 BSL_SAL_ThreadUnlock(g_errLock);
425 return NULL;
426 }
427 const char *str = curNode->data;
428 BSL_SAL_ThreadUnlock(g_errLock);
429 return str;
430 }
431
BSL_LIST_WriteLockCreate(ErrorCodeStack ** errStack,uint32_t * top)432 static int32_t BSL_LIST_WriteLockCreate(ErrorCodeStack **errStack, uint32_t *top)
433 {
434 int32_t ret = BSL_SAL_ThreadWriteLock(g_errLock);
435 if (ret != BSL_SUCCESS) {
436 return BSL_ERR_ERR_ACQUIRE_WRITE_LOCK_FAIL;
437 }
438
439 if (g_avlRoot == NULL) {
440 BSL_SAL_ThreadUnlock(g_errLock);
441 return BSL_ERR_ERR_NO_STACK;
442 }
443
444 const uint64_t threadId = BSL_SAL_ThreadGetId();
445 BSL_AvlTree *curNode = BSL_AVL_SearchNode(g_avlRoot, threadId);
446 if (curNode == NULL) {
447 BSL_SAL_ThreadUnlock(g_errLock);
448 return BSL_ERR_ERR_NO_STACK;
449 }
450
451 *errStack = curNode->data; /* will not be null */
452 if (top == NULL) {
453 return ret;
454 }
455 *top = (*errStack)->top - 1;
456 if (*top >= SAL_MAX_ERROR_STACK) {
457 *top = SAL_MAX_ERROR_STACK - 1;
458 }
459 return ret;
460 }
461
BSL_ERR_SetMark(void)462 int32_t BSL_ERR_SetMark(void)
463 {
464 ErrorCodeStack *errStack = NULL;
465 uint32_t top = 0;
466 int32_t ret = BSL_LIST_WriteLockCreate(&errStack, &top);
467 if (ret != BSL_SUCCESS) {
468 return ret;
469 }
470
471 if (errStack->errorStack[top] == 0) { /* error stack is empty */
472 BSL_SAL_ThreadUnlock(g_errLock);
473 return BSL_ERR_ERR_NO_ERROR;
474 }
475
476 errStack->errorFlags[top] |= ERR_FLAG_POP_MARK;
477
478 BSL_SAL_ThreadUnlock(g_errLock);
479 return BSL_SUCCESS;
480 }
481
BSL_ERR_PopToMark(void)482 int32_t BSL_ERR_PopToMark(void)
483 {
484 ErrorCodeStack *errStack = NULL;
485 uint32_t top = 0;
486 int32_t ret = BSL_LIST_WriteLockCreate(&errStack, &top);
487 if (ret != BSL_SUCCESS) {
488 return ret;
489 }
490
491 while (errStack->errorStack[top] != 0 && ((errStack->errorFlags[top] & ERR_FLAG_POP_MARK) == 0)) {
492 StackResetIndex(errStack, top);
493 top--;
494 if (top >= SAL_MAX_ERROR_STACK) {
495 top = SAL_MAX_ERROR_STACK - 1;
496 }
497 }
498 errStack->top = (top + 1) % SAL_MAX_ERROR_STACK;
499
500 if (errStack->errorStack[top] == 0) {
501 BSL_SAL_ThreadUnlock(g_errLock);
502 return BSL_ERR_ERR_NO_MARK;
503 }
504
505 errStack->errorFlags[top] &= ~ERR_FLAG_POP_MARK;
506
507 BSL_SAL_ThreadUnlock(g_errLock);
508 return BSL_SUCCESS;
509 }
510
BSL_ERR_ClearLastMark(void)511 int32_t BSL_ERR_ClearLastMark(void)
512 {
513 ErrorCodeStack *errStack = NULL;
514 uint32_t top = 0;
515 int32_t ret = BSL_LIST_WriteLockCreate(&errStack, &top);
516 if (ret != BSL_SUCCESS) {
517 return ret;
518 }
519
520 while (errStack->errorStack[top] != 0 && ((errStack->errorFlags[top] & ERR_FLAG_POP_MARK) == 0)) {
521 top--;
522 if (top >= SAL_MAX_ERROR_STACK) {
523 top = SAL_MAX_ERROR_STACK - 1;
524 }
525 }
526 errStack->errorFlags[top] &= ~ERR_FLAG_POP_MARK;
527
528 BSL_SAL_ThreadUnlock(g_errLock);
529 return BSL_SUCCESS;
530 }
531
532 #endif /* HITLS_BSL_ERR */
533