打开管道上的CloseHandle上的sigsegv

时间:2015-08-24 19:06:54

标签: c winapi

我在CloseHandle上获得了一个sigsegv(pipe_settings-> hPipe);我也在这个例子中使用线程,我不认为这与任何事情有关,因为管道是在同一个线程中打开和关闭的。

管道柄似乎也有效。类似的东西:0xcc。 事件句柄也正常关闭。

这是一个完全有效的例子,您应该可以将其放入CLion中,然后进行翻录。任何Windows安装都应该安全。

#include <stdio.h>
#include <windows.h>
#include <unistd.h>

#define UNICODE

#define PIPE_BUFFER_SIZE 4096
#define PIPE_TIMEOUT 10000
#define PIPE_MAX_CONNECT_TIMEOUT 10000
#define PIPE_CONNECT_FAIL_REPEAT_DELAY 1000
#define DUST_TEST_PIPE_NAME "\\\\.\\pipe\\DustTestPipe"
#define PIPE_TEST_TIMEOUT 100000

struct pipe_settings {
    HANDLE hPipe;
    OVERLAPPED ol;
    LPCTSTR name;
    DWORD pipe_timeout;
};

WINBOOL PipeClose(struct pipe_settings *pipe_settings)
{
    //Dies on CloseHandle(pipe_settings->hPipe) but not on CloseHandle(pipe_settings->ol.hEvent)
    return (CloseHandle(pipe_settings->ol.hEvent) && CloseHandle(pipe_settings->hPipe));
}

void InitializePipeSettings(struct pipe_settings *pipe_settings)
{
    pipe_settings->hPipe = INVALID_HANDLE_VALUE;
    pipe_settings->ol.hEvent = INVALID_HANDLE_VALUE;
    pipe_settings->ol.Internal = 0;
    pipe_settings->ol.InternalHigh = 0;
    pipe_settings->ol.Offset = 0;
    pipe_settings->ol.OffsetHigh = 0;
    pipe_settings->ol.Pointer = NULL;
}

DWORD PipeConnectToClient(struct pipe_settings *pipe_settings)
{
    HANDLE h;
    DWORD err;

    InitializePipeSettings(pipe_settings);

    for(int x = 0; x < PIPE_MAX_CONNECT_TIMEOUT; x += PIPE_CONNECT_FAIL_REPEAT_DELAY)
    {

        h = CreateFile(
                pipe_settings->name,
                GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                NULL,
                OPEN_EXISTING,
                FILE_FLAG_OVERLAPPED,
                NULL
        );

        err = GetLastError();

        if (h != INVALID_HANDLE_VALUE)
            break;

        if(err == ERROR_FILE_NOT_FOUND) {
            //The pipe might not be open yet
            sleep(PIPE_CONNECT_FAIL_REPEAT_DELAY/1000);
            continue;
        }

        else if (err != ERROR_PIPE_BUSY) {
            return err;
        }

        if (!WaitNamedPipe(pipe_settings->name, (DWORD)PIPE_MAX_CONNECT_TIMEOUT - x))
        {
            return ERROR_PIPE_BUSY;
        }
    }

    if(h == INVALID_HANDLE_VALUE)
        return err;

    pipe_settings->hPipe = h;

    DWORD dwMode = PIPE_READMODE_BYTE;

    if(!SetNamedPipeHandleState(h, &dwMode, NULL, NULL))
        return GetLastError();

    return ERROR_SUCCESS;
}

DWORD PipeListenForServerConnect(struct pipe_settings *pipe_settings)
{
    InitializePipeSettings(pipe_settings);

    HANDLE hPipe = CreateNamedPipe(
            pipe_settings->name,
            PIPE_ACCESS_INBOUND |    // read/write access
            FILE_FLAG_OVERLAPPED,    // overlapped mode
            PIPE_TYPE_BYTE |         // message-type pipe
            PIPE_READMODE_BYTE |     // message-read mode
            PIPE_WAIT,
            1,
            PIPE_BUFFER_SIZE,
            PIPE_BUFFER_SIZE,
            PIPE_TIMEOUT,
            NULL
    );

    if (hPipe == INVALID_HANDLE_VALUE)
    {
        return GetLastError();
    }

    OVERLAPPED ol;
    //DWORD dwWait;

    ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    if(ol.hEvent == NULL)
    {
        return GetLastError();
    }

    if(ConnectNamedPipe(hPipe, &ol) == 0)
    {
        //error should be ERROR_IO_PENDING or ERROR_PIPE_CONNECTED
        DWORD err = GetLastError();

        //wait for the connection event
        if (err != ERROR_IO_PENDING && err != ERROR_PIPE_CONNECTED) {
            if (WaitForSingleObject(ol.hEvent, pipe_settings->pipe_timeout) != WAIT_OBJECT_0) {
                CloseHandle(hPipe);
                CloseHandle(ol.hEvent);
                return err;
            }
        }
    }

    pipe_settings->hPipe = hPipe;
    pipe_settings->ol.Pointer = ol.Pointer;
    pipe_settings->ol.Offset = ol.Offset;
    pipe_settings->ol.Internal = ol.Internal;
    pipe_settings->ol.hEvent = ol.hEvent;
    pipe_settings->ol.InternalHigh = ol.InternalHigh;
    pipe_settings->ol.OffsetHigh = ol.OffsetHigh;

    return ERROR_SUCCESS;
}

