• My Name (unregistered)

    E_NOT_A_WTF

    This is C++, right? runtime_assert is most likely a macro that stringifies its argument using # then calls a function to log the failure before crashing. assert(might_be_falsehood && "comment") is a lazy way of providing textual comments to predicates that might be hard to understand otherwise.

    There are other ways to do that (e.g. provide a special argument for the comment, like static_assert in newer versions of the standard), but, since assert is in the standard library and only has one argument (the predicate) and most implementations stringify it in the error message, the predicate && "comment" idiom is too widespread to battle.

  • (nodebb)

    Maybe runtime_assert is a C preprocessor macro and the macro prints the stringification of its argument if it evaluates to false.

    https://en.cppreference.com/w/cpp/preprocessor/replace#.23_and_.23.23_operators

  • ray10k (unregistered) in reply to Jeremy Pereira

    My assumption as well, had to work with a library that did exactly that. Never came across that 'false && "message"' pattern, though. On the other hand, apparently macro expansion happened before the string got printed, leaving me to scratch my head why '5 != 6' was a problem.

  • Michael P (unregistered) in reply to Jeremy Pereira

    Yes, I think that is the obvious explanation. The standard assert() is always a macro, in large part because it is defined to have no effect if the preprocessor macro NDEBUG is defined (when <assert.h> or <cassert> is included). I suspect that Chris V is a junior developer who does not have a strong understanding of C, which makes me hope that this is not any important kind of compliance testing.

  • Raj (unregistered) in reply to My Name

    I've done that kind of thing, just like I've done condition || die "condition" in perl. Maybe it's not the most elegant thing in the world but it works.

    Maybe I'm lazy or maybe I just don't have time to create EnterpriseAssertionFactoryFactory helpers or whatever would be considered an acceptable way to handle unhappy paths.

    Full disclaimer: a long time ago I've also done "on error resume next" in VB script so it's possible I'm just evil.

  • Dave (unregistered)

    Why would you Try something when you can tell whether it'll fail or not?

  • (nodebb)

    Mostly it should really just omit the whole if block and just put the assertion before the then clause?

  • Simon Clarkstone (unregistered)

    People above have already discussed why the false && "string" can be a good idea (and I have seen it explained before), but I think that

    if (someConditionalStatement)  
    {
        // do stuff  
    }
    else  
    {
        runtime_assert(someConditionalStatement);  
    }
    

    can be sensible too. When assertions are turned off, the application will recover from the condition being true (by skipping the code that presumably can't work when the condition is false) but when developing you will get alerted that it has happened. For example, if the condition being false can only occur in some legacy situation or a future situation when other parts of the application have changed.

    OTOH I think that adding some non-fatal logging to the else branch would be a good idea.

  • Argle (unregistered)

    I have been in this business a long time. 45 long years ago I made some LEDs blink as directed with toggle switches. Yesterday I was poring over some PHP (a WTF in its own right) written by someone who hung out a shingle claiming 20 years of experience. Leaving aside the Bobby Table vulnerabilities, the code was a hodge-podge of Javascript style bracing, C-style bracing, complicated if/else statements in a single line, random tabbing and even no tabbing. I look at today's WTF and think "how perfectly ordinary." Randall Munroe (https://xkcd.com/2030/) and John Oliver (https://www.youtube.com/watch?v=svEuG_ekNT0) try to sound the alarm about one small aspect of programming... yet people keep trusting their lives with programming. I get depressed.

    Yesterday I got a call from Amex security. Minutes before and after I bought lunch, someone used my card 2000 miles away. Is it any surprise that someone has a security leak?

  • Karl Bielefeldt (github)

    I've worked in C++ embedded code bases where exceptions were not allowed and most asserts were compiled out in production builds. This is still a strange way to use asserts, though.

  • Some Ed (unregistered) in reply to Raj

    Yes, but have you done

    condition || (undef && die "condition");

    ? That's the real perl5 equivalent of what this perpetrator's been doing.

    (I have caught such things in code review, although usually they don't use die, but instead do something else which will cause the program to exit with a very misleading error message. I generally handle it by explaining to the submitter what a comment is and how to use them. Except for one special snowflake who clearly knew what comments were and how to use them, but still tried this anyway.)

  • sizer99 (google)

    If it really is 'everywhere' then that is almost the worst. The worst thing is obviously a codebase with no error handling.

    The second worst thing is a codebase with runtime asserts everywhere, even for things that could be recovered from. In this case if asserts are on the things crashes at the worst possible time (any time), and if they're off you get nothing AND the program just rumbles on with known bad configuration without trying to handle it properly. It's extremely lazy.

    I'm not against asserts (with stack dumps and context) - sometimes you're just in a situation you can't recover from and need to shut down. But those are fairly rare. Most things can be recovered from and politely logged.

    I've had people argue that just crashing the program any time something's wrong is superior because at least it gets people's attention - but that's not true at all. These things are usually running unattended, and a crash + disappearing into the void isn't noticed any more than logged errors are, because do you think these guys set up crash notifications? Hah!

  • Reginald P. Smithington (unregistered) in reply to Raj

    We basically just implemented that in our codebase because our customers were complaining about too many unhandled exceptions in the program.

    I work in the medical industry.

  • Angela Anuszewski (google) in reply to Karl Bielefeldt

    Agreed - my customer won't let us use exceptions. I had a very angry engineer fresh out of college that apparently didn't know any alternative shouting at me over it. I just shrugged and told him it was a customer requirement, get over it. He didn't last too long here. Oh well.

  • Zero (unregistered)

    May be the coder meant

        runtime_assert(someConditionalStatement)
        // do stuff
    

    but could not imagine that the "do stuff" will not be executed if someConditionalStatement is false, even if it is not enclosed in an IF.

  • Chris (unregistered)

    As the original submitter, I will point out that these asserts are not in any way critical to what I was testing, and shouldn't be capable of actually being triggered (as per the old quote about the code having been proven to be correct, but not tested).

    I expected a lot more discourse about bad macro usage / how bad macros can be. If you had never seen this pattern before, what would you expect the code provided is actually doing? There are good reasons and use cases for macros, but I think this sort of thing is simply terrible. Even if it is / was common, doesn't make it good.

    However, it is nice to know there was some method to that madness.

  • Miserable (unregistered)

    MISRA specifies that "Exceptions shall only be used for error handling." The example is clearly for debugging: MISRA precludes the inclusion of exceptions in the code base for that purpose, even if you have heard about them and understand them.

  • negative infinity (unregistered) in reply to Raj
    m_complianceProvider.getAssertionFactory(eAG_DEBUG_ASSERTION_GROUP /*Prod: eAG_PRODUCTION_ASSERTION_GROUP*/)
        .createAsserter(eAG_QA_ASSERTION_GROUP)
        .doAssertion(false && "This line cannot be reached", m_complianceProvider.lookupDescription("unreachable")); 
    
  • (nodebb)

    Oh, how come you missed the more interesting point? Imagine calling someConditionalStatement causes some side effects, or may be influenced by concurrently running code, and may evaluate differently when you call it later on again. There the real fun starts: what the fun is that?

  • (nodebb) in reply to Chris
    • these asserts [...] shouldn't be capable of actually being triggered*

    As far as I know, that's precisely what asserts are for: "can't happen" scenarios such that if they ever fire, it means your code is well and truly broken. For all other errors, you need actual error handling.

    I expected a lot more discourse about bad macro usage / how bad macros can be. If you had never seen this pattern before, what would you expect the code provided is actually doing? There are good reasons and use cases for macros, but I think this sort of thing is simply terrible. Even if it is / was common, doesn't make it good.

    It's not just common, it's standard. As in, the C99 standard explicitly says assertions "shall be implemented as a macro, not as an actual function" and that when false, "the assert macro writes information about the particular call that failed (including the text of the argument, the name of the source file, the source line number,and the name of the enclosing function" (emphasis mine). The only deviation here is using a custom macro instead of assert.

  • isthisunique (unregistered)

    If I were to be kind, I'd assume it's in the else as there somehow wasn't a guarantee of runtime_assert definitely preventing code execution.

    What the && is about is anyone's guess. Could be some weird thing with the macro or operator overriding.

    It would also tend to strip it out for optimised builds but not for debug builds. While never run it would be present there in the binary.

  • Chris (unregistered) in reply to Medinoc

    I have no problem with assert(a != b) as a macro. I have a problem with assert(a != b && "Some string which is definitely not a conditional statement, yet appears with a && operator"), in order to give the macro access to a helpful string. If that doesn't smell funny to you, that's because you've gotten used to this weirdness.

  • P (unregistered) in reply to Chris

    You're just bad, git gud dude

  • (nodebb) in reply to Chris

    Well technically the string is a condition, one which is always true. On my end, instead of assert(false && "message"); I tended to use assert(strlen("message")==0) (or possibly assert(condition || strlen("message")==0)) instead.

    But I see your point. It's true that it would be cleaner if the message were explicitly a parameter of assert(). Which is the case in C#... at the price of not being able to show the expression (which made the message argument a necessity).

  • Cbuttius (unregistered)

    Without looking at the other comments, runtime_assert is a macro and the important thing is you get reflection, i.e. what is in there gets printed out. assert(false) doesn't help anyone, assert( false && "This is why you failed" ) does. It's a clever way to report the error.

    Note that runtime asserts normally only run in debug builds, and you're expected to fix them for release builds.

  • David Mårtensson (unregistered) in reply to My Name

    One question though ...

    I know you can do lots of things with macros and that they can have arguments.

    But in this case, you only have one argument, a boolean.

    The macro should never see the string, only the resulting false value.

    Or am I missing some new fancy source rewrite type of macro?

  • G (unregistered)

    There's nothing wrong with assert (I assume this is a variant of it). It would've been useful if it had a message parameter, but it doesn't. So instead of assert(false) I end up writing assert(!"Some reason"). In C++, exceptions are intended to be used when something exceptional happens that can be caught by the user and handled sanely. If it can't be handled, don't throw an exception, assert: then you get an exact crash dump that can be used to analyze the issue. You don't get that from exceptions, you just get an error message that you can hopefully locate again.

  • (nodebb) in reply to David Mårtensson

    C macros have a stringification operator, so you can refer to the text of a macro argument, rather than its value.

Leave a comment on “Assert Yourself”

Log In or post as a guest

Replying to comment #509668:

« Return to Article