[英]Same c++ code sometimes works and sometimes doesnt
我的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()時發生。 非常感謝您對如何解決問題的任何幫助,在此先感謝您!
PS-我是cpp編碼的新手,請嘗試相應地進行解釋
lstrcat(path, L"\\\\calc.exe");
會導致緩沖區溢出。 path
是指向數組的指針,該數組只能包含文件夾路徑,僅此而已。 您將需要分配一個寬字符串,附加文件夾路徑,然后是文件路徑。 另外,您還需要檢查SHGetKnownFolderPath
結果,以確定path
是否包含有效的指針,並稍后通過調用CoTaskMemFree
釋放它。
SHGetKnownFolderPath
為path
分配了固定長度,因此您無法將可執行文件直接連接到該path
。 您需要先使用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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.