I'm getting errors in my code. The code compiles, but I'd still like to get rid of the warnings. I've looked on stackoverflow and google and clicked on the warnings which take me to the microsoft.com page, explaining each, but I don't see concrete examples of how to get rid of them.
Here's the C code and the warnings.
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);
...
}
Any help is appreciated.
CodePudding user response:
Those are not compiler warnings but a code analysis warnings (based on 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);
this informs you about potentially dangerous call, this function does not take information about size of the array so it might potentially lead to reading outside buffer. Analyzer does not know that this function relies on last element to be null initialized. You could silence this warning by allocating memory for ste
on heap and releasing after the StartServiceCtrlDispatcherW
call, or even better by wrapping allocated memory inside std::unique_ptr
or even storing entries in 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)
You should be able to fix this warning with gsl:
const auto args = gsl::span<LPWSTR>(lpszArgv, dwArgc);
then use args as if it was lpszArgv. For instructions on how to use gsl see here: https://github.com/Microsoft/GSL
According to documentation, ServiceMain should always be called with at least one element in 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
So it should be fine to suppress this warning with:
#pragma warning(suppress: 26429 26461)
VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
or better:
[[gsl::suppress(f.23)]]
[[gsl::suppress(con.3)]]
VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
links to both warnings: 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); ..
this will be fixed if you use gsl::span as shown above