我的c ++代码可以连续工作几次,执行几次后,它突然停止工作并抛出异常(没有任何更改!),我不知道为什么。
这是代码中有问题的部分:
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
TCHAR *path;
SHGetKnownFolderPath(FOLDERID_Startup, KF_FLAG_CREATE, NULL, &path);
lstrcat(path, L"\\calc.exe");
if (CreateProcess(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
执行几次后,在CreateProcess()行上抛出2个异常,第一个:
Unhandled exception at 0x779D8829 (ntdll.dll) in PS_Down.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77A15890).
第二个:
Exception thrown at 0x77946111 (ntdll.dll) in PS_Down.exe: 0xC0000005: Access violation reading location 0x00000069.
我在其他一些项目(不包括CreateProcess()函数)中发生了这种情况,并且iv'e注意到,总是在涉及TCHAR和SHGetKnownFolderPath()时发生。 非常感谢您对如何解决此问题的任何帮助,在此先感谢!
P.S-我是cpp编码的新手,请尝试相应地解释
答案 0 :(得分:8)
lstrcat(path, L"\\calc.exe");
将导致缓冲区溢出。 path
是指向数组的指针,该数组只能包含文件夹路径,仅此而已。您将需要分配一个宽字符串,附加文件夹路径,然后是文件路径。另外,您将需要检查SHGetKnownFolderPath
的结果以确定path
是否包含有效的指针,并稍后通过调用CoTaskMemFree
来释放它。
答案 1 :(得分:1)
path
由SHGetKnownFolderPath
分配了固定的长度,因此您不能直接将可执行文件连接到它。您需要先使用CoTaskMemRealloc
来扩展空间。使用完后,您还需要释放内存。同样,您需要关闭CreateProcess
创建的句柄。
因此,您可以创建支持类来自动处理资源:
#include "pch.h"
#include <iostream>
#include <windows.h>
#include <Shlobj.h>
#include <wchar.h>
// A wide string exception class. perhaps something like this already exist in VS?
class werror {
std::wstring text;
public:
werror(const wchar_t* Text) : text(Text) {}
const wchar_t* what() const { return text.c_str(); }
};
class ConCatToKnownFolderPath {
PWSTR m_path;
public:
ConCatToKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, const WCHAR* AddToPath = nullptr) :
m_path(nullptr)
{
if (SHGetKnownFolderPath(rfid, dwFlags, hToken, &m_path) != S_OK)
throw werror(L"SHGetKnownFolderPath failed");
if (AddToPath) {
size_t newlen = wcslen(m_path) + wcslen(AddToPath) + sizeof(WCHAR); // place for \0
size_t newbufsize = newlen * sizeof(WCHAR);
auto newPtr = CoTaskMemRealloc(m_path, newbufsize);
if (!newPtr) {
CoTaskMemFree(m_path);
throw werror(L"CoTaskMemRealloc failed");
}
m_path = reinterpret_cast<PWSTR>(newPtr);
wcscat_s(m_path, newlen, AddToPath);
}
}
// move works fine
ConCatToKnownFolderPath(ConCatToKnownFolderPath&& other) noexcept :
m_path(other.m_path)
{
other.m_path = nullptr;
}
ConCatToKnownFolderPath& operator=(ConCatToKnownFolderPath&& other) noexcept {
if (m_path) CoTaskMemFree(m_path);
m_path = other.m_path;
other.m_path = nullptr;
return *this;
}
// copy not supported (but could easily be added
ConCatToKnownFolderPath(const ConCatToKnownFolderPath&) = delete;
ConCatToKnownFolderPath& operator=(const ConCatToKnownFolderPath&) = delete;
// automatic free when it goes out of scope
~ConCatToKnownFolderPath() {
if (m_path) CoTaskMemFree(m_path);
}
PWSTR data() const { return m_path; }
operator LPCWSTR () const { return m_path; }
};
struct WProcessWithInfo : PROCESS_INFORMATION {
WProcessWithInfo(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPCWSTR lpCurrentDirectory) {
STARTUPINFOW si;
ZeroMemory(&si, sizeof(STARTUPINFOW));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
if (!CreateProcessW(lpApplicationName, lpCommandLine, NULL, NULL, FALSE, 0, NULL, lpCurrentDirectory, &si, *this))
throw werror(L"CreateProcessWCreateProcessW failed");
CloseHandle(hThread);
}
WProcessWithInfo(const WProcessWithInfo&) = delete;
WProcessWithInfo(WProcessWithInfo&&) = delete;
WProcessWithInfo& operator=(const WProcessWithInfo&) = delete;
WProcessWithInfo& operator=(WProcessWithInfo&&) = delete;
~WProcessWithInfo() {
CloseHandle(hProcess);
}
DWORD Wait(DWORD dwMilliseconds=INFINITE) {
return WaitForSingleObject(*this, dwMilliseconds);
}
operator HANDLE () { return hProcess; }
operator LPPROCESS_INFORMATION () { return this; }
};
int main() {
try {
ConCatToKnownFolderPath path(FOLDERID_System, KF_FLAG_CREATE, NULL, L"\\calc.exe");
std::wcout << L"Starting " << path.data() << L"\n";
WProcessWithInfo proc(path, NULL, NULL);
std::wcout << L"Process started\n";
proc.Wait();
std::wcout << L"Process done\n";
}
catch (const werror& ex) {
std::wcerr << L"Exception: " << ex.what() << L"\n";
}
return 0;
}