• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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