What do you mean "destructed"?



  • This one's short and sweet:

     

    class FileException : public std::exception {

    ...

    std::string filename;

    std::string error; 


    char* FileException::what() const throw () {

        return (filename + error).c_str(); 



  • Hmm?

    I'm not exactly sure what this means.  I suppose that's the joke, but I'm quite unfamiliar with this syntax.
     



  • I'm not too familiar with C++ lately; is the WTF that the exception message can throw an exception?



  • [quote user="Benanov"]

    I'm not exactly sure what this means.  I suppose that's the joke, but I'm quite unfamiliar with this syntax.
     

    [/quote]

     

    Storytelling is a skill.  



  • [quote user="Benanov"]

    I'm not exactly sure what this means.  I suppose that's the joke, but I'm quite unfamiliar with this syntax.
     

    [/quote]

     

    In C++, there are two ways to represent a string - std::string, which has fancy overloaded concatenation operators and memory mangement, and char*, which is basically a raw pointer. std::string has a method, c_str(), which returns an internal should-not-be-modified char* for interoperation with old APIs. The basic outline of what will happen is this:

     

    Filename and error are concatenated to a new string, Foo

    The address of Foo's data is stored in a char* Bar

    Foo is automatically destructed at the end of the method. Bar now points to garbage

    Bar is returned

     

    It turns out that on some platforms, Bar continues to point to valid string data, but on others it just gets random data. 



  • [quote user="Benanov"]

    I'm not exactly sure what this means.  I suppose that's the joke, but I'm quite unfamiliar with this syntax.

    [/quote]

    filename + error creates a local variable on the stack.  .c_str() returns a const char pointer to that internal string buffer.  Unfortunately, once the function exits, the local variable is destroyed.  The pointer that is being returned is no longer valid, and points to memory that is not currently allocated.  The vast majority of the time (at least on a Windows box), this will appear to work.  Every once in a while, another thread in the app will require memory, and the OS will happen to give it the memory pointer to by this bad pointer.  Then the memory will no longer have a nice null terminated string, but whatever the other thread deemed fit to plop into the buffer.  This will usually result in an exception string full of garbage, and occasionally an access violation if we don't run into a 0 before we run into a invalid memory location.

     



  • Will that code even compile on decent C++ compilers? They would prevent (or at least give a warning) when a const char* (returned from c_str()) is trying to be coerced to a char* without a const_cast<>.



  • [quote user="stewie"]Will that code even compile on decent C++ compilers? They would prevent (or at least give a warning) when a const char* (returned from c_str()) is trying to be coerced to a char* without a const_cast<>.
    [/quote]

    I just assumed that was a transcription error, but yes, you are correct. 



  • [quote user="stewie"]Will that code even compile on decent C++ compilers? They would prevent (or at least give a warning) when a const char* (returned from c_str()) is trying to be coerced to a char* without a const_cast<>.
    [/quote]

     Yeah, return value should be const char*, my bad.
     



  • Also, you will get a "returning [pointer/reference] to local variable" compilation warning from this code.



  • [quote user="Mikademus"]Also, you will get a "returning [pointer/reference] to local variable" compilation warning from this code.
    [/quote]

    The compiler would have to be damn smart to know that the resulting char * pointer wasn't actually allocated properly, or pointing to static data.  The compiler MIGHT be able to use specific knowledge of std::string, but that wouldn't be useful for other classes that do similar things.

     



  • Yeah, I hit this once myself too :). Code seems to work on windows, and then instant segfault on linux.



  • [quote user="UnFleshed One"]Yeah, I hit this once myself too :). Code seems to work on windows, and then instant segfault on linux.[/quote]

     Interestingly, when I did this, it was exactly the other way around. Worked fine in Linux and OS X, but spewed garbage when I ran it in Windows. That was what eventually drove me to using memory analysis software as part of automated testing.
     



  • Beware the naive solution.  Going back to C code, I once saw this

    char *foo(int param1)

    {

    /* Avoid the problem of returning a local variable which is

    destroyed when it goes out of scope by making it static */

    static char fred[200];

    /* set fred to some value based on param1*/

    return fred;

    }

    Then somewhere in the code, there was the line

    printf("%s, %s", foo(1), foo(2));

     And the coder wondered why both strings came out the same!



  • [quote user="bugmenot"] 


    Filename and error are concatenated to a new string, Foo

    The address of Foo's data is stored in a char* Bar

    Foo is automatically destructed at the end of the method. Bar now points to garbage

    Bar is returned

    It turns out that on some platforms, Bar continues to point to valid string data, but on others it just gets random data. 

    [/quote]

    Hah!  I understand now.  Thank you!

    I knew the part about char* and std::string, but I didn't know what the c_str() method was for.  (I'm get paid to write C#; haven't touched C/C++ strings in a long time)



  • Oh the joys of working with a language that doesn't actually support strings.


Log in to reply