簡體   English   中英

將 char** 傳遞給 void** function 參數時與指針類型不兼容的指針類型警告

[英]Incompatible pointer type warning with pointer-to-pointer types when passing char** to void** function parameter

I'm trying to implement a secure-free function that erases the allocated memory, frees it and then also sets the pointer to the allocated region to NULL so the pointer cannot be reused after-free and cannot be double-freed with the same function . 為了實現這一點,我使用了一個指向指針的參數,它允許我覆蓋指向分配的 memory 的指針。

問題是 GCC 抱怨指針類型不兼容(“但它適用於我的機器”); 我沒想到會有這樣的警告。 我的理解是任何指針都可以隱式轉換為void* ,因此我猜測指針的地址也可以轉換為void**

與此同時,我將secure_free()重寫為一個宏,它解決了警告,但我想知道編譯器為什么抱怨。

文件securefree.c

#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define STRING_BUFFER_LEN 10

/**
 * Securely erases a heap-allocated memory section, frees it and sets its
 * pointer to NULL to avoid use-after-free and double-free.
 */
static void secure_free(void** p_p_data, size_t length_in_bytes)
{
    if (p_p_data == NULL || *p_p_data == NULL)
    { return; }
    memset(*p_p_data, 0, length_in_bytes);
    free(*p_p_data);
    *p_p_data = NULL;
}

int main(void)
{
    // Allocate some data
    char* my_string = calloc(STRING_BUFFER_LEN, sizeof(char));
    if (my_string == NULL) { return 1; }
    // Use the allocated space in some way
    my_string[0] = 'a';
    my_string[1] = 'b';
    // Free using the dedicated function
    secure_free(&my_string, STRING_BUFFER_LEN);
    return 0;
}

使用 GCC 編譯(Rev6,由 MSYS2 項目構建,10.2.0):

$ gcc securefree.c -o securefree
securefree.c: In function 'main':
securefree.c:29:17: warning: passing argument 1 of 'secure_free' from incompatible pointer type [-Wincompatible-pointer-types]
   29 |     secure_free(&my_string, STRING_BUFFER_LEN);
      |                 ^~~~~~~~~~
      |                 |
      |                 char **
securefree.c:11:32: note: expected 'void **' but argument is of type 'char **'
   11 | static void secure_free(void** p_p_data, size_t length_in_bytes)
      |                         ~~~~~~~^~~~~~~~

編輯:宏版本看起來像這樣

#define secure_free_macro(ptr, len) if ((ptr) != NULL) { \
        memset((ptr), 0, (len)); free(ptr); (ptr) = NULL; }

您嘗試做的事情不能移植,因為不同的指針類型可以有不同的表示; 並將 null 指針分配給該值,您必須首先將指針指向指針轉換為指向實際指針變量的有效類型的指針 - 這是不可能的。

但是,您可以做的是使用宏,它與任何宏一樣好,並且使用起來更簡單:

#define secure_free(x) (free(x), (x) = 0)

這在沒有&的情況下有效。

C 允許將任何指針隱式轉換為void*作為顯式異常。 請注意, voidchar不是兼容的類型。 因此void*char*void**char**也不兼容。 這就是編譯器發出警告的原因。

要繞過此問題,請將 function 簽名更改為使用void*

void secure_free(void* ptr, size_t length_in_bytes) {
   void **p_p_data = (void**)ptr;
   ...
}

要添加對參數是指向指針的指針的保護,可以使用宏:

#define secure_free(x,s) ((void)sizeof **(x), secure_free((x), (s)))
  • 如果 x 不是指向指針的指針,則表達式**(x)將無法編譯。
  • sizeof防止在**(x)中評估x以避免副作用
  • (void)讓編譯器停止抱怨未使用的值
  • 逗號運算符(X,Y) ,僅返回Y的值,即secure_free(...)的返回值
  • 對宏使用與 function 相同的名稱,僅當它用作 function 時才允許將secure_free擴展為宏。 這允許使用secure_free作為指向 function 的指針

額外說明 在代碼中

    memset(*p_p_data, 0, length_in_bytes);
    free(*p_p_data);

編譯器可能會優化memset() 我建議強制轉換為volatile void *以強制編譯器生成清除代碼。

編輯

此外,由於memset丟棄了volatile限定符,因此可能會使用循環清除內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM