LCOV - code coverage report
Current view: top level - runtime/c/c_base/src - error_manager.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 149 241 61.8 %
Date: 2026-08-27 13:24:42 Functions: 19 22 86.4 %

          Line data    Source code
       1             : /**
       2             :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3             :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4             :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5             :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6             :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7             :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8             :  * See LICENSE in the root of the software repository for the full text of the License.
       9             :  */
      10             : #include <pthread.h>
      11             : #include <string.h>
      12             : #include "securec.h"
      13             : #include "vector.h"
      14             : #include "error_manager.h"
      15             : 
      16             : #define MAX_ARG_NUMBER 3
      17             : #define ERRCODE_LENGTH 6
      18             : #define PERCENT_S_LEN 2
      19             : #define NEWLINE_LEN 2
      20             : #define SPACE_NUMS 8
      21             : typedef struct {
      22             :     char *errorId;
      23             :     char *errorMessage;  // 模板错误message,可能带%s,跟argList是对应的
      24             :     char *possibleCause;
      25             :     char *solution;
      26             :     char *argList[MAX_ARG_NUMBER];
      27             : } ErrorInfoConfig;  // 外部错误码配置
      28             : 
      29             : typedef struct {
      30             :     char *errorId;
      31             :     char *errorMessage;  // 对于外部错误码而言,这里是格式化后的
      32             :     char *possibleCause;
      33             :     char *solution;
      34             :     bool idIsInner;   // 标识errorId是不是常量区
      35             :     bool errIsInner;  // 标识errorMessage是不是常量区
      36             : } ErrorItem;          // 兼容内外部错误信息
      37             : 
      38             : typedef struct {
      39             :     size_t errorMsgLen;    // 存储此次Get时返回的拼接字符串的长度
      40             :     size_t errorMsgSize;   // 上次分配errorMsg内存大小
      41             :     char *errorMsg;        // 存储Get时返回的拼接字符串
      42             :     Vector errorItemList;  // 存储每次Report的错误描述;
      43             : } ErrorInfoThread;
      44             : 
      45             : // g_errorMap必须要保证按errorId保序
      46             : static const ErrorInfoConfig ERROR_MAP[] = {
      47             :     // GE Errors
      48             :     {"E10001", "Value [%s] for parameter [%s] is invalid. Reason: %s", NULL /* possibleCause为空 */,
      49             :      "Try again with a valid argument.", {"value", "parameter", "reason"}},
      50             :     {"E10004", "Value for [--%s] is empty.", NULL, NULL /* solution为空 */, {"parameter"}},
      51             :     {"E10055", "The operation is not supported. Reason: %s", NULL, NULL, {"reason"}},
      52             :     {"E19001", "Failed to open file[%s]. Reason: %s.", NULL,
      53             :      "Fix the error according to the error message.", {"file", "errMsg"}},
      54             :     {"E19025", "Input tensor is invalid. Reason: %s.", NULL, NULL, {"reason"}},
      55             : 
      56             :     // RTS Errors, "EE4001"、"EE4002"、"EE4004"主线没有用到,删除
      57             :     {"EE1001", "The argument is invalid.Reason: %s", NULL, NULL, {"extendInfo"}},
      58             :     // {"EE4001", "Failed to bind the stream to the model. %s", "The stream has been bound to another model.",
      59             :     //  "Remove the repeated binding operation on the stream from the code.", {"extend_info"}},
      60             :     // {"EE4002", "Failed to unbind the stream to the model. %s",
      61             :     //  "1.The stream to be unbound is not bound to the model.   2.The model is running.",
      62             :     //  "1.Check the code to ensure that the stream to be unbound is bound to the model."
      63             :     //  "    2.Ensure that the model is not running.", {"extend_info"}},
      64             :     // {"EE4004", "Failed to enable profiling.  %s", NULL, "Do not enable profiling repeatedly.", {"extend_info"}},
      65             : 
      66             :     //  ACL Errors
      67             :     {"EH0001", "Value [%s] for [%s] is invalid. Reason: %s.", NULL, NULL, {"value", "param", "reason"}},
      68             :     {"EH0002", "Argument [%s] must not be NULL.", NULL, "Try again with a correct pointer argument.", {"param"}},
      69             :     {"EH0003", "Path [%s] is invalid. Reason: %s.", NULL, NULL, {"path", "reason"}},
      70             :     // {"EH0004", "File [%s] is invalid. Reason: %s.", NULL, NULL, {"path", "reason"}},  //主线没用到
      71             :     // {"EH0005", "AIPP argument [%s] is invalid. Reason: %s.", NULL, NULL, {"param", "reason"}}, // AIPP
      72             :     // {"EH0006", "%s is not supported. Reason: %s.", NULL, NULL, {"feature", "reason"}}, // DVPP跟TDT
      73             : 
      74             :     // Profiling Errors
      75             :     {"EK0001", "Value [%s] for [%s] is invalid. Reason: %s.", NULL, NULL, {"value", "param", "reason"}},
      76             :     {"EK0002", "Failed to call %s before calling %s.", NULL, NULL, {"intf1", "intf2"}},
      77             :     {"EK0003", "Failed to set the %s to [%s]. Reason: %s.", NULL, NULL, {"config", "value", "reason"}},
      78             :     {"EK0004", "[%s] is not supported in %s.", NULL, NULL, {"intf", "platform"}},
      79             :     {"EK0201", "Failed to allocate host memory for Profiling: %s.", "Available memory is insufficient.",
      80             :      "Close unused applications.", {"buf_size"}},
      81             :     {"EK9999", "An unknown error occurred. Please check the log.", NULL, NULL, {}},
      82             : };
      83             : __thread ErrorInfoThread *g_errorThread = NULL;
      84             : static pthread_key_t g_errorThreadKey;
      85             : 
      86           0 : static void KeyDestructor(void *value)
      87             : {
      88           0 :     if ((ErrorInfoThread *)value != NULL) {
      89           0 :         if (((ErrorInfoThread *)value)->errorMsg != NULL) {
      90           0 :             free(((ErrorInfoThread *)value)->errorMsg);
      91           0 :             ((ErrorInfoThread *)value)->errorMsg = NULL;
      92             :         }
      93           0 :         DeInitVector(&((ErrorInfoThread *)value)->errorItemList);
      94           0 :         free((ErrorInfoThread *)value);
      95             :     }
      96           0 : }
      97             : 
      98           1 : static void PfnDestroyItem(void *a)
      99             : {
     100           1 :     if (!((ErrorItem *)a)->idIsInner) {
     101           0 :         free(((ErrorItem *)a)->errorId);
     102             :     }
     103           1 :     if (!((ErrorItem *)a)->errIsInner) {
     104           1 :         free(((ErrorItem *)a)->errorMessage);
     105             :     }
     106           1 :     ((ErrorItem *)a)->errorId = NULL;
     107           1 :     ((ErrorItem *)a)->errorMessage = NULL;
     108           1 :     ((ErrorItem *)a)->possibleCause = NULL;
     109           1 :     ((ErrorItem *)a)->solution = NULL;
     110           1 : }
     111             : 
     112           1 : static void InitErrorThreadKey(void)
     113             : {
     114           1 :     pthread_key_create(&g_errorThreadKey, KeyDestructor);
     115           1 : }
     116             : 
     117           1 : static int32_t InitErrorInfoThread(void)
     118             : {
     119             :     static pthread_once_t once = PTHREAD_ONCE_INIT;
     120           1 :     pthread_once(&once, InitErrorThreadKey);
     121           1 :     g_errorThread = (ErrorInfoThread *)malloc(sizeof(ErrorInfoThread));
     122           1 :     if (g_errorThread == NULL) {
     123           0 :         return -1;
     124             :     }
     125           1 :     InitVector(&g_errorThread->errorItemList, sizeof(ErrorItem));
     126           1 :     SetVectorDestroyItem(&g_errorThread->errorItemList, PfnDestroyItem);
     127           1 :     g_errorThread->errorMsgLen = 0;
     128           1 :     g_errorThread->errorMsgSize = 0;
     129           1 :     g_errorThread->errorMsg = NULL;
     130           1 :     pthread_setspecific(g_errorThreadKey, g_errorThread);
     131           1 :     return 0;
     132             : }
     133             : 
     134           1 : static int Compare(const void *a, const void *b)
     135             : {
     136           1 :     return strcmp(((const ErrorInfoConfig *)a)->errorId, ((const ErrorInfoConfig *)b)->errorId);
     137             : }
     138             : 
     139           1 : static ErrorInfoConfig *SearchFromErrorMap(const char *errorCode)
     140             : {
     141           1 :     ErrorInfoConfig errConfig = {(char *)errorCode, NULL, NULL, NULL, {}};
     142             :     static size_t errorPerLen = sizeof(ERROR_MAP[0]);
     143             :     static size_t errorMapLen = sizeof(ERROR_MAP) / sizeof(ERROR_MAP[0]);
     144           1 :     return (ErrorInfoConfig *)bsearch(&errConfig, ERROR_MAP, errorMapLen, errorPerLen, Compare);
     145             : }
     146             : 
     147           1 : static int SearchFromArray(int32_t argsNum, char *args[], const char *arg)
     148             : {
     149           1 :     int index = -1;
     150           1 :     for (int i = 0; i < argsNum; i++) {
     151           1 :         if (strcmp(args[i], arg) == 0) {
     152           1 :             index = i;
     153           1 :             break;
     154             :         }
     155             :     }
     156           1 :     return index;
     157             : }
     158             : 
     159           1 : static int SubString(const char *str, const char *sub)
     160             : {
     161           1 :     int count = 0;
     162             :     size_t j;
     163          32 :     for (size_t i = 0; i < strlen(str); i++) {
     164          33 :         for (j = 0; j < strlen(sub); j++) {
     165          32 :             if (str[i + j] != sub[j]) {
     166          30 :                 break;
     167             :             }
     168             :         }
     169          31 :         if (j == strlen(sub)) {
     170           1 :             count++;
     171             :         }
     172             :     }
     173           1 :     return count;
     174             : }
     175             : 
     176             : /* 函数名:FormatString
     177             :    函数功能:格式化错误模板信息,如
     178             :       FormatString({"value", "param", "reason"}, "Value [%s] for [%s] is invalid. Reason: %s.",
     179             :                    {"value", "param", "reason"}, {"25", "x", "The value is too small"}, 3);
     180             :       返回"Value [25] for [x] is invalid. Reason: The value is too small.
     181             :    输入:
     182             :        tmplArgList : 模板参数列表,如{"value", "param", "reason"}
     183             :        tmplErrorMsg : 模板errMsg, 如"Value [%s] for [%s] is invalid. Reason: %s."
     184             :        args : 用户传入的参数列表, {"value", "param", "reason", "..."}
     185             :        argValues : 用户传入的参数值列表, {"5", "x", "x is invalid", "..."}
     186             :        argsNum :用户传入的参数值或者参数列表长度, sizeof(args) / sizeof(char*)
     187             :    返回值:格式化后的字符串,失败为NULL
     188             : */
     189           1 : static char *FormatString(char *tmplArgList[MAX_ARG_NUMBER], char *tmplErrorMsg,
     190             :                           char *args[], char *argValues[], int32_t argsNum)
     191             : {  // 当模板中errormsg %s个数大于3个时,提前处理
     192           1 :     if (SubString(tmplErrorMsg, "%s") > MAX_ARG_NUMBER) {
     193           0 :         return NULL;
     194             :     }
     195             :     // 判断模板参数列表的参数是否都包含在用户传入的参数列表中,是的话计算格式化字符串长度
     196           1 :     char *validArgVals[MAX_ARG_NUMBER];
     197           1 :     size_t formatMsgLen = strlen(tmplErrorMsg) + 1;
     198           1 :     int index = -1;
     199           2 :     for (int i = 0; i < MAX_ARG_NUMBER; i++) {
     200           2 :         if (tmplArgList[i] == NULL || strlen(tmplArgList[i]) == 0) {
     201             :             break;
     202             :         }
     203           1 :         index = SearchFromArray(argsNum, args, tmplArgList[i]);
     204           1 :         if (index == -1) {
     205           0 :             return NULL;
     206             :         }
     207           1 :         validArgVals[i] = argValues[index];
     208           1 :         formatMsgLen += (strlen(argValues[index]) - PERCENT_S_LEN);
     209             :     }
     210           1 :     char *dstInfo = (char *)malloc(formatMsgLen);
     211           1 :     if (dstInfo == NULL) {
     212           0 :         return NULL;
     213             :     }
     214           1 :     int n = sprintf_s(dstInfo, formatMsgLen, tmplErrorMsg, validArgVals[0], validArgVals[1], validArgVals[2]);
     215           1 :     if (n < 0) {
     216           0 :         free(dstInfo);
     217           0 :         return NULL;
     218             :     }
     219           1 :     return dstInfo;
     220             : }
     221             : 
     222           1 : static int32_t Init(void)
     223             : {
     224           1 :     if (g_errorThread == NULL) {
     225           1 :         int32_t initRet = InitErrorInfoThread();
     226           1 :         if (initRet) {
     227           0 :             return -1;
     228             :         }
     229             :     }
     230           1 :     return 0;
     231             : }
     232             : 
     233           1 : void ReportErrMessage(const char *errorCode, char *args[], char *argValues[], int32_t argsNum)
     234             : {
     235           1 :     int32_t initRet = Init();
     236           1 :     if (initRet) {
     237           0 :         return;
     238             :     }
     239             : 
     240           1 :     ErrorInfoConfig *searchRet = SearchFromErrorMap(errorCode);
     241           1 :     if (searchRet == NULL) {
     242           0 :         return;
     243             :     }
     244             : 
     245           1 :     ErrorItem errorItem;
     246           1 :     char *ret = strstr(searchRet->errorMessage, "%s");
     247           1 :     if (ret == NULL) {
     248           0 :         errorItem.errorMessage = searchRet->errorMessage;
     249           0 :         errorItem.errIsInner = true;
     250             :     } else {
     251           1 :         errorItem.errorMessage = FormatString(searchRet->argList, searchRet->errorMessage, args, argValues, argsNum);
     252           1 :         if (errorItem.errorMessage == NULL) {
     253           0 :             return;
     254             :         }
     255           1 :         errorItem.errIsInner = false;
     256             :     }
     257           1 :     errorItem.idIsInner = true;
     258           1 :     errorItem.errorId = searchRet->errorId;
     259           1 :     errorItem.possibleCause = searchRet->possibleCause;
     260           1 :     errorItem.solution = searchRet->solution;
     261             :     // 为GetErrorMessage时返回拼接字符串做准备,NEWLINE_LEN表示为每条errMsg末尾增加"\r\n"
     262           1 :     g_errorThread->errorMsgLen += (SPACE_NUMS + strlen(errorItem.errorMessage) + NEWLINE_LEN);
     263           1 :     if ((EmplaceBackVector(&g_errorThread->errorItemList, &errorItem) == NULL) && (errorItem.errIsInner == false)) {
     264           0 :         free(errorItem.errorMessage);
     265             :     }
     266           1 :     return;
     267             : }
     268             : 
     269           3 : static bool IsValidErrorCode(const char *errorCode)
     270             : {
     271           3 :     return strlen(errorCode) == ERRCODE_LENGTH;
     272             : }
     273             : 
     274           3 : static bool IsInnerErrorCode(const char *errorCode)
     275             : {
     276           3 :     const char *kInterErrorCodePrefix1 = "9999";
     277           3 :     const char *kInterErrorCodePrefix2 = "8888";
     278           3 :     if (IsValidErrorCode(errorCode) && (strcmp(errorCode + PERCENT_S_LEN, kInterErrorCodePrefix1) == 0 ||
     279           3 :         strcmp(errorCode + PERCENT_S_LEN, kInterErrorCodePrefix2) == 0)) {
     280           0 :         return true;
     281             :     }
     282           3 :     return false;
     283             : }
     284             : 
     285           0 : void ReportInterErrMessage(const char *errorCode, const char *errorMsg)
     286             : {
     287           0 :     int32_t initRet = Init();
     288           0 :     if (initRet) {
     289           0 :         return;
     290             :     }
     291           0 :     if (!IsInnerErrorCode(errorCode)) {
     292           0 :         return;
     293             :     }
     294           0 :     ErrorItem errorItem;
     295           0 :     size_t errCodeLen = ERRCODE_LENGTH + 1;
     296           0 :     errorItem.errorId = (char *)malloc(errCodeLen);
     297           0 :     if (errorItem.errorId == NULL) {
     298           0 :         return;
     299             :     }
     300           0 :     size_t errMsgLen = strlen(errorMsg) + 1;
     301           0 :     errorItem.errorMessage = (char *)malloc(errMsgLen);
     302           0 :     if (errorItem.errorMessage == NULL) {
     303           0 :         free(errorItem.errorId);
     304           0 :         return;
     305             :     }
     306           0 :     if ((memcpy_s(errorItem.errorId, errCodeLen, errorCode, errCodeLen) != EOK) ||
     307           0 :         (memcpy_s(errorItem.errorMessage, errMsgLen, errorMsg, errMsgLen) != EOK)) {
     308           0 :         free(errorItem.errorId);
     309           0 :         free(errorItem.errorMessage);
     310           0 :         return;
     311             :     }
     312           0 :     errorItem.idIsInner = false;
     313           0 :     errorItem.errIsInner = false;
     314             :     // 这里加1没加2是因为上面errMsgLen已经加了1
     315           0 :     g_errorThread->errorMsgLen += (SPACE_NUMS + errMsgLen + 1);
     316           0 :     if (EmplaceBackVector(&g_errorThread->errorItemList, &errorItem) == NULL) {
     317           0 :         free(errorItem.errorId);
     318           0 :         free(errorItem.errorMessage);
     319             :     }
     320           0 :     return;
     321             : }
     322             : 
     323           0 : void FormatReportInner(const char *errorCode, const char *fmt, ...)
     324             : {
     325           0 :     va_list arg;
     326           0 :     va_start(arg, fmt);
     327           0 :     char errorStr[LIMIT_PER_MESSAGE] = {0};
     328           0 :     if (vsnprintf_s(errorStr, LIMIT_PER_MESSAGE, LIMIT_PER_MESSAGE - 1, fmt, arg) != -1) {
     329           0 :         ReportInterErrMessage(errorCode, errorStr);
     330             :     }
     331           0 :     va_end(arg);
     332           0 :     return;
     333             : }
     334             : 
     335             : // 根据此次计算的字符串大小和上次申请的内存大小关系,判断是否需要重新申请内存空间
     336           1 : static int32_t MallocByCase(void)
     337             : {
     338           1 :     if ((g_errorThread->errorMsgLen) > g_errorThread->errorMsgSize) {
     339           1 :         if (g_errorThread->errorMsg != NULL) {
     340           0 :             free(g_errorThread->errorMsg);
     341             :         }
     342           1 :         g_errorThread->errorMsg = (char *)malloc(g_errorThread->errorMsgLen);
     343           1 :         if (g_errorThread->errorMsg == NULL) {
     344           0 :             return -1;
     345             :         }
     346           1 :         g_errorThread->errorMsgSize = g_errorThread->errorMsgLen;
     347             :     }
     348           1 :     return 0;
     349             : }
     350             : 
     351           1 : static size_t GetFirstCode(size_t errorItemNum)
     352             : {
     353           1 :     for (size_t i = 0; i < errorItemNum; i++) {
     354           1 :         if (!IsInnerErrorCode(((ErrorItem *)VectorAt(&g_errorThread->errorItemList, i))->errorId)) {
     355           1 :             return i;
     356             :         }
     357             :     }
     358           0 :     return 0;
     359             : }
     360             : 
     361           1 : static int32_t ComputeAllocate(ErrorItem *firstItem)
     362             : {
     363           1 :     g_errorThread->errorMsgLen += (ERRCODE_LENGTH + sizeof(": Inner Error!\r\n")  + strlen(firstItem->errorMessage) +
     364             :                                    NEWLINE_LEN  + sizeof("        TraceBack (most recent call last): \r\n"));
     365             : 
     366           1 :     if (!IsInnerErrorCode(firstItem->errorId)) {
     367           1 :         if (firstItem->possibleCause != NULL) {
     368           0 :             g_errorThread->errorMsgLen +=
     369           0 :                 (sizeof("        PossibleCause: ") + strlen(firstItem->possibleCause) + NEWLINE_LEN);
     370             :         }
     371           1 :         if (firstItem->solution != NULL) {
     372           1 :             g_errorThread->errorMsgLen += (sizeof("        Solution: ") + strlen(firstItem->solution) + NEWLINE_LEN);
     373             :         }
     374             :     }
     375           1 :     return MallocByCase();
     376             : }
     377             : 
     378           1 : static int32_t FormatTraceBefore(ErrorItem *firstItem)
     379             : {
     380             :     int32_t n;
     381           1 :     int32_t nFirstCause = 0;
     382           1 :     int32_t nFirstSolution = 0;
     383           1 :     if (IsInnerErrorCode(firstItem->errorId)) {
     384           0 :         n = sprintf_s(g_errorThread->errorMsg, g_errorThread->errorMsgLen, "%s: Inner Error!\r\n%s\r\n",
     385             :                       firstItem->errorId, firstItem->errorMessage);
     386           0 :         if (n < 0) {
     387           0 :             return -1;
     388             :         }
     389             :     } else {
     390           1 :         n = sprintf_s(g_errorThread->errorMsg, g_errorThread->errorMsgLen, "%s: %s\r\n",
     391             :                       firstItem->errorId, firstItem->errorMessage);
     392           1 :         if (n < 0) {
     393           0 :             return -1;
     394             :         }
     395           1 :         if (firstItem->possibleCause != NULL) {
     396           0 :             nFirstCause = sprintf_s(g_errorThread->errorMsg + n, g_errorThread->errorMsgLen,
     397             :                                     "        PossibleCause: %s\r\n", firstItem->possibleCause);
     398           0 :             if (nFirstCause < 0) {
     399           0 :                 return -1;
     400             :             }
     401           0 :             n += nFirstCause;
     402             :         }
     403           1 :         if (firstItem->solution != NULL) {
     404           1 :             nFirstSolution = sprintf_s(g_errorThread->errorMsg + n, g_errorThread->errorMsgLen,
     405             :                                        "        Solution: %s\r\n", firstItem->solution);
     406           1 :             if (nFirstSolution < 0) {
     407           0 :                 return -1;
     408             :             }
     409           1 :             n += nFirstSolution;
     410             :         }
     411             :     }
     412           1 :     return n;
     413             : }
     414             : 
     415           1 : static int32_t FormatTraceAfter(ErrorItem *firstItem, size_t errorItemNum, int32_t offset)
     416             : {
     417           1 :     bool printTracebackOnce = false;
     418           1 :     int32_t n = offset;
     419             :     int traceRet;
     420             :     int32_t nErrMsg;
     421             :     ErrorItem *errorItem;
     422           2 :     for (size_t i = 0; i < errorItemNum; i++) {
     423           1 :         errorItem = (ErrorItem *)VectorAt(&g_errorThread->errorItemList, i);
     424           1 :         if (strcmp(firstItem->errorId, errorItem->errorId) == 0 &&
     425           1 :             strcmp(firstItem->errorMessage, errorItem->errorMessage) == 0) {
     426           1 :             continue;
     427             :         }
     428           0 :         if (!printTracebackOnce) {
     429           0 :             traceRet = sprintf_s(g_errorThread->errorMsg + n, g_errorThread->errorMsgLen, "%s\r\n",
     430             :                                  "        TraceBack (most recent call last):");
     431           0 :             if (traceRet < 0) {
     432           0 :                 return -1;
     433             :             }
     434           0 :             printTracebackOnce = true;
     435           0 :             n += traceRet;
     436             :         }
     437             : 
     438           0 :         nErrMsg = sprintf_s(g_errorThread->errorMsg + n, g_errorThread->errorMsgLen, "        %s\r\n",
     439             :                             errorItem->errorMessage);
     440           0 :         if (nErrMsg < 0) {
     441           0 :             return -1;
     442             :         }
     443           0 :         n += nErrMsg;
     444             :     }
     445           1 :     return 0;
     446             : }
     447             : 
     448           1 : static bool FormatOutMsg(ErrorItem *firstItem, size_t errorItemNum)
     449             : {
     450           1 :     int32_t offset = FormatTraceBefore(firstItem);
     451           1 :     if (offset == -1) {
     452           0 :         return false;
     453             :     }
     454           1 :     int32_t ret = FormatTraceAfter(firstItem, errorItemNum, offset);
     455           1 :     if (ret == -1) {
     456           0 :         return false;
     457             :     }
     458           1 :     return true;
     459             : }
     460             : 
     461           2 : char *GetErrorMessage(void)
     462             : {
     463           2 :     if (g_errorThread == NULL) {
     464           0 :         return NULL;
     465             :     }
     466           2 :     size_t errorItemNum = VectorSize(&g_errorThread->errorItemList);
     467           2 :     if (errorItemNum == 0) {
     468           1 :         return NULL;
     469             :     }
     470           1 :     size_t index = GetFirstCode(errorItemNum);
     471           1 :     ErrorItem *firstItem = (ErrorItem *)VectorAt(&g_errorThread->errorItemList, index);
     472           1 :     int32_t allocResult = ComputeAllocate(firstItem);
     473           1 :     if (allocResult == -1) {
     474           0 :         return NULL;
     475             :     }
     476           1 :     bool ret = FormatOutMsg(firstItem, errorItemNum);
     477           1 :     if (!ret) {
     478           0 :         free(g_errorThread->errorMsg);
     479           0 :         g_errorThread->errorMsgLen = 0U;
     480           0 :         g_errorThread->errorMsgSize = 0U;
     481           0 :         g_errorThread->errorMsg = NULL;
     482           0 :         return NULL;
     483             :     }
     484           1 :     ClearVector(&g_errorThread->errorItemList);
     485           1 :     return g_errorThread->errorMsg;
     486             : }

Generated by: LCOV version 1.14