Success? How did this happen?



  • XBMC doesn't seem to approve of success

    Error: Success 



  • I've seen similar messages before: "Error: such-and-such was successful."

     

    I'm guessing that in these situations, the only existing method of providing feedback to the user is via error reporting, so the programmer uses that to report success. Downright lazy, if you ask me. 



  • It's often due to the following code pattern:

    if(!dostuff()){

        message(lookup_error());

    Of course, if dostuff() fails, but doesn't set an error condition for lookup_error, lookup_error will return the message for the last (usually successful) function, leading to these sorts of error messages. 



  • Some Perl comes to mind: 

    die("Success!\n");

     

    It seems akin to ending a program (in java, C++,etc) by:

    assert(false);



  • BitchX (an IRC client for Linux), used to give "Connection closed: success" when you were disconnected from IRC server.

     This, of course, made me ask "WTF? Another message from UNIX weenies to other UNIX weenies?".
     



  • Looks like you happened upon the Win32 WTF error code: ERROR_SUCCESS (the descriptive string for which is "Success").  I would provide a supporting MSDN link, but it seems that MSDN is currently in its own WTF state at this moment (half the links are broken), so I'll leave it for you to Google.



  • In some circles this is known as "errno leakage". Most functions in the C and POSIX standard library return an error via the errno thread-local variable. If the function does not fail, it sets errno to 0, so you can test for the presence of an error with "if (errno)" as well as via the functions own return value.

    The problem occurs when you have code like this:

    X* setup_x(...) {
      X *x = create_X(...);
      if (!read_X(x, ...)) {
        cleanup_X(x);
        return NULL;
      }
      return x;
    }
    

    void foo(...) {
    X *x = setup_x(...);
    if (!x)
    printf("Failed to setup x: %s\n", strerror(errno));
    }

    What's the problem? The cleanup_x function calls one of the standard C library functions that returns its error status in errno - most commonly it is an unrelated function, like some kind of log message. By the time foo() gets around to checking with strerror(), the error from read_x() has been overwritten with 0. And strerror(0) happens to be "Success", because an errno value of 0 indicates the absence of an error.

    Any error message that just says "Success" is almost certainly some variation on this theme.

    Somebody mentioned BitchX - I happen to know offhand that bug is caused by a poorly placed call to close() in the error handling code. It is essential when dealing with errno to remember to prepare your error message before performing any cleanup.



  • @asuffield said:

    In some circles this is known as "errno leakage". Most functions in the C and POSIX standard library return an error via the errno thread-local variable. If the function does not fail, it sets errno to 0, so you can test for the presence of an error with "if (errno)" as well as via the functions own return value.

    The problem occurs when you have code like this:

    X* setup_x(...) {
    X *x = create_X(...);
    if (!read_X(x, ...)) {
    cleanup_X(x);
    return NULL;
    }
    return x;
    }

    void foo(...) {
    X *x = setup_x(...);
    if (!x)
    printf("Failed to setup x: %s\n", strerror(errno));
    }

    What's the problem? The cleanup_x function calls one of the standard C library functions that returns its error status in errno - most commonly it is an unrelated function, like some kind of log message. By the time foo() gets around to checking with strerror(), the error from read_x() has been overwritten with 0. And strerror(0) happens to be "Success", because an errno value of 0 indicates the absence of an error.

    Any error message that just says "Success" is almost certainly some variation on this theme.

    Somebody mentioned BitchX - I happen to know offhand that bug is caused by a poorly placed call to close() in the error handling code. It is essential when dealing with errno to remember to prepare your error message before performing any cleanup.

    Wow.  Just wow.  Your entire post is a WTF.

    If the function does not fail, it sets errno to 0, so you can test for the presence of an error with "if (errno)" as well as via the functions own return value.


    This is utterly wrong.  Errno is only set if an error has occured.  If a function succeeded (ie. did not return an error), the value of errno is undefined.  It may be cleared.  It may be the value that it was when the function entered.  It may be the value set by a failure that was caught and successfully handled internally to this function.  It could be pink unicorns.  The point is, it is undefined and checking it is incorrect.  See the return value from the read(2) man page below.  Notice that errno is not discussed except in the failure case.

    RETURN VALUE
    On success, the number of bytes  read  is  returned  (zero
    indicates  end of file), and the file position is advanced
    by this number.  It is not an  error  if  this  number  is
    smaller  than the number of bytes requested; this may hap­
    pen for example because fewer bytes are actually available
    right  now (maybe because we were close to end-of-file, or
    because we are reading from a pipe, or from  a  terminal),
    or  because read() was interrupted by a signal.  On error,
    -1 is returned, and errno is set  appropriately.  In  this
    case  it is left unspecified whether the file position (if
    any) changes.

     




  • Yeah. Error: Success messages are never because of errno, in my opinion. It usually goes something like this:




    int my_subsystem(paramObj *, yadda *, ...) {
    int retval;
    ... some code
    if(!(retval = open(paramObj->getPath(), O_RDONLY)) {
    return errno;
    }
    paramObj->setHandle(retval);
    retval = 0;

    if(read(paramObj->getHandle(), buf, SIZE) != SIZE) {
         ... do some recovery ...
         retval = errno;
    } else {
        ... doing stuff with buf ...
        paramObj->setState(SUCCESS);
    }
    return retval;
    

    }

    ... Later on:

    void some_func () {
    ... lots of stuff ...
    val = my_subsystem(myParams, yidda, etc.);
    if(!myParams->getState() & SUCCESS) {
    show_error_message(strerror(val));
    }
    ...
    }


    If the coder was naive, they might not process a file in a loop (for example), and just assume after some weak testing that the read call would read the whole buffer in one slurp if possible. But read only sets errno to something interesting if it returns -1. So the function returns 0 but doesn't do the setState(). Later on, it calls getState() and finds no success, and assumes that val would have captured the reason why. But it returned 0. And strerror of 0 is "Success" which doesn't make any sense, but that's what you get for not being 100% familiar with the ins and outs of errno-setting library functions, and doing hokey things will your return codes.


  • ahh the old smb networking problems.

     

    never did figure that one out.

    seems to happen with a incorrect login info.
     



  • @joe_bruin said:

    seems that MSDN is currently in its own WTF state at this moment

    That's a design feature.
     



  • @joe_bruin said:

    If the function does not fail, it sets errno to 0, so you can test for the presence of an error with "if (errno)" as well as via the functions own return value.


    This is utterly wrong.  Errno is only set if an error has occured.

    Sorry dude, but you've spent too long reading manpages and not enough time in the real world. glibc and win32 both set errno to 0 on success in most cases. Most of the other libc implementations do as well. I speak as somebody who has fixed bugs in several libc implementations relating to errno handling (it gets really interesting when threads are involved), so I'm quite familiar with the actual code - and what it actually does is set errno to 0 on entry to the library and set it to something else if an error occurs. To generate behaviour where errno is unmodified is actually harder than resetting it - the libc implementations typically use the 'errno == 0' property internally, and to avoid doing this would require an extra thread-local variable.

    Just because POSIX doesn't require a libc to do something doesn't mean that they don't all do it. There are lots of features in the real world C libraries that aren't in the spec, and they remain in the real world because it happens to be the right way to do it.



  • @kirchhoff said:

    Error: Success messages are never because of errno, in my opinion.

    That opinion is.. well, pretty stupid. The aforementioned BitchX bug was an errno leak related to a misplaced close() call. Ergo, you're wrong - there exists at least one such bug, so they can't "never happen", and you had all that information before expressing your 'opinion'.
     


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.