Subhranil
Subhranil

Reputation: 881

Segfault on calling a function in C

So I'm building a virtual machine, and trying to make it as cross platform as possible, and suddenly encountering a strange error. There is a let instruction for my machine, which allocates memory for a variable in the memory of the machine and assign that variable with a value. In short, the let function calls getAddress to get the address of the variable. getAddress checks if the variable is already defined, and returns the address. If the variable is not defined, getAddress calls memallocate to allocate memory for the variable, and returns the address. Here is the definition of the functions :

static uint16_t memallocate(Machine *m, char *symbol){
    uint16_t allocationAddress = getFirstFree(*m);
    SymbolTable *newSymbol = (SymbolTable *)malloc(sizeof(SymbolTable));
    newSymbol->symbolName = strdup(symbol);
    newSymbol->next = NULL;
    newSymbol->mema = allocationAddress;
    if(m->symbolTable==NULL){
        m->symbolTable = newSymbol;
    }
    else{
        SymbolTable *temp = m->symbolTable;
        while(temp->next!=NULL)
            temp = temp->next;
        temp->next = newSymbol;
    }
    m->memory[allocationAddress].acquired = 1;
    m->memory[allocationAddress].data.value = 0;
    m->occupiedAddress++;
    return allocationAddress;
}

uint16_t getAddress(Machine *m, char *symbol){
    SymbolTable *table = m->symbolTable;
    while(table!=NULL){
        if(strcmp(symbol, table->symbolName)==0){
            return table->mema;
        }
        table = table->next;
    }
    uint16_t address = memallocate(m, symbol); // Here is the segfault happening
    return address;
}

This code compiles and runs pretty well on Linux, but on Windows I'm getting a segfault on the memallocate call. Since memallocate is directly passed the arguments of getAddress, and the arguments both being a pointer, they shouldn't change. But while debugging through CLion, I'm seeing gibberish arguments to the memallocate call, which is indicating some kind of stack violation(may be). Again, it is ONLY happening in Windows. Can anybody tell me what is going wrong with my code? Full code for the project can be found at GitHub.

Upvotes: 2

Views: 2018

Answers (1)

vonaka
vonaka

Reputation: 953

I took your code and run it on linux through valgrind:

==13768== Conditional jump or move depends on uninitialised value(s)
==13768==    at 0x109ABE: getAddress (in /home/vonaka/VirtualMachine/machine)
==13768==    by 0x10B714: let (in /home/vonaka/VirtualMachine/machine)
==13768==    by 0x109425: run (in /home/vonaka/VirtualMachine/machine)
==13768==    by 0x109F64: main (in /home/vonaka/VirtualMachine/machine)
==13768==  Uninitialised value was created by a heap allocation
==13768==    at 0x4C2BE7F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd
==13768==    by 0x109C2F: main (in /home/vonaka/VirtualMachine/machine)
==13768== 

So (luckily for us) it's not a Windows specific problem. The trick is that on the first call of getAddress (when m->symbolTable is NULL) you call getFirstFree(*m) at the beginning of memallocate, but look at this function:

static uint16_t getFirstFree(Machine m) {
    uint16_t add = 0;
    while(m.memory[add].acquired)
        add++;
    return add;
}

m.memory[i].acquired for i between 0 and number_of_instructions_in_your_input_file - 1are all equal to 1 as you initialize them in writeInstruction, but m.memory[number_of_instructions_in_your_input_file].acquired is not initialized yet.

So something like this will resolve your problem:

void writeInstruction(Machine *m, uint16_t add, Instruction ins) {
    m->memory[add].acquired = 1;
    m->memory[add].type = INSTRUCTION;
    m->memory[add].data.instruction = ins;
    m->occupiedAddress++;
    if(add + 1 < NUM_MEM)
        m->memory[add + 1].acquired = 0;
}

Or maybe this is more elegant (if it's works):

static uint16_t getFirstFree(Machine m) {
    uint16_t add = 0;
    while (m.memory[add].acquired && add < m.occupiedAddress)
        add++;
    return add;
}

Edit:

First of all about your comment:

By default, the members of the structure is initialised as 0

It's just not true!

Now about why you have segfault without malloc and how it's connected with valgrind's warning.

You have variable m of type Machine and some other variables in the stack, m contains Cell memory[NUM_MEM] and there is acquired in each Cell (which are not initialized!). Your input file contains let's say 88 instructions, so first 88 acquired will be correctly initialized after 88 calls of writeInstruction. Then program start to execute your instructions by calling some functions including memallocate and getFirstFree. In this loop:

while(m.memory[add].acquired)
    add++;

for any add m.memory[add].acquired very likely can be different from 0, so once add is equal to NUM_MEM you have segfault.

Why it's not happening with malloc? Simply because you are lucky (but it's not a good luck), your heap is 'cleaner' than stack. Why it's happening only in Windows? Because this time you were not so lucky (I don't have segfault even in Windows).

Upvotes: 1

Related Questions