惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
WordPress大学
WordPress大学
T
The Exploit Database - CXSecurity.com
博客园_首页
MyScale Blog
MyScale Blog
The Cloudflare Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
美团技术团队
Stack Overflow Blog
Stack Overflow Blog
博客园 - 聂微东
M
MIT News - Artificial intelligence
Microsoft Security Blog
Microsoft Security Blog
F
Full Disclosure
V
V2EX
博客园 - Franky
博客园 - 三生石上(FineUI控件)
Hugging Face - Blog
Hugging Face - Blog
P
Proofpoint News Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
SecWiki News
SecWiki News
N
Netflix TechBlog - Medium
S
Secure Thoughts
酷 壳 – CoolShell
酷 壳 – CoolShell
Hacker News: Ask HN
Hacker News: Ask HN
爱范儿
爱范儿
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Webroot Blog
Webroot Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Martin Fowler
Martin Fowler
PCI Perspectives
PCI Perspectives
S
Security @ Cisco Blogs
Recorded Future
Recorded Future
Help Net Security
Help Net Security
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
AI
AI
Microsoft Azure Blog
Microsoft Azure Blog
K
Kaspersky official blog
G
GRAHAM CLULEY
H
Hackread – Cybersecurity News, Data Breaches, AI and More
C
CERT Recently Published Vulnerability Notes
U
Unit 42
T
Tor Project blog
Cloudbric
Cloudbric
Hacker News - Newest:
Hacker News - Newest: "LLM"
MongoDB | Blog
MongoDB | Blog
GbyAI
GbyAI
T
The Blog of Author Tim Ferriss
Security Latest
Security Latest
N
News and Events Feed by Topic
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

David Baron's Weblog

Software engineering, responsibility, and ownership Software engineering, responsibility, and ownership David Baron's weblog: Security and Inequality Running animations on the compositor thread David Baron's weblog: Tying ecosystems through browsers David Baron's weblog: Payments on the Web Thoughts on migrating to a secure Web David Baron's weblog: The need for government David Baron's weblog: Priority of constituencies How browser developers should seek feedback from Web developers A possible approach to shorter release cycles David Baron's weblog: Fifteen years Ten years of the Mozilla Foundation Open licensing at the W3C Why adding compositing and blending to CSS is harder than it looks How you can help with removing -moz- prefixes Moving bug history out of the primary display of a bug report Beware of locale-specific behavior in the C library Eating dogfood and shipping software Specification style and the future of the Web The bug system I wish I had CSS border-image changes and unprefixing Improving font size readability on Firefox for Android David Baron's weblog: CSS Animations, part 2 Hue-preserving color inversion with SVG filters Changes to handling of @-moz-keyframes David Baron's weblog: window.matchMedia() David Baron's weblog: CSS Animations What does a blur radius mean? Crash analysis in the future David Baron's weblog: calc() David Baron's weblog: colorDepth David Baron's weblog: Hidden complexity in specifications The most important field in a bug report: the summary WOFF font format submitted to W3C David Baron's weblog: :-moz-any() selector grouping setTimeout with a shorter delay Faster repainting in SVG foreignObject David Baron's weblog: Distributed Extensibility David Baron's weblog: Broadening crash analysis Correlating crashes with binary extensions or plugins David Baron's weblog: ex-HTML Downloadable font formats for the Web Web Accessibility as a Political Movement David Baron's weblog: CSS priorities David Baron's weblog: Bug priorities David Baron's weblog: Semi-vacation Some new CSS features in Firefox 3 David Baron's weblog: New selectors David Baron's weblog: The age of bugs Seeking a good Linux distribution David Baron's weblog: Teaching to the test David Baron's weblog: March 2008 David Baron's weblog: February 2008 David Baron's weblog: January 2008 David Baron's weblog: October 2007 David Baron's weblog: September 2007 David Baron's weblog: August 2007 David Baron's weblog: June 2007 David Baron's weblog: April 2007 David Baron's weblog: March 2007 David Baron's weblog: January 2007 David Baron's weblog: September 2006 David Baron's weblog: August 2006 David Baron's weblog: July 2006 David Baron's weblog: May 2006 David Baron's weblog: February 2006 David Baron's weblog: January 2006 David Baron's weblog: December 2005 David Baron's weblog: October 2005 David Baron's weblog: September 2005 David Baron's weblog: June 2005 David Baron's weblog: May 2005 David Baron's weblog: April 2005 David Baron's weblog: March 2005 David Baron's weblog: February 2005 David Baron's weblog: October 2004 David Baron's weblog: September 2004 David Baron's weblog: August 2004 David Baron's weblog: June 2004 David Baron's weblog: May 2004 David Baron's weblog: April 2004 David Baron's weblog: March 2004 David Baron's weblog: February 2004 David Baron's weblog: January 2004 David Baron's weblog: November 2003 David Baron's weblog: October 2003 David Baron's weblog: September 2003 David Baron's weblog: August 2003 David Baron's weblog: July 2003 David Baron's weblog: June 2003 David Baron's weblog: May 2003 David Baron's weblog: April 2003 David Baron's weblog: March 2003 David Baron's weblog: February 2003 David Baron's weblog: January 2003 David Baron's weblog: December 2002 David Baron's weblog: November 2002 David Baron's weblog: September 2002
Why debug builds (and assertions) are important
David Baron · 2013-07-30 · via David Baron's Weblog

