释放包含恶意字符串的 malloc'd 结构



我正在为一个C++库编写一个包装器,该库需要与普通C一起使用。该库有一个名为checkError()的函数。此函数引发与对象内发生的错误相关的异常。在C++包装器中,我捕获了这个错误,对一个C兼容的结构进行mallocated,将错误消息和信息分配给错误结构变量,然后我将指向该结构的指针传回。这一切都很好,但我担心一旦C调用函数处理完结构,内存就会泄漏。

对于这个问题,让我们假设库的对象被称为objectA,库被称为libraryA

C&C++兼容wrapper.h:

#ifndef LIBRARY_WRAPPER_DEFINITION
#define LIBRARY_WRAPPER_DEFINITION
#ifdef __cplusplus
extern "C" {
#endif
typedef struct wrapper_error_message_struct{
    char *what;
    char *typeAsText;
    unsigned char severityLevel; /* 0-10; 0 = lowest severity. 10 = highest severity */
} wrapper_error_message_t;
typedef void *pLibObj_t;
/**
 * I've omitted the other prototypes, typedefs, etc.
 **/
/* checkError()'s wrapper prototype */
wrapper_error_message_t *wrapper_check_error(pLibObj_t ptrObjectToCheck);
#ifdef __cplusplus
}
#endif
#endif

wrapper.cpp:中wrapper_check_error的C++实现

/* Imports and other functions preceding wrapper_check_error() */
wrapper_error_message_t *wrapper_check_error(pLibObj_t ptrObjectToCheck){
    /* for the sake of this question, I've omitted the validity checks on
     * ptrObjectToCheck. I've also omitted my malloc checks. */
    libraryA::objectA *convertedObj = (libraryA::objectA *)ptrObjectToCheck;
    size_t structSize = sizeof(wrapper_error_message_t);
    size_t charSize = sizeof(char); // just in case it's not 1 on this system.
    try{
        convertedObj->checkError();
        /* if the checkError() function did not throw an error, then we
           can simply return NULL indicating that no ERROR was thrown */
        return NULL;
    }catch(libraryA::SomeLibraryExceptionType_1 &err){
        wrapper_error_message_t *cErr = (wrapper_error_message_t *)malloc(structSize);
        cErr->severityLevel = 3;
        const char *errWhat = err.what();
        cErr->what = (char *)malloc((strlen(errWhat)+1) * charSize);
        strcpy(cErr->what, errWhat);
        const char errorType[] = "Library Exception Type Name 1";
        cErr->typeAsText = (char *)malloc((strlen(errorType)+1) * charSize);
        strcpy(cErr->typeAsText, errorType);
        return cErr;
    }catch(libraryA::SomeLibraryExceptionType_2 &err){
        /*  Roughly the same as SomeLibraryExceptionType_1's catch statement */
    }catch(libraryA::SomeLibraryExceptionType_3 &err){
        /*  Roughly the same as SomeLibraryExceptionType_1's catch statement */
    }catch(std::exception &err)
        wrapper_error_message_t *cErr = (wrapper_error_message_t *)malloc(structSize);
        cErr->severityLevel = 7;
        const char *errWhat = err.what();
        cErr->what = (char *)malloc((strlen(errWhat)+1) * charSize);
        strcpy(cErr->what, errWhat);
        const char errorType[] = "Unknown standard exception (std::exception)";
        cErr->typeAsText = (char *)malloc((strlen(errorType)+1) * charSize);
        strcpy(cErr->typeAsText, errorType);
        return cErr;
    }catch(...){
        wrapper_error_message_t *cErr = (wrapper_error_message_t *)malloc(structSize);
        cErr->severityLevel = 10;
        cErr->what = NULL;
        const char errorType[] = "Unknown. Could not be caught.";
        cErr->typeAsText = (char *)malloc((strlen(errorType)+1) * charSize);
        strcpy(cErr->typeAsText, errorType);
        return cErr;
    }
}

main.c:中使用wrapper_check_error()的普通C函数

/* imports, irrelevant functions, irrelevant variable definitions */
void someFunction(){
    pLibObj_t ourWrappedObj;
    /*
     * function code before error check.
     */
    wrapper_error_message_t *errorMsg = wrapper_check_error(ourWrappedObj);
    if(wrapper_error_message_t != NULL){
        /* there was an error.
         * the code within this if statement:
         *      - processes the error message
         *      - logs information about it (current time, type, severity and the what message)
         *      - makes logical decisions about how to handle it if possible.
         */
        free(errorMsg);
        errorMsg = NULL;
        /* In the line above, the function frees the malloc'd structure to remove it
         * from the heap.
         *
         *        This free statement is what I'm concerned about.
         *
         */
    }
    // etc.
}

free(errorMsg)是否也会释放char *whatchar *typeAsText,因为它们是正在被释放的结构的成员?根据我所做的一些阅读,我目前相信whattypeAsText所指向的值仍将存在于堆中,因为errorMsg只包含指向这些值的指针,而不是值本身。

如果*what*typeAsText仍在堆中,我将编写一个函数,在释放结构本身之前释放结构的成员。不过,我只想在必要的时候这样做。

如果有人能对此提供一些指导/见解,我们将不胜感激。

谢谢。


如果这个问题重复,我提前道歉。如果是,请给我指出类似问题的方向,这样我就可以阅读那里的答案。我在SO和其他网站上搜索过,但没有找到任何能回答我问题的东西。

我从我的项目中摘录了一些代码,缩短了代码,并重命名了变量/函数。除了一些错误检查之外,如果代码中有我没有注意到的明显错误,请发表评论,以便我可以修改。如果有什么不清楚的地方,请在评论中告诉我,我会尽最大努力更新问题并澄清。

由于有三个malloc()调用用于构建将所有权传递给的对象:

    wrapper_error_message_t *cErr = (wrapper_error_message_t *)malloc(structSize);
    cErr->severityLevel = 3;
    const char *errWhat = err.what();
    cErr->what = (char *)malloc((strlen(errWhat)+1) * charSize);
    strcpy(cErr->what, errWhat);
    const char errorType[] = "Library Exception Type Name 1";
    cErr->typeAsText = (char *)malloc((strlen(errorType)+1) * charSize);
    strcpy(cErr->typeAsText, errorType);
    return cErr;

需要3次呼叫free():

    free(errorMsg->typeAsText);
    free(errorMsg->what);
    free(errorMsg);

顺便说一句,sizeof(char)的定义是1,所以没有必要为此做任何特殊的事情。

另一方面,我建议使用strdup(),而不是像这样容易出错的杂波

    cErr->what = (char *)malloc((strlen(errWhat)+1) * charSize);
    strcpy(cErr->what, errWhat);