![](/img/trans.png)
[英]incompatible pointer types passing 'void (void *) to parameter of type 'void *
[英]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*
作為顯式異常。 請注意, void
和char
不是兼容的類型。 因此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)
將無法編譯。sizeof
防止在**(x)
中評估x
以避免副作用(void)
讓編譯器停止抱怨未使用的值(X,Y)
,僅返回Y
的值,即secure_free(...)
的返回值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.