简体   繁体   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. 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 . To achieve this I'm using a pointer-to-pointer parameter, which allows me to overwrite the pointer to the allocated memory.为了实现这一点,我使用了一个指向指针的参数,它允许我覆盖指向分配的 memory 的指针。

The issue is GCC complaining about incompatible pointer types ("but it works on my machine");问题是 GCC 抱怨指针类型不兼容(“但它适用于我的机器”); I did not expect such a warning.我没想到会有这样的警告。 My understanding was that any pointer can be implicitly cast to void* , thus I'm guessing also the address of a pointer could be cast to void** .我的理解是任何指针都可以隐式转换为void* ,因此我猜测指针的地址也可以转换为void**

In the meantime I rewrote secure_free() as a macro, which solves the warning, but I would like to know why the compiler is complaining.与此同时,我将secure_free()重写为一个宏,它解决了警告,但我想知道编译器为什么抱怨。

File securefree.c文件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;
}

Compiling with GCC (Rev6, Built by MSYS2 project, 10.2.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)
      |                         ~~~~~~~^~~~~~~~

EDIT: the macro version looks like this编辑:宏版本看起来像这样

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

What you're trying to do cannot be done portably, because different pointer types can have different representations;您尝试做的事情不能移植,因为不同的指针类型可以有不同的表示; and to assign the null pointer to the value, you must cast the pointer-to-pointer first to a pointer to the effective type of the actual pointer variable - which is impossible.并将 null 指针分配给该值,您必须首先将指针指向指针转换为指向实际指针变量的有效类型的指针 - 这是不可能的。

What you can do however is use a macro, it is as good as any, and much simpler to use:但是,您可以做的是使用宏,它与任何宏一样好,并且使用起来更简单:

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

This works without & .这在没有&的情况下有效。

C lets any pointer be implicitly cast to void* as an explicit exception. C 允许将任何指针隐式转换为void*作为显式异常。 Note, that void and char are not compatible types.请注意, voidchar不是兼容的类型。 Thus void* , char* , void** and char** are not compatible as well.因此void*char*void**char**也不兼容。 That is why compiler emits a warning.这就是编译器发出警告的原因。

To bypass this issue change the function signature to use void* :要绕过此问题,请将 function 签名更改为使用void*

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

To add protection that the argument is a pointer to a pointer one could use a macro:要添加对参数是指向指针的指针的保护,可以使用宏:

#define secure_free(x,s) ((void)sizeof **(x), secure_free((x), (s)))
  • Expression **(x) will not compile is x were not a pointer to a pointer.如果 x 不是指向指针的指针,则表达式**(x)将无法编译。
  • sizeof prevent evaluation of x in **(x) to avoid side effects sizeof防止在**(x)中评估x以避免副作用
  • (void) silence the compiler about complaining on unused value (void)让编译器停止抱怨未使用的值
  • comma operator (X,Y) , return only value of the Y , which is return value of secure_free(...)逗号运算符(X,Y) ,仅返回Y的值,即secure_free(...)的返回值
  • using the same name for macro as for function allows to expand secure_free as macro only if it used as a function.对宏使用与 function 相同的名称,仅当它用作 function 时才允许将secure_free扩展为宏。 This allows to use secure_free as a pointer to a function这允许使用secure_free作为指向 function 的指针

Extra note .额外说明 In the code在代码中

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

The compiler will likely optimize out memset() .编译器可能会优化memset() I suggest casting to volatile void * to force the compiler to generate clearing code.我建议强制转换为volatile void *以强制编译器生成清除代码。

Edit编辑

Additionally, one may have clear the content with a loop because memset discards volatile qualifier.此外,由于memset丢弃了volatile限定符,因此可能会使用循环清除内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 不兼容的指针类型将'void(void *)传递给'void *类型的参数 - incompatible pointer types passing 'void (void *) to parameter of type 'void * 不兼容的指针类型,将“ char(*)[128]”传递给类型为“ char **”的参数 - incompatible pointer types passing 'char (*)[128]' to parameter of type 'char **' 不兼容的指针类型将&#39;char *(char *)&#39;传递给类型&#39;VALUE(*)()&#39;的参数 - incompatible pointer types passing 'char *(char *)' to parameter of type 'VALUE (*)()' 不兼容的指针类型将“char (*)[3]”传递给“const char *”类型的参数 - incompatible pointer types passing 'char (*)[3]' to parameter of type 'const char * 警告:不兼容的指针类型将“char *”传递给“FILE *”类型的参数(又名“struct __sFILE *”) - warning: incompatible pointer types passing 'char *' to parameter of type 'FILE *' (aka 'struct __sFILE *') C:警告:不兼容的指针类型将“int **”传递给“int *”类型的参数 - C: Warning: incompatible pointer types passing 'int **' to parameter of type 'int *' 将“void *(struct thread_args *)”传递给“void * _Nullable (* _Nonnull)(void * _Nullable)”类型参数的不兼容指针类型 - Incompatible pointer types passing 'void *(struct thread_args *)' to parameter of type 'void * _Nullable (* _Nonnull)(void * _Nullable)' 传递指针的指针时指针类型不兼容 - Incompatible pointer type when passing a pointer of pointer C:将“char (*)”传递给“char (*)[5]”类型参数的不兼容指针类型,但程序运行正常 - C: incompatible pointer types passing 'char (*)' to parameter of type 'char (*)[5]', but program works fine 指针转换不兼容的整数,将“ char”传递给类型为“ const char *”的参数 - Incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM