LCOV - code coverage report
Current view: top level - runtime_compact/c_base/src - error_manager.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 62.0 % 237 147
Test Date: 2026-08-06 15:29:52 Functions: 86.4 % 22 19

            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           30 :     for (size_t i = 0; i < strlen(str); i++) {
     164           31 :         for (j = 0; j < strlen(sub); j++) {
     165           30 :             if (str[i + j] != sub[j]) {
     166           28 :                 break;
     167              :             }
     168              :         }
     169           29 :         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              :     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              :     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              :     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              :     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 2.0-1