在我的 C++ Windows 服务代码中出现 C26xxx 错误

Getting C26xxx errors in my C++ Windows service code

我的代码出现错误。代码可以编译,但我仍然想摆脱警告。我查看了 Whosebug 和 google 并单击了将我带到 microsoft.com 页面的警告,对每个警告进行了解释,但我没有看到如何摆脱它们的具体示例。

这是 C++ 代码和警告。

void WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv);

VOID main() noexcept
{
CONST SERVICE_TABLE_ENTRY ste[] = { {L"MyService", ServiceMain}, {NULL, NULL} };

//C26485    Expression 'ste': No array to pointer decay (bounds.3).
StartServiceCtrlDispatcherW(ste); 
}

// C26429 Symbol 'lpszArgv' is never tested for nullness, it can be marked as not_null (f.23).
// C26461 The pointer argument 'lpszArgv' for function 'ServiceMain' can be marked as a pointer to const (con.3).
VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv) 
{

// C26481 Don't use pointer arithmetic. Use span instead (bounds.1).
ssh = RegisterServiceCtrlHandlerExW(lpszArgv[0], (LPHANDLER_FUNCTION_EX) Service_Ctrl, 0);
...

}

感谢任何帮助。

这些不是编译器警告,而是代码分析警告(基于 CppCoreGuidelines), which give hints on how to improve code to prevent common errors - like null pointer dereferences and out of bound reads/writes. Fixing them might require use of gsl library of tools : https://github.com/microsoft/GSL.

//C26485 Expression 'ste': No array to pointer decay (bounds.3). StartServiceCtrlDispatcherW(ste);

这会通知您有关潜在危险的调用,此函数不获取有关数组大小的信息,因此它可能会导致读取外部缓冲区。分析器不知道此函数依赖于最后一个元素被初始化为 null。您可以通过在堆上为 ste 分配内存并在 StartServiceCtrlDispatcherW 调用后释放来消除此警告,或者更好的方法是将分配的内存包装在 std::unique_ptr 中,甚至将条目存储在 std::vector

https://docs.microsoft.com/en-us/cpp/code-quality/c26485?view=msvc-170

// C26429 Symbol 'lpszArgv' is never tested for nullness, it can be marked as not_null (f.23). // C26461 The pointer argument 'lpszArgv' for function 'ServiceMain' can be marked as a pointer to const (con.3). VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)

您应该可以使用 gsl 修复此警告:

const auto args = gsl::span<LPWSTR>(lpszArgv, dwArgc);

然后像使用 lpszArgv 一样使用 args。有关如何使用 gsl 的说明,请参见此处:https://github.com/Microsoft/GSL

根据文档,调用 ServiceMain 时应始终使用 lpszArgv 中的至少一个元素:

...The first parameter contains the number of arguments being passed to the service in the second parameter. There will always be at least one argument. The second parameter is a pointer to an array of string pointers. The first item in the array is always the service name.

https://docs.microsoft.com/en-us/windows/win32/services/writing-a-servicemain-function

因此可以通过以下方式抑制此警告:

#pragma warning(suppress: 26429 26461)
VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv) 

或更好:

[[gsl::suppress(f.23)]]
[[gsl::suppress(con.3)]]
VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv) 

两个警告的链接: https://docs.microsoft.com/en-us/cpp/code-quality/c26429?view=msvc-170 https://docs.microsoft.com/en-us/cpp/code-quality/c26461?view=msvc-170

// C26481 Don't use pointer arithmetic. Use span instead (bounds.1). ssh = RegisterServiceCtrlHandlerExW(lpszArgv[0], (LPHANDLER_FUNCTION_EX) Service_Ctrl, 0); ..

如果您使用如上所示的 gsl::span,这将得到解决