Reputation: 14194
I am working on a project that can start a program on the winlogon desktop. The program works perfectly while debugging but when I start it outside the ide it fails strangly with the infamous c0000005 error. The weirdest thing though is it doesn't seem to occur on any particular line. Here is the code:
#include "stdafx.h"
#include <windows.h>
#include "BinRes.h"
#include <string>
#include <iostream>
int main(int argc, char* argv[])
{
if(argc != 2)
{
return 0;
}
std::string a;
a.append(BinRes::getAppLocation());
a.append("\\wls.exe");
BinRes::ExtractBinResource("EXE",102,"wls.exe");
Sleep(500);
SC_HANDLE schsm;
schsm = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
SC_HANDLE schs;
schs = CreateService(schsm,"WLS","WLS",SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,SERVICE_DEMAND_START,NULL,a.c_str(),0,0,0,0,0);
char* cd = argv[1];
LPCSTR* arg = (LPCSTR*)&cd;
StartService(schs,1,arg);
HANDLE endevent;
endevent = OpenEvent(EVENT_ALL_ACCESS,TRUE,"ENDWLS");
WaitForSingleObject(endevent,INFINITE);
SERVICE_STATUS ss;
QueryServiceStatus(schs,&ss);
if(ss.dwCurrentState != SERVICE_STOPPED)
{
LPSERVICE_STATUS xyz = (LPSERVICE_STATUS)malloc(sizeof(LPSERVICE_STATUS));
ControlService(schs,SERVICE_CONTROL_STOP,xyz);
}
DeleteService(schs);
//error occurs right here
DeleteFile(a.c_str());
return 0;
}
The error always occurs after DeleteService and before the next line but I'm sure it isn't DeleteService because the service is deleted. I tried commenting out DeleteService and DeleteFile but it still crashes. I'm sure I've made some bonehead mistake and am just going blind. Thanks in advance for the help!
Upvotes: 0
Views: 2279
Reputation: 11
The reason why it usually would NOT fail is the last part of:
"The service control manager fills in the structure only when ControlService returns one of the following error codes: NO_ERROR
, ERROR_INVALID_SERVICE_CONTROL
, ERROR_SERVICE_CANNOT_ACCEPT_CTRL
, or ERROR_SERVICE_NOT_ACTIVE
. Otherwise, the structure is not filled in."
So it would only ever use the pointer when something fails... :)
Upvotes: 1
Reputation: 31053
I think the problem lies within the
LPSERVICE_STATUS xyz = (LPSERVICE_STATUS)malloc(sizeof(LPSERVICE_STATUS));
ControlService(schs,SERVICE_CONTROL_STOP,xyz);
part. The last argument xyz to ControlService is used by that API to return status information about the service. You are actually passing a pointer to a pointer sized memory region here, which is too small to hold all the values, which ControlService would like to fill in. IMHO you get bitten at run-time, because executing the ControlService call will override random memory directly after the space for the pointer allocated by malloc.
Try
SERVICE_STATUS xyz;
memset(&xyz, 0, sizeof(xyz));
ControlService(schs, SERVICE_CONTROL_STOP, &xyz);
instead. There is no need to allocate the structure dynamically here. According to the documentation, the ControlService will only use it to return status information; it won't be stored somewhere within Windows internal data structures.
More about the content of the structure can be in the MS documentation. No idea, why it might work during debugging. Maybe, the malloc linked against for debugging behaves slightly differently in comparison to the production version malloc?
Upvotes: 5
Reputation: 229563
In the windows API types starting with LP
are pointers, so LPSERVICE_STATUS is a pointer to a SERVICE_STATUS
. Therefore sizeof(LPSERVICE_STATUS)
returns the size of a pointer, not the size of a SERVICE_STATUS
, and this malloc doesn't allocate enough memory:
LPSERVICE_STATUS xyz = (LPSERVICE_STATUS)malloc(sizeof(LPSERVICE_STATUS));
ControlService(schs,SERVICE_CONTROL_STOP,xyz);
The correct size would be sizeof(SERVICE_STATUS)
. Also you don't really seem to need to allocate the memory dynamically, a pointer to a local variable should work as well:
SERVICE_STATUS xyz;
ControlService(schs,SERVICE_CONTROL_STOP,&xyz);
Upvotes: 4