3

I am writing a stock market system that uses several threads to process the incoming orders.

The project was going fine until i added one more thread. When i launch the said thread my program segfaults. The segfault is generated in the above thread by an invalid memory read.

This segfault is generated only when the program is compiled with optimization -O2 and above.

After compiling the programming with debug info using -g3 and running valgrind using

valgrind ./marketSim

and get the following output about the segfault

==2524== Thread 5:
==2524== Invalid read of size 4
==2524==    at 0x402914: limitWorker (limit.c:4)
==2524==    by 0x4E33D5F: start_thread (in /lib/libpthread-2.14.so)
==2524==  Address 0x1c is not stack'd, malloc'd or (recently) free'd
==2524== 
==2524== 
==2524== Process terminating with default action of signal 11 (SIGSEGV)
==2524==  Access not within mapped region at address 0x1C
==2524==    at 0x402914: limitWorker (limit.c:4)
==2524==    by 0x4E33D5F: start_thread (in /lib/libpthread-2.14.so)

The thread is launched like this

pthread_t limit_thread;
pthread_create(&limit_thread, NULL, limitWorker, q);

q is variable which is also passed to other threads i initialize

the limitWorker code is as follows

void *limitWorker(void *arg){
    while(1){
        if ((!lsl->empty) && (!lbl->empty)) {
            if ((currentPriceX10 > lGetHead(lsl)->price1) && (currentPriceX10 < lGetHead(lbl)->price1)) {
                llPairDelete(lsl,lbl);
            }
        }
    }
    return NULL;
}

Line 4: The line which according to valgrind produces the segfault is void *limitWorker(void *arg){

Also some more info this is compiled using gcc 4.6.1, when using gcc 4.1.2 the program doesn't segfault, even when it is optimized although it's performance is much worse.

When the program is complied using clang it also doesn't segfault when optimized.

Question

Am i making a mistake?? Is it a gcc bug?? What course of action should i follow??

If you want to take a look at the code the github page is https://github.com/spapageo/Stock-Market-Real-Time-System/

The code in question is in file marketSim.c and limit.c

EDIT: Valgrind specifies that the invalid read happens at line 4. Line 4 is the "head" of the function. I don't know compiler internals, so my naive thought is that the argument is wrong. BUT while using gdb after the segfault the argument , because the program is optimized, is optimized out according to gdb. So i don't think that that is the culprit.

Spyros
  • 67
  • 9

1 Answers1

7

If you are compiling for a 64 bit system, then 0x1c is the offset of the price1 field within the order struct. This implies that either (or both) of lsl->HEAD and lbl->HEAD are NULL pointers when the fault occurs.

Note that because your limitWorker() function includes no thread synchronisation outside of the llPairDelete() function, it is incorrect and the compiler may not be reloading those values on every execution of the loop. You should be using a using a mutex to protect the linked lists even in the read-only paths.

Additionally, your lsl and lbl variables are multiply defined. You should declare them as extern in limit.h, and define them without the extern in limit.c.

caf
  • 233,326
  • 40
  • 323
  • 462
  • 2
    I think you nailed it. Yes i am compiling in a 64-bit system. I thought that the first if clause `if ((!lsl->empty) && (!lbl->empty)) ` would protect me from excessing a NULL pointer at the second if `if ((currentPriceX10 > lGetHead(lsl)->price1) && (currentPriceX10 < lGetHead(lbl)->price1))` but the compilers optimization and preloading screwed with me. Also i don't get how declaring the `lsl` and `lbl` inside include guards aka `#ifndef LIMIT_H` isn't tha same as the extern statement since they are both working for me. – Spyros Jul 21 '11 at 13:19
  • 1
    @Spyros: The way you have done it, every `.c` file that includes `limit.h` defines those variables, which means you end up with multiple definitions. This isn't allowed, and exactly what happens depends on how your linker handles this - just don't do it. – caf Jul 21 '11 at 13:22
  • 1
    @Spyros: AFAIK, include guards save you from multiple declaration in the SAME file, but extern is needed if you want to access a variable defined in another file. – puffadder Jul 21 '11 at 13:23
  • @puffadder I guess, the linker took care of the duplicates for me. Thx for the heads up. – Spyros Jul 21 '11 at 13:32