Why am I getting an "Access violation writing location" in my C code?

-2

Im trying to create two threads that simply read and write to files respectively. The reader thread is supposed to read a line from a file, calculate an MD5 value, then write that and some other necessary data to a buffer.

The Writer thread must read the data from the buffer and recalculate the MD5 with the data (which was also passed to the buffer by the reader thread). Then if during the comparison the MD5s are equal, then the writer thread will append that data to a new line in another file.

I have simply implemented a struct buffer to store the necessary values, and pass it on to both threads as pointers to it.

Thing is, to have mutual exclusion, I have/need to implement CritcalSections, everytime something is being read from or written to the buffer.

Just for testing purposes, i wanted to test how is it that the mutually exclude themselves, so I have implemented a small test scenario where one thread writes a value to one of the variables on the buffer, and then the second thread prints it out to the console.

I get the error on the second thread to start right where the EnterCriticalSection(lpCritSec) is.

The error is:

"Exception thrown at 0x7792FE05 (ntdll.dll) in filename.exe: 0xC0000005: Access violation writing location 0x00000004."

I've noticed the writing location address chenges sometimes but I haven't noticed a trend

I've tried testing out different structures, and trying to find any reference errors in the code, but I can't seem to find anything.

#include <stdio.h>
#include <Windows.h>
#include <stdlib.h>
#include <time.h>

/*Data buffer struct*/
typedef struct buffer_data
{
    DWORD   read_counter;
    DWORD   wrte_counter;
    DWORD   run_number;
    char*   line_data;
    char*   md5_ctrl;
    BOOL    read_flag;
} BUFFER_DATA;

typedef struct thread_data
{
    BUFFER_DATA*        pBuffer;
    CRITICAL_SECTION*   pCritSec;
} THREAD_DATA;


/*Definition for thread function start address aka callback_function*/
typedef DWORD WINAPI START_ADDR(void*);

/*Predeclaration for functions*/
DWORD WINAPI readerThread(THREAD_DATA thData);
DWORD WINAPI writerThread(THREAD_DATA thData);
HANDLE* init_threads(
    BUFFER_DATA*        pBuffer,
    CRITICAL_SECTION*   pCritSec,
    START_ADDR*         thFunc[]
);


int main(int argc, char* argv[])
{
    puts("\nHello Arthur!\n");
    puts("Initializing...\n");

    /*Vars*/
    HANDLE*             hThreadsArr;
    CRITICAL_SECTION    critSec;
    START_ADDR*         thFunc[] = { readerThread, writerThread };


    /*Initializing the data buffer struct*/
    BUFFER_DATA     buffer_data;
    buffer_data.line_data = "";
    buffer_data.md5_ctrl = "";
    buffer_data.read_counter = 0;
    buffer_data.wrte_counter = 0;
    buffer_data.read_flag = 0;
    buffer_data.run_number = 0;

    /*Initialize threads*/
    InitializeCriticalSection(&critSec);
    hThreadsArr = init_threads(&buffer_data, &critSec, thFunc);
    /*TODO something*/
    DeleteCriticalSection(&critSec);


    return 0;
}

HANDLE* init_threads(
    BUFFER_DATA*        pBuffer,
    CRITICAL_SECTION*   pCritSec,
    START_ADDR*         thFunc[]
    ) 
{
    HANDLE*         thHandles;  //return value of array of thread handles
    THREAD_DATA     thData;     //data to pass to each threa, id est the buffer and the critical section pointer
    DWORD           idReaderTh, idWriterTh;

    //Data for both threads to share
    for (int i = 1; i >= 0; i--) {
        thData.pBuffer  = pBuffer;
        thData.pCritSec = pCritSec;

        thHandles = (HANDLE*)malloc(sizeof(HANDLE) * 2);    //allocating memory for thread handles
        thHandles[i] = CreateThread(NULL, 0, thFunc[i], &thData, 0, &idReaderTh); //index 0 = ReaderThread;
        if (!thHandles[i])
        {
            /*printf("Launching Read Thread Error. Exiting. ---ErrNo: %lu\n", GetLastError());*/
            fprintf(stderr, "Launching Reader Thread Error. Exiting. ---ErrNo: %lu\n", GetLastError()); //print to stderr dump
            return EXIT_FAILURE;
        }
        printf("Reader Thread Launched Succesfully! TID: %lu\n", idReaderTh);
    }
    return thHandles;
}

DWORD WINAPI readerThread(void* params)
{   
    THREAD_DATA thread_data;

    thread_data = *(THREAD_DATA*)params;

    EnterCriticalSection(thread_data.pCritSec); //this is where i get the error being the code as it is
    //thread_data.pBuffer->run_number = 99u;
    LeaveCriticalSection(thread_data.pCritSec);
}

DWORD WINAPI writerThread(void* params)
{
    THREAD_DATA thread_data;

    thread_data = *(THREAD_DATA*)params;

    EnterCriticalSection(thread_data.pCritSec);
    //thread_data.pBuffer->run_number = 99u;
    LeaveCriticalSection(thread_data.pCritSec);

}

Depending on the "for" loop in the init_threads method, is how i was changing the order of creation of the threads.

c
windows
multithreading
asked on Stack Overflow May 18, 2019 by Cnidarian • edited May 18, 2019 by Neil Butterworth

1 Answer

0

thData is a local variable that goes out of scope when the init_threads function returns. This return happens before writerThread has finished using the data. When it is then accessed by one of your running threads you get Undefined Behavior, which in this case is a crash.

Possible solutions include making thData static, or using an event so that the threads can signal when they are done using the data. The main thread can then call WaitForMultiple to wait for both threads to get started.

answered on Stack Overflow May 18, 2019 by 1201ProgramAlarm

User contributions licensed under CC BY-SA 3.0