簡體   English   中英

相同的C ++代碼有時有效,有時無效

[英]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釋放它。

SHGetKnownFolderPathpath分配了固定長度,因此您無法將可執行文件直接連接到該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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM