如何在 typedef 函数上强制执行 SAL 注释?
How do I enforce SAL annotations on a typedef'd function?
假设我像这样导入一个 DLL 函数:
typedef int(__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
HINSTANCE hDLL = LoadLibraryW(L"foo.dll");
pRandomNumber RandomNumber = (pRandomNumber)GetProcAddress(hDLL, "RandomNumber");
现在,DLL代码中的这个函数RandomNumber
被SAL注解_Check_return_
注解了。我还希望在调用它的代码中强制执行此注释。我该如何完成?
如果我把注释放在 typedef
:
_Check_return_
typedef int(__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
稍后当我初始化一个 pRandomNumber
并调用它而不检查 return 值时,分析无法报告警告。
如果我把注释放在一个实例上:
typedef int(__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
_Check_return_
pRandomNumber RandomNumber;
不检查return值就调用分析还是报错
有什么办法可以强制执行吗?一种方法是编写带有注释的存根内联函数,但这对我来说很难看。
而不是声明变量
int (__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
您可以在此声明中使用 __declspec(dllimport)
attribute and use [[nodiscard]]
and/or _Must_inspect_result_
声明函数
EXTERN_C
_NODISCARD
DECLSPEC_IMPORT
_Must_inspect_result_
int
WINAPI
RandomNumber(
_In_ size_t cb,
_Out_writes_bytes_(cb) unsigned char *pb
);
在内部,当您使用 __declspec(dllimport)
attribute, compiler declare 变量 和 extern
关键字声明 api 时;
extern "C" {
extern PVOID __imp_<function_name>;
}
到位 __FUNCDNAME__
使用 - 函数的修饰名
所以可能说
extern PVOID __imp_##__FUNCDNAME__;
当然,因为extern,这只是声明。如果你不添加定义 - 你得到
error LNK2001: unresolved external symbol __imp_RandomNumber
如果你尝试调用 RandomNumber
。所以你需要添加定义。对于 _AMD64_
这很简单,因为 extern "C"
符号没有修饰。
所以简单写:
EXTERN_C_START
PVOID __imp_RandomNumber;
EXTERN_C_END
改为
EXTERN_C_START
int (__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
EXTERN_C_END
你需要在这两种情况下声明指针大小变量,它将保存函数指针 - 仅在名称上不同 - 你 select pRandomNumber
作为名称(并且可以 select 任何名称) - 在我的例子中 - 你必须 select __imp_RandomNumber
( __imp_<function_name>
) - 添加 __imp_
修饰函数名称前缀。
但如果 _X86_
存在问题 - 对于 __stdcall
- @ 符号将出现在装饰函数名称中。你需要写
EXTERN_C_START
PVOID __imp__RandomNumber@8;
EXTERN_C_END
因为装饰名称将是 _RandomNumber@8
。但 __imp__RandomNumber@8
无效 c/c++ 名称。您可以在 asm 代码中定义这样的名称,但不能在 c/c++ 中定义。但您可以使用 /alternatename
链接器选项。
__pragma(comment(linker, "/alternatename:__imp__RandomNumber@8=___imp_RandomNumber"))
EXTERN_C_START
PVOID __imp_RandomNumber;
EXTERN_C_END
如果未找到链接器 __imp__RandomNumber@8
它会尝试使用 ___imp_RandomNumber
如果它存在。 __imp_RandomNumber
将在 _X86_
中被修饰为 ___imp_RandomNumber
可能写下一个宏
#ifdef _X86_
#define ALT_NAME(name, n) __pragma(comment(linker, _CRT_STRINGIZE(/alternatename:__imp__##name##@##n####=___imp_##name)))
#else
#define ALT_NAME(name, n)
#endif
#define IMP_FUNC(name, n) EXTERN_C_START PVOID __imp_##name; EXTERN_C_END ALT_NAME(name, n)
你的代码将是
// global declaration
EXTERN_C
_NODISCARD
DECLSPEC_IMPORT
_Must_inspect_result_
int
WINAPI
RandomNumber(
_In_ size_t cb,
_Out_writes_bytes_(cb) unsigned char *pb
);
IMP_FUNC(RandomNumber, 8);
// initialization
__imp_RandomNumber = GetProcAddress(GetModuleHandle(L"foo"), "RandomNumber");
//usage
if (__imp_RandomNumber )
{
UCHAR test[16];
RandomNumber(sizeof(test), test);
}
你得到了
warning C4834: discarding return value of function with 'nodiscard' attribute
如果不使用 RandomNumber
的 return 值
假设我像这样导入一个 DLL 函数:
typedef int(__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
HINSTANCE hDLL = LoadLibraryW(L"foo.dll");
pRandomNumber RandomNumber = (pRandomNumber)GetProcAddress(hDLL, "RandomNumber");
现在,DLL代码中的这个函数RandomNumber
被SAL注解_Check_return_
注解了。我还希望在调用它的代码中强制执行此注释。我该如何完成?
如果我把注释放在 typedef
:
_Check_return_
typedef int(__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
稍后当我初始化一个 pRandomNumber
并调用它而不检查 return 值时,分析无法报告警告。
如果我把注释放在一个实例上:
typedef int(__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
_Check_return_
pRandomNumber RandomNumber;
不检查return值就调用分析还是报错
有什么办法可以强制执行吗?一种方法是编写带有注释的存根内联函数,但这对我来说很难看。
而不是声明变量
int (__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
您可以在此声明中使用 __declspec(dllimport)
attribute and use [[nodiscard]]
and/or _Must_inspect_result_
声明函数
EXTERN_C
_NODISCARD
DECLSPEC_IMPORT
_Must_inspect_result_
int
WINAPI
RandomNumber(
_In_ size_t cb,
_Out_writes_bytes_(cb) unsigned char *pb
);
在内部,当您使用 __declspec(dllimport)
attribute, compiler declare 变量 和 extern
关键字声明 api 时;
extern "C" {
extern PVOID __imp_<function_name>;
}
到位 __FUNCDNAME__
使用 - 函数的修饰名
所以可能说
extern PVOID __imp_##__FUNCDNAME__;
当然,因为extern,这只是声明。如果你不添加定义 - 你得到
error LNK2001: unresolved external symbol __imp_RandomNumber
如果你尝试调用 RandomNumber
。所以你需要添加定义。对于 _AMD64_
这很简单,因为 extern "C"
符号没有修饰。
所以简单写:
EXTERN_C_START
PVOID __imp_RandomNumber;
EXTERN_C_END
改为
EXTERN_C_START
int (__stdcall *pRandomNumber)(size_t cb, unsigned char *pb);
EXTERN_C_END
你需要在这两种情况下声明指针大小变量,它将保存函数指针 - 仅在名称上不同 - 你 select pRandomNumber
作为名称(并且可以 select 任何名称) - 在我的例子中 - 你必须 select __imp_RandomNumber
( __imp_<function_name>
) - 添加 __imp_
修饰函数名称前缀。
但如果 _X86_
存在问题 - 对于 __stdcall
- @ 符号将出现在装饰函数名称中。你需要写
EXTERN_C_START
PVOID __imp__RandomNumber@8;
EXTERN_C_END
因为装饰名称将是 _RandomNumber@8
。但 __imp__RandomNumber@8
无效 c/c++ 名称。您可以在 asm 代码中定义这样的名称,但不能在 c/c++ 中定义。但您可以使用 /alternatename
链接器选项。
__pragma(comment(linker, "/alternatename:__imp__RandomNumber@8=___imp_RandomNumber"))
EXTERN_C_START
PVOID __imp_RandomNumber;
EXTERN_C_END
如果未找到链接器 __imp__RandomNumber@8
它会尝试使用 ___imp_RandomNumber
如果它存在。 __imp_RandomNumber
将在 _X86_
___imp_RandomNumber
可能写下一个宏
#ifdef _X86_
#define ALT_NAME(name, n) __pragma(comment(linker, _CRT_STRINGIZE(/alternatename:__imp__##name##@##n####=___imp_##name)))
#else
#define ALT_NAME(name, n)
#endif
#define IMP_FUNC(name, n) EXTERN_C_START PVOID __imp_##name; EXTERN_C_END ALT_NAME(name, n)
你的代码将是
// global declaration
EXTERN_C
_NODISCARD
DECLSPEC_IMPORT
_Must_inspect_result_
int
WINAPI
RandomNumber(
_In_ size_t cb,
_Out_writes_bytes_(cb) unsigned char *pb
);
IMP_FUNC(RandomNumber, 8);
// initialization
__imp_RandomNumber = GetProcAddress(GetModuleHandle(L"foo"), "RandomNumber");
//usage
if (__imp_RandomNumber )
{
UCHAR test[16];
RandomNumber(sizeof(test), test);
}
你得到了
warning C4834: discarding return value of function with 'nodiscard' attribute
如果不使用 RandomNumber