-
Notifications
You must be signed in to change notification settings - Fork 257
[Darwin] Disable NSAsserts in release builds. #860
Conversation
Chromium has a similar gn flag to disable asserts in release builds: https://source.chromium.org/chromium/chromium/src/+/main:build/config/BUILD.gn;drc=9dab28144192cefadbb96b778ef866ea3deb74ff;l=148 Related: flutter/flutter#148279
1fac750
to
88d344f
Compare
test-exempt: configuration change |
if (is_mac || is_ios) { | ||
# Disable NSAsserts in release builds. | ||
defines += [ "NS_BLOCK_ASSERTIONS=1" ] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really surprised we didn't already have this on...
@cbracken or @chinmaygarde are you aware of any reason why we wouldn't want to disable NSAssert
in release?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, we don't use foundation assertions.
If the assertion needs to be fatal in all modes, there is FML_CHECK
. If its a useful signal while developing the engine, there is FML_DCHECK
. There are vanishingly few cases where the algorithmic complexity of an operation changes based on the either mode so it mostly just to indicate "actionable to end-users" vs "actionable to engine-developers". If its actionable to neither, there is typically no assertion.
The contributing factor for this suppression seems to be here. I think that code handles the case via an early return.
It depends on whether the macOS/iOS embedder authors expect assertions to be blocked in release modes and whether this is a good assertion to have. At least to my reading, it looks like no one understands how we got into this situation and so we are disabling the assertion. But the ability to reason about the severity of ignoring the assertion and whether ignoring it will cause issues further down the line is perhaps lost now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed with @chinmaygarde. I don't think we'd left them enabled intentionally, but rather I think mostly assumed we were using the FML macros.
To be honest, I thought I had gone through and replaced any I found with FML macros at least in the macOS embedder, but maybe that was just cleaning up Windows assertions (e.g. flutter/engine#38826), and just imagined I'd also got around to it for macOS.
We should probably come to a decision as to whether we want to standardise on one other the other so we don't have a semi-random mix of the two. Personal preference would be to standardise on FML across the board both for consistency and because they provide more indication of intent, but either way is fine.
Happy to send a cleanup patch for the macOS embedder and common code. Happy to do iOS too, but am super familiar with the macOS code and it should be straightforward to reason about whether any should actually be FML_CHECK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think standardizing on the macros makes senses, though unless we have a lint forbidding NSAsserts
and friends, they will sneak in via reviewers not being aware its disallowed.
NSAssert
NSCAssert
I vote we should turn this on to match the Xcode default (ENABLE_NS_ASSERTIONS
set to NO
in release) of having NSAssert
s fire in debug but not in-the-wild production apps. But that wouldn't prevent us from auditing the embedder code to swap to the FML macros.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @knopp
In flutter/buildroot#860 , disabling NSAssert in release build was added, and flutter#53005 tries to roll the change into the engine. However, the change is blocked due to several compilation errors in the engine. This is due to the fact that Google's DCHECK(in flutter engine, FML_DCHECK) does not make unused variable warning even in release build, while traditional assertion macro like assert or NSAssert does. For example, the following code will be expanded like this: code: FML_DCHECK(status == kCVReturnSuccess && pxbuffer != nullptr) << "Failed to create pixel buffer"; expanded code: true || (status == kCVReturnSuccess && pxbuffer != nullptr) ? (void)0 :: : fml::LogMessageVoidify() & ::fml::LogMessage(::fml::kLogFatal, 0, 0, nullptr).stream() However, equivalent code with NSAssert will make unused variable warning, since the expanded code doesn't have any reference to the variable: code: NSAssert(status == kCVReturnSuccess && pxbuffer != NULL, @"Failed to create pixel buffer."); expanded code: do { } while (0) To unblock the build, this CL replaces several NSAssert with FML_DCHECK in the engine codebase. This CL isn't aimed to replace all NSAssert with FML_DCHECK since discussions in flutter/buildroot#860 are not finalized whether to replace all NSAssert with FML_DCHECK or not.
While
The second part is explained in the another PR ( flutter/engine#53048 ). Also, I hope that the linked PR will be reviewed. |
Thanks for looking into this, @bc-lee! |
It turns out the second advantage is not entirely true. While it does not generate compile-time warnings, Flutter uses |
…53048) In flutter/buildroot#860, disabling `NSAssert` in release build was added, and #53005 tries to roll the change into the engine. However, the change is blocked due to several compilation errors in the engine. This is due to the fact that Google's `DCHECK`(in flutter engine, `FML_DCHECK`) does not make unused variable warning even in release build, while traditional assertion macro like `assert` or `NSAssert` does. For example, the following code will be expanded like this: code: ```c++ FML_DCHECK(status == kCVReturnSuccess && pxbuffer != nullptr) << "Failed to create pixel buffer"; ``` expanded code: ```c++ true || (status == kCVReturnSuccess && pxbuffer != nullptr) ? (void)0 :: : fml::LogMessageVoidify() & ::fml::LogMessage(::fml::kLogFatal, 0, 0, nullptr).stream() ``` However, equivalent code with `NSAssert` will make unused variable warning, since the expanded code doesn't have any reference to the variable: code: ```c++ NSAssert(status == kCVReturnSuccess && pxbuffer != NULL, @"Failed to create pixel buffer."); ``` expanded code: ```c++ do { } while (0) ``` To unblock the build, this CL replaces several `NSAssert` with `FML_DCHECK` in the engine codebase. This CL isn't aimed to replace all `NSAssert` with `FML_DCHECK` since discussions in flutter/buildroot#860 are not finalized whether to replace all `NSAssert` with `FML_DCHECK` or not. [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Time to revert pull request flutter/buildroot/860 has elapsed. |
This reverts commit 5b504e1.
#860 isn't cleanly rolling into the engine due to side effects of turning off NSAsserts in release. Revert until the fixes are in the engine.
@bc-lee do you intend to re-land this or is there another fix for flutter/flutter#148279? |
Chromium has a similar gn flag to disable asserts in release builds: https://source.chromium.org/chromium/chromium/src/+/main:build/config/BUILD.gn;drc=9dab28144192cefadbb96b778ef866ea3deb74ff;l=148
Related: flutter/flutter#148279
Pre-launch Checklist
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.