views:

343

answers:

3

I am debugging some Linux C code in a signal handler for floating point exceptions. The goal is to check the floating point registers, print some information, and then abort. I get a segmentation fault when attempting to printf the result of (char)('0' + phyreg).

struct ucontext *   uc = (struct ucontext *) data;
fpregset_t   fp = uc -> uc_mcontext.fpregs;

int top = (fp -> sw >> 11) & 0x07;
int i,j,k;
for (i = 0; i < 8; i++) {
    static const char * tags [] = {
        "valid", "zero", "invalid/infin", "empty"
    };
    int phyreg = (top + i) & 0x07;
    struct _libc_fpreg* r = &(fp -> _st [phyreg]);
    const char* regExp = (((r->exponent & 0x8000) != 0) ? "-" : "+");
    printf ("  FP %s: Mantissa= %s",
            (char) ('0' + phyreg), // reg stack (SIGSEGV here)
            regExp); // register exponent sign
    j = (r->significand[3] >> 15) & 0x01;
    printf ("%s.",(char) ('0' + j)); // mantissa (Also SIGSEGV here when
                                     // previous SIGSEGV is commented out)
    ...
}

It's not the calculation of (char)('0' + phyreg) that's the problem, because when I move it to a separate line and store the result in a temp variable, I don't get the segfault until the printf tries to display the temp variable. So, where's the bug that causes the segfault?

+7  A: 

You are printing with %s. Should be " FP %c: Mantissa = %s".

antti.huima
Duh! It's been so long since I've used printf. I knew it was probably something obvious, but I just didn't see it.
Scottie T
+3  A: 

%s means a string, you're giving it a character. This character value is interpreted by printf as a pointer to the first character of the string to print, which will of course fail horibbly.

Put the character into a character array with 2 elements, the second being '\0', or see if printf has something that evaluates to a character.

Lasse V. Karlsen
+3  A: 

Use the %c format specifier for a single character, instead of %s (which should be used for a null-terminated string).

Zach Scrivena