When you run a debug build of Firefox you get a lot of stuff printed to stderr. Some of it looks like this:
++DOCSHELL 0x7f53d836b800 == 3
++DOMWINDOW == 5 (0x7f53d836c078) [serial = 5] [outer = (nil)]
and I imagine it’s occasionally useful.
You also see a lot of warnings like these, which I just saw (with duplicates removed) when I just started up Firefox, loaded www.mozilla.com, and then exited:
WARNING: 1 sort operation has occurred for the SQL statement '0x7f53e3d32208'. See https://developer.mozilla.org/En/Storage/Warnings details.: file /home/njn/moz/mc2/storage/src/mozStoragePrivateHelpers.cpp, line 144
WARNING: GetDefaultCharsetForLocale: need to add multi locale support: file /home/njn/moz/mc2/intl/locale/src/unix/nsUNIXCharset.cpp, line 146
WARNING: Ignoring duplicate observer.: file /home/njn/moz/mc2/modules/libpref/src/nsPrefBranch.cpp, line 594
WARNING: not an nsIRDFRemoteDataSource: 'remote != nsnull', file /home/njn/moz/mc2/rdf/datasource/src/nsLocalStore.cpp, line 312
WARNING: NS_ENSURE_SUCCESS(rv, 0) failed with result 0x8000FFFF: file /home/njn/moz/mc2/content/base/src/nsContentUtils.cpp, line 2527
WARNING: NS_ENSURE_SUCCESS(rv, rv) failed with result 0x80040111: file /home/njn/moz/mc2/content/base/src/nsFrameLoader.cpp, line 415
WARNING: NS_ENSURE_SUCCESS(rv, rv) failed with result 0x8053000C: file /home/njn/moz/mc2/content/base/src/nsGenericElement.cpp, line 5484
WARNING: NS_ENSURE_TRUE(aURI) failed: file /home/njn/moz/mc2/content/base/src/nsContentUtils.cpp, line 4706
WARNING: NS_ENSURE_TRUE(!(mAsyncExecutionThread)) failed: file /home/njn/moz/mc2/storage/src/mozStorageConnection.cpp, line 784
WARNING: NS_ENSURE_TRUE(pusher.Push(aBoundElement)) failed: file /home/njn/moz/mc2/content/xbl/src/nsXBLProtoImplMethod.cpp, line 327
WARNING: nsExceptionService ignoring thread destruction after shutdown: file /home/njn/moz/mc2/xpcom/base/nsExceptionService.cpp, line 197
WARNING: SQLite returned error code 1 , Storage will convert it to NS_ERROR_FAILURE: file /home/njn/moz/mc2/storage/src/mozStoragePrivateHelpers.cpp, line 113
WARNING: Subdocument container has no content: file /home/njn/moz/mc2/layout/base/nsDocumentViewer.cpp, line 2398
WARNING: Subdocument container has no frame: file /home/njn/moz/mc2/layout/base/nsDocumentViewer.cpp, line 2418
WARNING: Subdocument container has no frame: file /home/njn/moz/mc2/layout/base/nsDocumentViewer.cpp, line 2418
The NS_ENSURE_SUCCESS and NS_ENSURE_TRUE ones in particular look like assertion failures. I’ve heard before that Firefox assertions (outside the JS engine) are non-fatal. I was wondering about this last week and had planned to ask someone about it in more detail.
But before I did that, I spent several hours yesterday debugging the crash in bug 654573. Turns out the problem is that this assertion in mozStorageConnection.cpp fails:
NS_ENSURE_FALSE(mAsyncExecutionThread, NS_ERROR_UNEXPECTED);
This causes this warning to be printed out at run-time:
Oh, and just to make things really complicated, here’s the definition of NS_ENSURE_FALSE, from nsDebug.h:
#define NS_ENSURE_TRUE(x, ret) \
PR_BEGIN_MACRO \
if (NS_UNLIKELY(!(x))) { \
NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
return ret; \
} \
PR_END_MACRO
#define NS_ENSURE_FALSE(x, ret)
NS_ENSURE_TRUE(!(x), ret)
Oh look; if the condition fails it not only prints out a warning message, it also does an early return. And that’s exactly what was causing the crash, because some code that followed the assertion wasn’t run, which meant that a database connection wasn’t closed properly, which caused a use-after-free error.
If this assertion had been fatal, I wouldn’t have spent several hours yesterday debugging this crash, because there wouldn’t have been a crash; there would have been an assertion failure, and the problem would have been immediately obvious. (As it happens, I eventually worked out the problem when I noticed that warning message among the pages of output that Firefox produces.) If the assertion had been non-fatal but did not have the early return, there also probably wouldn’t have been a crash, but it’s hard to know, because once an assertion fails you’re pretty much in no-man’s land.
So, in summary, here are my thoughts about assertions:
- Non-fatal assertions are close to useless. They don’t get fixed. The warnings just get lost among the noise of all the messages that go to stderr.
- Non-fatal assertions that return early are worse than useless. Especially since the early-return behaviour is entirely non-obvious from their names.
One suggestion I heard on IRC yesterday was that there just aren’t enough developers in general to fix all the assertion failures if we were to make them fatal. But in contrast, the JS engine is able to use fatal assertions because it has a higher developer-to-code ratio than the rest of Firefox. (This makes me also think of compiler warnings, where there’s a similar disparity between the JS engine and the rest of Firefox.)
Because this is Mozilla, I’m sure there is a ton of history behind this current situation that I’m unaware of. I’d love to know what that is, and why we let obvious defects — because an assertion failure unambiguously indicates there’s a defect, be it in the code or the assertion itself — remain. Thanks!