Search code examples
c++stringsegmentation-faultunions

Why is my string assignment causing a segmentation fault?


I've tried to eliminate the common causes of seg faults such as dereferencing a null pointer, but I'm stumped. This error does not appear on my test machine in debug mode, but does appear on my production machine the release compile. Both are set to /O0 to eliminate that as a possibility. When I comment out the string assignment, the seg fault goes away, now I just need to understand what's happening so I can fix it.

There may be something more obvious, but an additional complication is that this code is being called by a kernel mode application, and the only instructions I have from the vendor about writing safe code for the system is "every function which needs anything from the operating system or has to wait for anything from the OS will not work" (verbatim).

union {
    REAL_T real[8];
    char   byte[64];
} fileName;

void transferFilenames () {
    string tempname;

    // This is from an api I must use, it retrieves values from NVRAM on
    // an accessory board.  Specifically it will return 8 REAL_T values
    // and store them starting at &filename.real[0], inp/outpArray are 
    // globals defined elsewhere.
    inpArray.I7_ARRAY.INDEX = 2903;
    inpArray.I7_ARRAY.LEN = 8;
    inpArray.I7_ARRAY.Z_PAR_PTR = &fileName.real[0];
    b_array ( READ_CYCLE_PARAMS, &status, &inpArray, &outpArray );

    // if status != 0, there was an error
    if ( status == 0 ) {
        // there is no guarantee of being null terminated
        fileName.byte[63] = 0;

        /* This test code didn't fix the problem
        int i;
        char myStr[64];
        for ( i = 0; i < 64; i++ )
            myStr[i] = fileName.byte[i];
        if ( myStr[0] != '\0' )
            string mystring( myStr ); // seg fault
        */
        tempname.assign( fileName.byte ); // Throws seg fault
        // tempname.assign( &fileName.byte[0] ); // try to be more explicit

        // controlBlock is a global class defined elsewhere
        controlBlock->setFileName ( tempname, ISINPUT);
    } else {
        controlBlock->setFileName( "BAD", ISINPUT );
    }
    return;
}

When I overloaded my control block to take a char* directly controlBlock->setFileName( &fileName.byte[0] ), and removed the string assignment altogether the segmentation fault disappeared. All the overload does is assign the char* to a local string and call the regular method.

What am I missing behind the scenes?


Solution

  • The problem may not be in the call to tempname.assign(). Pipelining can result in somewhat erroneous reports of where the demon really lies. This statement makes me think the demon lies elsewhere:

    When I overloaded my control block to take a char* directly controlBlock->setFileName( &fileName.byte[0] ), and removed the string assignment altogether the segmentation fault disappeared.

    You are passing a std::string to setFileName in one case, a char* in the other. Try replacing

    controlBlock->setFileName ( tempname, ISINPUT);
    

    with

    controlBlock->setFileName ( tempname.c_str(), ISINPUT);
    

    Addendum
    The problem may well be with using std::string, period. std::string::assign() will call malloc if the reserved size is too small. Making the reserved size sufficiently large may not work either; this may just push the malloc call into the constructor. Using something that allocates memory dynamically doesn't jibe with the clause every function which needs anything from the operating system or has to wait for anything from the OS will not work.

    In fact, this clause may well preclude the use of huge chunks of the C++ library on this machine. The C++ library is pretty loose with regard to allocating and deallocating memory, and std::string does lots of it.