Teaching old assert() new Tricks

(blog.ngs-lang.org)

22 points | by todsacerdoti 3 days ago ago

7 comments

  • Rygian an hour ago

    The other day I had a senior developer tell me that he uses assert to perform critical security checks (eg input validation logic, size of input less than size of buffer, ...) and therefore his code is secure.

    I asked if the compiler preserved the asserts when not compiling in debug mode.

    • snovv_crash 36 minutes ago

      Even if it did, DoS is still a valid security issue that can be exploited.

  • TheNewAndy 3 days ago

    I used to like having nice strings to go with my asserts and would often do something like: assert(condition && "explanation of assert"). Now I think that the whole point of an assert is that it is for errors that require a code change (i.e. it is not recoverable at runtime) and so the very first thing that will happen in the investigation will be looking at the code with the assert - so a comment will do just fine if things aren't obvious. We also know that the programmer is going to need to understand the code that they are changing, and we also know that whoever wrote the code must have had a wrong assumption, so while their documentation is a good clue, it is also to be treated with some level of suspicion. As a result, I go for a simple assert, occasionally with a comment that explains why the assert should never fail.

    Being able to use the value asserted is nice sugar though. I will take that :)

    • akira2501 5 hours ago

      > and so the very first thing that will happen in the investigation will be looking at the code with the assert

      And the very next thing that will happen is me swearing up and down that I wished I captured more context at the point of error so I could understand the corner case much more easily.

      assert, on failure, should dump as much function and stack context as it possibly can generate; and possibly, a string tag for _user_ convenience in reporting on and differentiating for themselves the specific error condition.

      mainframes are great for this. You get a custom tagged error message that conveys the subsystem, error level, and error number along with a text error string. This makes cataloging and classifying errors automatic for everyone who sees and conveys them. Then you can use the system record store to go get the context information generated at the site of the error itself and build a much clearer idea of why the particular operation failed.

    • o11c 7 hours ago

      One thing that severely hinders assertion strings is that people can't seem to decide whether the string should state the intended case or the failure case.

      By contrast, being able to dump out the inputs to the failing expression is always useful. This is mostly discussed in the context of test-suite asserts, but should probably be generalized.

    • vueko 5 hours ago

      One reason I like assert strings is that they can assist bug triage in a large organization, assuming that (as in my environment) the string is available outside of the core/kernel dump, probably in the kernel ring buffer/logs. Often, keying off of line number won't work across different branches, maintenance releases, patches and the like, so having a unique-ish string to search known issues/chat history/etc with is valuable. Sure, you can check out the code corresponding to the build that produced the core and find the code context from there, but that's another step that takes time, especially if you have to traverse a bunch of mappings like "oh, the core's from a machine on B_FOO_1337, which according to this one service corresponds to commit abcdef123, which is in repo baz, which I don't actually have checked out and/or fetched recently, oops." In an environment of this sort, it's also frequently not super quick or straightforward to get a debugger set up with the appropriate symbols to open the core and see the context - if a person running through a big list of defects can simply plug the string into a search and go oh, yup, it's known issue #12345 vs. having to hunt for the correct symbols, copy the (potentially several gb!) core around, get gdb to happily open it, etc, that eventually adds up to big time savings. Finally, compiler optimizations can make it so that, while a value is present in the core, the debugger can't automatically find it and gives you that <value optimized out> thing. While you usually can go digging around in the registers to extract it, that's a pain and yet more time. If you put the value(s) of the failed assertion in the string, that's one less spot for someone doing triage to get hung up on when trying to tell whether an issue is something new or just frequency of a known issue.

      For stuff I'm just writing by and for myself, yeah, I take your approach. For software that will generate failures I may not be the first person in an organization to have to look at, I add friendly strings.