DWORD WINAPI ClientProc(LPVOID)
{
    struct pipe_settings pipe_settings;
    pipe_settings.name = TEXT(DUST_TEST_PIPE_NAME);
    pipe_settings.pipe_timeout = PIPE_TEST_TIMEOUT;

    DWORD err = PipeListenForServerConnect(&pipe_settings);
    //EXPECT_EQ((DWORD)ERROR_SUCCESS, err);

    WINBOOL pipe_close_success = PipeClose(&pipe_settings);
    //EXPECT_NE(1, pipe_close_success);

    return 0;
}

DWORD WINAPI ServerProc(LPVOID)
{
    struct pipe_settings pipe_settings;
    pipe_settings.name = TEXT(DUST_TEST_PIPE_NAME);
    pipe_settings.pipe_timeout = PIPE_TEST_TIMEOUT;

    DWORD err = PipeConnectToClient(&pipe_settings);
    //EXPECT_EQ((DWORD)ERROR_SUCCESS, err);

    WINBOOL pipe_close_success = PipeClose(&pipe_settings);
    //EXPECT_NE(0, pipe_close_success);

    return 0;
}



int main(void) {

    DWORD dwThreadId1;
    DWORD dwThreadId2;

    HANDLE h1 = CreateThread(NULL, 0, ServerProc, NULL, 0, &dwThreadId1);
    HANDLE h2 = CreateThread(NULL, 0, ClientProc, NULL, 0, &dwThreadId2);

    WaitForSingleObject(h1, INFINITE);
    WaitForSingleObject(h2, INFINITE);
    // your code goes here
    return 0;
}

2 个答案:

答案 0 :(得分:1)

CreateEvent()不使用INVALID_HANDLE_VALUE来表示无效句柄,而是使用NULL。因此,您需要InitializePipeSettings()ol.hEvent初始化为NULL

void InitializePipeSettings(struct pipe_settings *pipe_settings)
{
    pipe_settings->hPipe = INVALID_HANDLE_VALUE;
    pipe_settings->ol.hEvent = NULL; // <-- here
    pipe_settings->ol.Internal = 0;
    pipe_settings->ol.InternalHigh = 0;
    pipe_settings->ol.Offset = 0;
    pipe_settings->ol.OffsetHigh = 0;
    pipe_settings->ol.Pointer = NULL;
}

然后在PipeClose()中,您需要先检查INVALID_HANDLE_VALUE / NULL的每个句柄,然后再调用CloseHandle()。并且您还应PipeClose()重置其关闭的句柄,以便PipeClose()可以安全地多次调用pipe_settings

WINBOOL PipeClose(struct pipe_settings *pipe_settings)
{
    BOOL bResult = TRUE;
    if (pipe_settings->ol.hEvent != NULL)
    {
        bResult = bResult && CloseHandle(pipe_settings->ol.hEvent);
        pipe_settings->ol.hEvent = NULL;
    }
    if (pipe_settings->hPipe != INVALID_HANDLE_VALUE)
    {
        bResult = bResult && CloseHandle(pipe_settings->hPipe);
        pipe_settings->hPipe = INVALID_HANDLE_VALUE;
    }
    return bResult;
}

答案 1 :(得分:0)

这是我的最终解决方案,但我不知道为什么。

WINBOOL PipeClose(struct pipe_settings *pipe_settings)
{
    bool failed = false;

    if(pipe_settings->ol.hEvent != NULL)
    {
        if(!CloseHandle(pipe_settings->ol.hEvent))
            failed = true;
    }

    if(pipe_settings->hPipe != INVALID_HANDLE_VALUE)
    {
        if(!CloseHandle(pipe_settings->hPipe))
            failed = true;
    }

    return failed ? 0 : 1;
}


void InitializePipeSettings(struct pipe_settings *pipe_settings)
{
    pipe_settings->hPipe = INVALID_HANDLE_VALUE;
    pipe_settings->ol.hEvent = NULL;
    pipe_settings->ol.Internal = 0;
    pipe_settings->ol.InternalHigh = 0;
    pipe_settings->ol.Offset = 0;
    pipe_settings->ol.OffsetHigh = 0;
    pipe_settings->ol.Pointer = NULL;
}