assert(0) behavior
Steven Schveighoffer via Digitalmars-d
digitalmars-d at puremagic.com
Mon Aug 3 16:57:36 PDT 2015
On 8/3/15 6:54 PM, Walter Bright wrote:
> On 8/3/2015 8:50 AM, Steven Schveighoffer wrote:
>> 1. They aren't removed, they are replaced with a nearly useless segfault.
>
> Not useless at all:
>
> 1. The program does not continue running after it has failed. (Please,
> let's not restart that debate.
You can run some code that is fresh, i.e. don't *continue* running
failing code, but it's ok, for example, to run a signal handler, or call
a pure function. My thought is that you should print the file location
and exit (perhaps with segfault).
> 2. Running it under a debugger, the location of the fault will be
> identified.
Yeah, the real problem is when you are not running under a debugger. If
you have an intermittent bug, or one that is in the field, a stack trace
of the problem is worth 100x more than a segfault and trying to talk a
customer through setting up a debugger, or even setting up their system
to do a core dump for you to debug. They aren't always interested in
that enough to care.
But also, a segfault has a specific meaning. It means, you tried to
access memory you don't have access to. This clearly is not that, and it
sends the wrong message -- memory corruption. This is not memory
corruption, it's a program error.
>> 2. If we are going to put something in there instead of "assert", why
>> not just
>> throw an error?
>
> Because they are expensive.
They are expensive when? 2 microseconds before the program ends? At that
point, I'd rather you spend as much resources telling me what went wrong
as possible. More info the better.
Now, if it's expensive to include the throw vs. not including it (I
don't know), then that's a fair point. If it means an extra few
instructions to set up the throw (which isn't run at all when the
assert(0) line isn't run), that's not convincing.
> To keep asserts in all their glory in released code, do not use the
> -release switch.
OK, this brings up another debate. The thing that triggered all this is
an issue with core.time, see issue
https://issues.dlang.org/show_bug.cgi?id=14863
Essentially, we wrote code to get all the clock information at startup
on a posix system that supports clock_gettime, which is immutable and
can be read easily at startup. However, how we handled the case where a
clock could not be fetched is to assert(0, "don't support clock " ~
clockname).
The clear expectation was that the message will be printed (along with
file/line number), and we can go fix the issue.
On Linux 2.6.32 - a supported LTS release I guess - one of these clocks
is not supported. This means running a simple "hello world" program
crashes at startup in a segfault, not a nice informative message.
So what is the right answer here? We want an assert to trigger for this,
but the only assert that stays in is assert(0). However, that's useless
if all someone sees is "segfuault". "some message" never gets printed,
because druntime is compiled in release mode. I'm actually quite
thrilled that someone figured this all out -- one person analyzed his
core dump to narrow down the function, and happened to include his linux
kernel version, and another person had the arcane knowledge that some
clock wasn't supported in that version.
Is there a better mechanism we should be using in druntime that is
clearly going to be compiled in release mode? Should we just throw an
assert error directly? Clearly the code is not "corrupted" at this
point, it's just an environmental issue. But we don't want to continue
execution. What is the right call?
At the very least, assert(0, "message") should be a compiler error, the
message is unused information.
-Steve
More information about the Digitalmars-d
mailing list