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

Conversation

@jmagman
Copy link
Member

@jmagman jmagman commented Nov 9, 2021

Run the static analyzer on the iOS embedder. Fix the issues, mostly related to memory management.

Hopefully soon we can run clang-tidy in post-submit or the push hooks flutter/flutter#91857

To run clang-tidy for iOS:

dart tools/clang_tidy/bin/main.dart --lint-all --compile-commands out/ios_debug/compile_commands.json --repo .

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 and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See testing the engine for instructions on
    writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

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

@jmagman jmagman self-assigned this Nov 9, 2021
@google-cla google-cla bot added the cla: yes label Nov 9, 2021
* The name of the callback.
*/
@property(retain) NSString* callbackName;
@property(copy) NSString* callbackName;
Copy link
Member Author

Choose a reason for hiding this comment

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

Foundation objects with mutable variants (NSMutableString) should be copy.

options:0
error:NULL];
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[networkConfigArray release];
Copy link
Member Author

Choose a reason for hiding this comment

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

networkConfigArray was leaked.

Copy link
Contributor

Choose a reason for hiding this comment

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

The style in projects I worked on prior to the advent of ARC was that unless there was a compelling reason not to--e.g., code that's called in a tight loop--it's far better to autorelease as part of the alloc/init statement, because then there's no chance of introducing a leak later via early return. It also made it much easier to review code for correctness, because any line that did an alloc/init but not an autorelease was immediately suspect, triggering a check for a corresponding release.

So tl;dr, I would make this part of line 276 instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

In MRC projects I've worked on the style guide was to init/release within a scope so we didn't hit memory highwater marks waiting for the autorelease pool to drain. And autorelease on return statements.
This style avoids memory bloat, but your suggested way probably makes it easier to do the right thing with memory management. MRC documentation/examples have fallen off the internet and there's no style guide in play, and Apple never published one. I'd rather avoid crashes and leaks than theoretical memory bloat issues (though they weren't theoretical in other projects I've worked on). So let's go with your style suggestion.

* Set by the initializer.
*/
@property(nonatomic) FlutterSendKeyEvent sendEvent;
@property(nonatomic, copy, readonly) FlutterSendKeyEvent sendEvent;
Copy link
Member Author

Choose a reason for hiding this comment

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

if (weak.get().enableObservatoryPublication) {
[[weak.get() delegate] publishServiceProtocolPort:url];
}
[url release];
Copy link
Member Author

Choose a reason for hiding this comment

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

url was leaked.