I want to talk about why DEBUG builds are important.

First, though, I'd like to clarify terminology. When developers talk about debug builds, they might be talking about one of three things:

  1. builds that have the DEBUG macro defined, so that #ifdef DEBUG blocks are used
  2. builds that have compiler-generated debugging information, so that they work better in a debugger
  3. builds that have optimization disabled, so that they work better in a debugger

I want to talk about the first of these, the #ifdef DEBUG blocks. The most important difference when DEBUG is defined is often that assertions (in their various forms) are checked. See, for example the beginning of Element::BindToTree (which is called when an Element is attached to its parent). All of these NS_PRECONDITION macros are tested only in debug builds. They're not included in the release builds that we ship to users because they would slow things down. But in debug builds, they print a warning to the console, and they cause any xpcshell test to fail, and causes any reftest or mochitest (except browser-chrome mochitests) that isn't already marked as having known assertions (i.e., known failures) to fail. We also have fatal assertions, such as the MOZ_ASSERT macro, which cause any debug build to crash instantly, which would cause any test that hits it to fail.

To explain one reason this is important, I'd like to step away from software engineering for a minute and talk about airplanes. Airplanes are expected to be really safe, and the people who make them and fly them have developed ways of doing that to make them safe. One of these is the idea that it's generally hard for an airplane to fail catastrophically with only one thing going wrong; most serious airplane crashes have required multiple failures. Consider, for example, the crash of American Airlines Flight 191 in 1979. In this incident, due to faulty repair procedures, the left engine detached from the wing due to failure of the rear engine mount, swung around in front of the wing, and ejected itself over top of the wing. This, alone, should have been survivable. However, the engine detaching from the wing damaged the hydraulic lines and cut power to some monitoring systems whose power source was only connected to a single engine. The damaged hydraulic line led the leading edge slats on the wing to retract, reducing the aerodynamic stall speed of that wing to below its takeoff speed, and causing the aircraft to roll over and crash. The response to this crash was not only to forbid the maintenance procedures that damaged the engine mount. The response also included mandating slat relief valves so that the slats would not retract due to loss of hydraulic pressure.

So, back in the world of software, there are also times we want to make sure a single mistake can't lead to a serious failure. For example, when I see an exploitable security bug, I often want to fix that bug in two different ways, so that a single mistake, alone, couldn't lead to a similar bug happening again. (See, for example, followups to bug 607222 or the multiple fixes to bug 468645.) This is possible quite often, as many exploitable security bugs are the result of a sequence of things going wrong, just like airplane crashes.

But when bad things don't happen immediately when something goes wrong, how do we know that something is wrong in the first place? That's one thing all these assertions are for. They document our understanding of how the system is supposed to work. We generally shouldn't crash in an exploitable way when one thing goes wrong. But we generally should assert. The assertion might show that something has gone wrong that we assume won't, or that something has gone wrong which we know will produce bad results when interacting with another feature (even if it might not be interacting with that feature when the assertion fires). Running all of our test suites in debug builds and making the tests fail when new assertions fire allow us to prevent introducing these first-step-of-a-sequence problems in anything tested by our test suites.

Also (and less related to airplane crashes), the process of debugging a software problem is often a process of working backwards in time: we observe a problem and figure out what led to that state. This leads to another case where it's useful to have assertions: to document things that we know will lead to a failure (such as a crash) in the near future, but which represent a much easier point to debug backwards from (for example, the assertions about callback reentry in pldhash). When good assertions are present, problems are often easier to debug, since there will be assertions documenting something that goes wrong earlier, which shortens the amount of working backwards that we have to do to find the problem.

Likewise, we can also use assertions so they fire in cases where we know something has gone wrong, but we might not notice it. For example, if we can write an assertion that will fire in a certain case where things would be drawn incorrectly, we'll detect any case in which that incorrect painting happens, even if it happens in the middle of a test that was designed to test something else and isn't actually looking at what appears on the screen.

So assertions, the key component of debug builds, help us in multiple ways. They prevent problems from being introduced that are one step of a sequence that could lead to more serious problems, and they help us debug failures that have been observed in other ways, and they allow us to increase our test coverage.

Update (23:33): Robert O'Callahan points out that I missed another important reason for assertions: they serve as documentation. And they're more reliable than prose documentation, too, because they're tested to be correct.