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

Getting C26xxx errors in my C++ Windows service code

提问人:JeffR 提问时间:12/6/2021 最后编辑:JeffR 更新时间:12/7/2021 访问量:278

问:

我的代码中出现错误。代码可以编译,但我仍然想删除警告。我查看了 stackoverflow 和 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);
...

}

任何帮助都是值得赞赏的。

C++ Windows 服务 警告 编译器警告

评论

1赞 Richard Critten 12/6/2021
这些是来自 MS 代码分析器的消息(请注意,它们不会在消息中显示警告或错误)。它们不是错误,而是来自 MS 规则驱动的代码分析器的消息。我通常不会默认打开它(分析器),但偶尔会打开它并对每个报告做出判断。例如:C26481 NO_POINTER_ARITHMETIC
0赞 IInspectable 12/7/2021
请为每个代码分析警告提出一个问题。你会发现有些(甚至可能全部)以前被问过和回答过。

答:

1赞 marcinj 12/7/2021 #1

这些不是编译器警告,而是代码分析警告(基于 CppCoreGuidelines),它提供了有关如何改进代码以防止常见错误(如空指针取消引用和越界读取/写入)的提示。修复它们可能需要使用 gsl 工具库:https://github.com/microsoft/GSL

C26485 表达式“ste”:没有指向指针衰减的数组(bounds.3)。 StartServiceCtrlDispatcherW(ste);

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

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

C26429 符号“lpszArgv”从不测试是否为空,可以将其标记为not_null (f.23)。 C26461 函数“ServiceMain”的指针参数“lpszArgv”可以标记为指向 const (con.3) 的指针。 VOID WINAPI ServiceMain(DWORD dwArgc、LPWSTR* lpszArgv)

您应该能够使用 gsl 修复此警告:

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

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

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

...第一个参数包含第二个参数中传递给服务的参数数。总会有一个参数。第二个参数是指向字符串指针数组的指针。数组中的第一项始终是服务名称。

https://learn.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://learn.microsoft.com/en-us/cpp/code-quality/c26429?view=msvc-170 https://learn.microsoft.com/en-us/cpp/code-quality/c26461?view=msvc-170

C26481 不要使用指针算术。请改用 span (bounds.1)。 ssh = RegisterServiceCtrlHandlerExW(lpszArgv[0], (LPHANDLER_FUNCTION_EX) Service_Ctrl, 0); ..

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

评论

0赞 JeffR 12/7/2021
太棒了,谢谢!有没有办法从 Visual Studio 中的 C++ 项目设置中将其关闭?
0赞 JeffR 12/7/2021
它位于“项目”/“属性”/“代码分析器”下。将“全部”设置为“否”。