FlutterSendKeyEvent sendEvent =
^(const FlutterKeyEvent& event, FlutterKeyEventCallback callback, void* userData) {
[_engine.get() sendKeyEvent:event callback:callback userData:userData];
[weakSelf.get()->_engine.get() sendKeyEvent:event callback:callback userData:userData];
Copy link
Member Author

Choose a reason for hiding this comment

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

This didn't show up in the linter, but this retain cycle was exposed when I wrote the testReleasesKeyboardManagerOnDealloc and the view controller wasn't being released.

- (void)encodeRestorableStateWithCoder:(NSCoder*)coder {
NSData* restorationData = [[_engine.get() restorationPlugin] restorationData];
[coder encodeDataObject:restorationData];
[super encodeRestorableStateWithCoder:coder];
Copy link
Member Author

Choose a reason for hiding this comment

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

This was an analyzer warning, encodeRestorableStateWithCoder needs to encode the super class's state.

if (@available(iOS METAL_IOS_VERSION_BASELINE, *)) {
auto device = MTLCreateSystemDefaultDevice();
ios_version_supports_metal = [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v3];
[device release];
Copy link
Member Author

Choose a reason for hiding this comment

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

MTLCreateSystemDefaultDevice is NS_RETURNS_RETAINED

[self.keyboardManager addPrimaryResponder:responder];
[responder release];
FlutterTextInputPlugin* textInputPlugin = self.engine.textInputPlugin;
if (textInputPlugin != nil) {
Copy link
Member Author

Choose a reason for hiding this comment

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

self.engine is nullable. When I tested it threw when adding nil to the secondary responder array.

@jmagman jmagman changed the title Fix memory management analyzer warnings Fix memory management and other analyzer warnings Nov 9, 2021
@jmagman jmagman changed the title Fix memory management and other analyzer warnings Fix iOS embedder memory management and other analyzer warnings Nov 10, 2021
Copy link
Contributor

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

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

LGTM with nits

options:0
error:NULL];
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[networkConfigArray release];
Copy link
Contributor

Choose a reason for hiding this comment

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

The style in projects I worked on prior to the advent of ARC was that unless there was a compelling reason not to--e.g., code that's called in a tight loop--it's far better to autorelease as part of the alloc/init statement, because then there's no chance of introducing a leak later via early return. It also made it much easier to review code for correctness, because any line that did an alloc/init but not an autorelease was immediately suspect, triggering a check for a corresponding release.

So tl;dr, I would make this part of line 276 instead.

* of the key down event.
*/
@property(nonatomic) NSMutableDictionary<NSNumber*, NSNumber*>* pressingRecords;
@property(nonatomic, retain, readonly) NSMutableDictionary<NSNumber*, NSNumber*>* pressingRecords;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we have readonly private properties?

Copy link
Member Author

Choose a reason for hiding this comment

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

I didn't write this and I don't want to start a stylistic war, but I think properties should always preferred over ivars (and the backing ivar only touched in init, dealloc, getters, and setters), even when private, because of KVO, KVC, to enforce readonly, to enforce copy when it's readwrite.

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html

It’s best practice to use a property on an object any time you need to keep track of a value or another object.

Can we put a pin in this question for this PR? I only did the bare minimum to make the analyzer happy, plus some tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm aware of the property vs ivar debate; I actually don't have a strong opinion on that. I was just curious about the addition of readonly to a private proprety. It just seems odd to say that code within a class can modify the collection, but not replace it with a different collection.

But this wasn't intended to be a PR-blocking question.

Copy link
Member Author

@jmagman jmagman Nov 12, 2021

Choose a reason for hiding this comment

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

I'm aware of the property vs ivar debate; I actually don't have a strong opinion on that.

Guess I'm always geared up for a religious war in these kinds of reviews 😉

Re: the readonly, you're right, that wasn't a static analyzer warning. I did it because the property wasn't being set other than in init, so it could be made readonly, which I did in the spirit of preferring stricter property attributes, readonly, immutable, nonnull, etc. But yeah, it's not API just private so it doesn't really matter (unless you're KVOing on the property and need to handle updating notifications in the property setter, which we aren't). I can change it back if you prefer.

* The primary responders added by addPrimaryResponder.
*/
@property(nonatomic) NSMutableArray<id<FlutterKeyPrimaryResponder>>* primaryResponders;
@property(nonatomic, retain, readonly)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same question here.

// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// FLUTTER_NOLINT: https://github.com/flutter/flutter/issues/93360
Copy link
Member Author

Choose a reason for hiding this comment

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

This one is new.
FlutterUmbrellaImport is used in the copy_and_verify_framework_module target, is not included in the engine framework source, and cannot be compiled on its own.

When clang-tidy is run on this file, it fails with a clang-diagnostic-error (compilation failure). Add a FLUTTER_NOLINT to this file with link to flutter/flutter#93360.

@jmagman jmagman added the waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. label Nov 12, 2021
@fluttergithubbot fluttergithubbot merged commit c19137f into flutter:master Nov 12, 2021
@jmagman jmagman deleted the warnings-memory branch November 12, 2021 21:18
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 12, 2021
yx-mike added a commit to yx-mike/engine that referenced this pull request May 18, 2022
…er#29623)

有一些内存泄露,有些代码修改是在新代码,这个分支就不合了
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cla: yes platform-ios waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants