Skip to content
This repository was archived by the owner on Apr 21, 2025. It is now read-only.

[Darwin] Disable NSAsserts in release builds. #860

Merged
merged 1 commit into from
May 23, 2024

Conversation

bc-lee
Copy link
Contributor

@bc-lee bc-lee commented May 17, 2024

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

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read the Flutter Style Guide recently, and have followed its advice.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@bc-lee bc-lee force-pushed the feature/disable-nsassert branch from 1fac750 to 88d344f Compare May 17, 2024 22:11
@Hixie
Copy link
Contributor

Hixie commented May 18, 2024

test-exempt: configuration change

Comment on lines +87 to +90
if (is_mac || is_ios) {
# Disable NSAsserts in release builds.
defines += [ "NS_BLOCK_ASSERTIONS=1" ]
}
Copy link
Member

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?

Copy link
Member

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.

Copy link
Member

@cbracken cbracken May 20, 2024

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.

Copy link
Member

@jmagman jmagman May 20, 2024

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 NSAsserts 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.

Copy link
Member

@jmagman jmagman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @knopp

@jmagman jmagman added the autosubmit Merge PR when tree becomes green via auto submit App label May 23, 2024
@auto-submit auto-submit bot merged commit 5b504e1 into flutter:master May 23, 2024
@bc-lee bc-lee deleted the feature/disable-nsassert branch May 23, 2024 22:09
bc-lee pushed a commit to bc-lee/flutter-engine that referenced this pull request May 26, 2024
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.
@bc-lee
Copy link
Contributor Author

bc-lee commented May 26, 2024

While NSAssert appears consistent with the rest of the Objective-C codebase, FML_DCHECK offers two key advantages:

  1. FML_DCHECK aligns more closely with the engine codebase's conventions.
  2. FML_DCHECK doesn't trigger unused variable warnings in release builds, unlike NSAssert.

The second part is explained in the another PR ( flutter/engine#53048 ). Also, I hope that the linked PR will be reviewed.

@jmagman
Copy link
Member

jmagman commented May 28, 2024

Thanks for looking into this, @bc-lee!

@bc-lee
Copy link
Contributor Author

bc-lee commented May 29, 2024

  1. FML_DCHECK doesn't trigger unused variable warnings in release builds, unlike NSAssert.

It turns out the second advantage is not entirely true. While it does not generate compile-time warnings, Flutter uses clang-tidy's clang-analyzer-deadcode.DeadStores (or simply deadcode.DeadStores) to identify unused variables. Although FML_DCHECK employs smart ways to avoid compile-time warnings, clang-tidy is too smart to be fooled by it. Since neither Chromium nor abseil uses clang-tidy to check for dead stores, they don't encounter this issue.

@zanderso
Copy link
Member

cc @chinmaygarde

auto-submit bot pushed a commit to flutter/engine that referenced this pull request May 30, 2024
…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
@jmagman jmagman added the revert Label used to revert changes in a closed and merged pull request. label May 30, 2024
Copy link
Contributor

auto-submit bot commented May 30, 2024

Time to revert pull request flutter/buildroot/860 has elapsed.
You need to open the revert manually and process as a regular pull request.

@auto-submit auto-submit bot removed the revert Label used to revert changes in a closed and merged pull request. label May 30, 2024
jmagman added a commit to jmagman/buildroot that referenced this pull request May 30, 2024
auto-submit bot pushed a commit that referenced this pull request May 31, 2024
#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.
@cbenhagen
Copy link

@bc-lee do you intend to re-land this or is there another fix for flutter/flutter#148279?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
autosubmit Merge PR when tree becomes green via auto submit App
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants