cgccpass-by-reference

Issues passing by reference with gcc. No issues when compiling with gcc



EDIT: Adding this to the top because it is critical information being missed. The FSCC_REGISTERS_INIT call does EXACTLY what it is supposed to do, which is fill the entire struct with '-1's. The segfault occurs when individual members in the struct are accessed.


I am humbly learning that I am not very good at c despite being an experienced c++ developer. I am working on a test tool for Fastcomm fscc cards.

I was originally passing the functions by refernce (c++ style) and compiling with g++ until I decided to just compile with c. Why you ask? I guess I just wanted to. I was getting good output in c++ without segfaults.

With gcc, the program compiles without warning but a get a segfault. looking at it with gdb, it appears that this is being caused by the way I am accessing the members of the regs object within the update_all_registers(...) function.

Is the way I am passing values incorrect? Like I said, this worked with c++ references.

#include <fcntl.h>
#include <unistd.h>
#include <fscc.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <ncurses.h>

int64_t get_current_time_ms()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

void update_all_registers(int fd, struct fscc_registers* regs)
{
    FSCC_REGISTERS_INIT(regs);
    regs->CMDR = FSCC_UPDATE_VALUE;
    regs->STAR = FSCC_UPDATE_VALUE;
    regs->CCR0 = FSCC_UPDATE_VALUE;
    regs->CCR1 = FSCC_UPDATE_VALUE;
    regs->CCR2 = FSCC_UPDATE_VALUE;
    regs->BGR = FSCC_UPDATE_VALUE;
    regs->SSR = FSCC_UPDATE_VALUE;
    regs->SMR = FSCC_UPDATE_VALUE;
    regs->TSR = FSCC_UPDATE_VALUE;
    regs->TMR = FSCC_UPDATE_VALUE;
    regs->RAR = FSCC_UPDATE_VALUE;
    regs->RAMR = FSCC_UPDATE_VALUE;
    regs->PPR = FSCC_UPDATE_VALUE;
    regs->TCR = FSCC_UPDATE_VALUE;
    regs->VSTR = FSCC_UPDATE_VALUE;
    ioctl(fd, FSCC_GET_REGISTERS, &regs);
}

void print_registers(struct fscc_registers* regs)
{
    printf("%.10llu 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x "
        "0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
        get_current_time_ms(), regs->CMDR, regs->STAR, regs->CCR0,
        regs->CCR1, regs->CCR2, regs->BGR, regs->SSR, regs->SMR, regs->TSR,
        regs->TMR, regs->RAR, regs->RAMR, regs->PPR, regs->TCR, regs->VSTR);
}

int main(void)
{
    int fd = 0;
    struct fscc_registers regs;
    fd = open("/dev/fscc0", O_RDWR);
    if (fd == -1)
    {
        perror("open");
        return EXIT_FAILURE;
    }
    FSCC_REGISTERS_INIT(regs);
    ioctl(fd, FSCC_GET_REGISTERS, &regs);
    printf("TS (ms)       CMDR       STAR       CCR0       CCR1       CCR2       BGR"
        "        SSR        SMR        TSR        TMR        RAR"
        "        RAMR       PPR        TCR        VSTR\n");
    print_registers(&regs);

    char odata[] = "This is a test";
    write(fd, odata, sizeof(odata));
    update_all_registers(fd, &regs);
    print_registers(&regs);

    close(fd);
    return 0;
}

For reference the FSCC library is here https://github.com/commtech/fscc-linux


Solution

  • Disclaimer: I don't know anything about these libs, I only took a peek at their source for 5 mins.

    From where we can see that FSCC_REGISTERS_INIT requires the macro parameter to be passed by value. From the fscc.h library internals:

    #define FSCC_REGISTERS_INIT(registers) memset(&registers, -1, sizeof(registers))