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

Generated by: LCOV version 2.0-1