-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Document that error parameter must be initialized
#177730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document that error parameter must be initialized
#177730
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging. If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group. |
|
Please advise if this issue is insufficiently trivial to be exempt from a dedicated issue. |
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.
Code Review
This pull request adds documentation to many functions that use the GError** error pattern, clarifying that the GError* variable must be initialized before use. This is a valuable addition to prevent common mistakes with this pattern. My feedback focuses on making the new documentation even more precise by specifying that the variable must be initialized to NULL, which aligns with the underlying GLib g_set_error behavior.
engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h
Outdated
Show resolved
Hide resolved
engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h
Outdated
Show resolved
Hide resolved
engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h
Outdated
Show resolved
Hide resolved
engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h
Outdated
Show resolved
Hide resolved
engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_texture_gl.h
Outdated
Show resolved
Hide resolved
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
|
Gemini emitted a huge number of identical suggestions that the wording be changed. Gemini's analysis assumed that I was imprecise in my choice of words, but this is not the case, and Gemini's suggestion says something explicitly different from what I intended. |
… parameters to inline code documentation.
98b2b06 to
f0a9a4b
Compare
|
( |
robert-ancell
left a comment
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.
Thanks for this! I suggested a wording change but otherwise I think this change is good.
I also considered linking to the upstream documentation but I didn't find that any clearer describing why it should be initialized.
| * @engine: an #FlEngine. | ||
| * @error: (allow-none): #GError location to store the error occurring, or %NULL | ||
| * to ignore. | ||
| * to ignore. If `error` is not %NULL, `*error` must not be uninitialized. |
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.
This is a double negative and thus hard to understand - suggest instead "If provided, *error must be initialized.".
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.
That's fair, though I feel that if it says just "must be initialized", it may not be obvious to readers that both NULL and a pointer to an object are valid initialized values. Perhaps a parenthetical on this point...
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.
Okay, this should be much easier to understand:
/**
* fl_engine_start:
* @engine: an #FlEngine.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore. If `error` is not %NULL, `*error` must be initialized (typically
* %NULL, but an error from a previous call using GLib error handling is explicitly
* valid).
*
Is it good? 🙂
Silly me, I jumped the gun and committed this change to one file. 🤦
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.
Maybe "using GLib error handling" is unnecessary...
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.
Looks good. I think it's better to err on the side of being more verbose since consumers are less likely to understand the GLib conventions.
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'll propagate that wording out, then.
|
Mostly for the purposes of anyone who might stumble across this bug in the future - the recommended use of GError is to use // CORRECT CODE
g_autoptr(GError) error = nullptr;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
} |
… parameter to `fl_engine_start`.
…ion of all applicable functions.
robert-ancell
left a comment
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.
Thanks for working on this!
|
autosubmit label was removed for flutter/flutter/177730, because This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.
|
mattkae
left a comment
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.
Looks good to me too!
flutter/flutter@de4be4f...9f383e0 2025-11-20 [email protected] Roll Dart SDK from 331595776540 to 5b21f8a7d5d3 (1 revision) (flutter/flutter#178861) 2025-11-20 [email protected] Roll ICU from f27805b7d7d8 to a86a32e67b8d (1 revision) (flutter/flutter#178859) 2025-11-20 [email protected] Roll Dart SDK from d6f9477a2d9f to 331595776540 (1 revision) (flutter/flutter#178851) 2025-11-20 [email protected] Roll Skia from 5bdda9a41db9 to 6284b4f09e14 (3 revisions) (flutter/flutter#178849) 2025-11-20 [email protected] Roll Skia from 24c28206d912 to 5bdda9a41db9 (2 revisions) (flutter/flutter#178845) 2025-11-20 [email protected] Roll Dart SDK from 7506c64a5117 to d6f9477a2d9f (1 revision) (flutter/flutter#178844) 2025-11-20 [email protected] Roll Skia from fd41f3650729 to 24c28206d912 (2 revisions) (flutter/flutter#178841) 2025-11-20 [email protected] Use WidgetsBinding.instance.platformDispatcher in windowing instead of PlatformDispatcher.instance (flutter/flutter#178799) 2025-11-20 [email protected] [Impeller] Adds support for r32float textures (flutter/flutter#178418) 2025-11-20 [email protected] Roll Skia from a283da7a6b6c to fd41f3650729 (2 revisions) (flutter/flutter#178838) 2025-11-20 [email protected] [Impeller] Deny-list Adreno 640 and 650 for Vulkan eligibility. (flutter/flutter#178833) 2025-11-19 [email protected] Roll Skia from b5dc8c3494ac to a283da7a6b6c (8 revisions) (flutter/flutter#178832) 2025-11-19 [email protected] Roll Dart SDK from f7e9bd245fd9 to 7506c64a5117 (3 revisions) (flutter/flutter#178828) 2025-11-19 [email protected] Allow the `RawAutocomplete` to display the options even when one is selected (flutter/flutter#177705) 2025-11-19 [email protected] [web] Skip flaky service worker test (flutter/flutter#178820) 2025-11-19 [email protected] Only call glCheckFrameBufferStatus in the render pass in debug builds (flutter/flutter#178707) 2025-11-19 [email protected] Manual pub roll (flutter/flutter#178687) 2025-11-19 [email protected] Document that `error` parameter must be initialized (flutter/flutter#177730) 2025-11-19 [email protected] Update `_CircularProgressIndicatorState` to use `transform` directly (flutter/flutter#178569) 2025-11-19 [email protected] Fix layout for macOS frameworks for code assets (flutter/flutter#178625) 2025-11-19 [email protected] Roll Packages from 34746bb to 8f72e4b (7 revisions) (flutter/flutter#178800) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Flutter is built on top of GLib, and GLib's standard error mechanism
uses a structure `GError` and a function `g_set_error`. This function
takes a pointer to a pointer, setting it to a new `GError` for the outer
caller to receive. The model is designed to capture the first error that
occurs; as such, `g_set_error` checks if the supplied (by reference)
pointer is _already_ pointing at something. If it is, then it simply
emits a warning about this new error and discards it, assuming that
`error` already points at a presumably more-pertinent `GError`.
This semantic is sensible, but it isn't automatically obvious. It makes
sense when a function is calling multiple other functions, each of which
could return an error, ensuring that the error that gets returned is the
first one that happened. But, if you're only calling one function and
you don't have prior exposure to this design, it might not be
intuitively obvious that it has this intentional behaviour. Instead, the
`GError** error` parameter just looks like any old `out` parameter. That
can lead to code being written that doesn't bother to initialize the
error variable; after all, if no error occurs, it's irrelevant, and if
an error _does_ occur, then the function will overwrite it anyway,
right? (This latter being the incorrect assumption.)
```
// INCORRECT CODE
GError *error;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
g_error_free(error);
}
```
GLib handles the fact that this isn't automatically obvious to someone
with no prior experience with straightforward documentation:
> GLib ▶ set_error
>
> Does nothing if `err` is `NULL`; **if `err` is non-`NULL`, then `*err`
must be `NULL`**. A new `GError` is created and assigned to `*err`.
Since this is, ultimately, the function used internally by Flutter API
functions to return errors through this channel, Flutter effectively has
this same semantic. As such:
```
// CORRECT CODE
GError *error = nullptr;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
g_error_free(error);
}
```
(edited per @robert-ancell) In addition, `g_autoptr` can be used to make
a smart pointer that automatically ensures that the error, if any, is
not leaked.
```
// CORRECTER CODE
g_autoptr(GError) error = nullptr;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
}
```
Flutter should make a similar mention in its documentation so that
people who are just discovering the system don't make the same mistake I
did. 🙂
This PR updates the inline documentation comments for public functions
that take `GError** error` parameters to warn concisely about this
situation. Note that it is not required (at least by `g_set_error`) that
they poin at `NULL`, specifically, just that they not be
_uninitialized_.
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
---------
Co-authored-by: Robert Ancell <[email protected]>
Flutter is built on top of GLib, and GLib's standard error mechanism
uses a structure `GError` and a function `g_set_error`. This function
takes a pointer to a pointer, setting it to a new `GError` for the outer
caller to receive. The model is designed to capture the first error that
occurs; as such, `g_set_error` checks if the supplied (by reference)
pointer is _already_ pointing at something. If it is, then it simply
emits a warning about this new error and discards it, assuming that
`error` already points at a presumably more-pertinent `GError`.
This semantic is sensible, but it isn't automatically obvious. It makes
sense when a function is calling multiple other functions, each of which
could return an error, ensuring that the error that gets returned is the
first one that happened. But, if you're only calling one function and
you don't have prior exposure to this design, it might not be
intuitively obvious that it has this intentional behaviour. Instead, the
`GError** error` parameter just looks like any old `out` parameter. That
can lead to code being written that doesn't bother to initialize the
error variable; after all, if no error occurs, it's irrelevant, and if
an error _does_ occur, then the function will overwrite it anyway,
right? (This latter being the incorrect assumption.)
```
// INCORRECT CODE
GError *error;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
g_error_free(error);
}
```
GLib handles the fact that this isn't automatically obvious to someone
with no prior experience with straightforward documentation:
> GLib ▶ set_error
>
> Does nothing if `err` is `NULL`; **if `err` is non-`NULL`, then `*err`
must be `NULL`**. A new `GError` is created and assigned to `*err`.
Since this is, ultimately, the function used internally by Flutter API
functions to return errors through this channel, Flutter effectively has
this same semantic. As such:
```
// CORRECT CODE
GError *error = nullptr;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
g_error_free(error);
}
```
(edited per @robert-ancell) In addition, `g_autoptr` can be used to make
a smart pointer that automatically ensures that the error, if any, is
not leaked.
```
// CORRECTER CODE
g_autoptr(GError) error = nullptr;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
}
```
Flutter should make a similar mention in its documentation so that
people who are just discovering the system don't make the same mistake I
did. 🙂
This PR updates the inline documentation comments for public functions
that take `GError** error` parameters to warn concisely about this
situation. Note that it is not required (at least by `g_set_error`) that
they poin at `NULL`, specifically, just that they not be
_uninitialized_.
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
---------
Co-authored-by: Robert Ancell <[email protected]>
Flutter is built on top of GLib, and GLib's standard error mechanism
uses a structure `GError` and a function `g_set_error`. This function
takes a pointer to a pointer, setting it to a new `GError` for the outer
caller to receive. The model is designed to capture the first error that
occurs; as such, `g_set_error` checks if the supplied (by reference)
pointer is _already_ pointing at something. If it is, then it simply
emits a warning about this new error and discards it, assuming that
`error` already points at a presumably more-pertinent `GError`.
This semantic is sensible, but it isn't automatically obvious. It makes
sense when a function is calling multiple other functions, each of which
could return an error, ensuring that the error that gets returned is the
first one that happened. But, if you're only calling one function and
you don't have prior exposure to this design, it might not be
intuitively obvious that it has this intentional behaviour. Instead, the
`GError** error` parameter just looks like any old `out` parameter. That
can lead to code being written that doesn't bother to initialize the
error variable; after all, if no error occurs, it's irrelevant, and if
an error _does_ occur, then the function will overwrite it anyway,
right? (This latter being the incorrect assumption.)
```
// INCORRECT CODE
GError *error;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
g_error_free(error);
}
```
GLib handles the fact that this isn't automatically obvious to someone
with no prior experience with straightforward documentation:
> GLib ▶ set_error
>
> Does nothing if `err` is `NULL`; **if `err` is non-`NULL`, then `*err`
must be `NULL`**. A new `GError` is created and assigned to `*err`.
Since this is, ultimately, the function used internally by Flutter API
functions to return errors through this channel, Flutter effectively has
this same semantic. As such:
```
// CORRECT CODE
GError *error = nullptr;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
g_error_free(error);
}
```
(edited per @robert-ancell) In addition, `g_autoptr` can be used to make
a smart pointer that automatically ensures that the error, if any, is
not leaked.
```
// CORRECTER CODE
g_autoptr(GError) error = nullptr;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
}
```
Flutter should make a similar mention in its documentation so that
people who are just discovering the system don't make the same mistake I
did. 🙂
This PR updates the inline documentation comments for public functions
that take `GError** error` parameters to warn concisely about this
situation. Note that it is not required (at least by `g_set_error`) that
they poin at `NULL`, specifically, just that they not be
_uninitialized_.
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
---------
Co-authored-by: Robert Ancell <[email protected]>
Flutter is built on top of GLib, and GLib's standard error mechanism
uses a structure `GError` and a function `g_set_error`. This function
takes a pointer to a pointer, setting it to a new `GError` for the outer
caller to receive. The model is designed to capture the first error that
occurs; as such, `g_set_error` checks if the supplied (by reference)
pointer is _already_ pointing at something. If it is, then it simply
emits a warning about this new error and discards it, assuming that
`error` already points at a presumably more-pertinent `GError`.
This semantic is sensible, but it isn't automatically obvious. It makes
sense when a function is calling multiple other functions, each of which
could return an error, ensuring that the error that gets returned is the
first one that happened. But, if you're only calling one function and
you don't have prior exposure to this design, it might not be
intuitively obvious that it has this intentional behaviour. Instead, the
`GError** error` parameter just looks like any old `out` parameter. That
can lead to code being written that doesn't bother to initialize the
error variable; after all, if no error occurs, it's irrelevant, and if
an error _does_ occur, then the function will overwrite it anyway,
right? (This latter being the incorrect assumption.)
```
// INCORRECT CODE
GError *error;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
g_error_free(error);
}
```
GLib handles the fact that this isn't automatically obvious to someone
with no prior experience with straightforward documentation:
> GLib ▶ set_error
>
> Does nothing if `err` is `NULL`; **if `err` is non-`NULL`, then `*err`
must be `NULL`**. A new `GError` is created and assigned to `*err`.
Since this is, ultimately, the function used internally by Flutter API
functions to return errors through this channel, Flutter effectively has
this same semantic. As such:
```
// CORRECT CODE
GError *error = nullptr;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
g_error_free(error);
}
```
(edited per @robert-ancell) In addition, `g_autoptr` can be used to make
a smart pointer that automatically ensures that the error, if any, is
not leaked.
```
// CORRECTER CODE
g_autoptr(GError) error = nullptr;
if (!fl_method_call_respond_success(method_call, result_value, &error)) {
g_warning("Failed to send Flutter Platform Channel response: %s", error->message);
}
```
Flutter should make a similar mention in its documentation so that
people who are just discovering the system don't make the same mistake I
did. 🙂
This PR updates the inline documentation comments for public functions
that take `GError** error` parameters to warn concisely about this
situation. Note that it is not required (at least by `g_set_error`) that
they poin at `NULL`, specifically, just that they not be
_uninitialized_.
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
---------
Co-authored-by: Robert Ancell <[email protected]>
Flutter is built on top of GLib, and GLib's standard error mechanism uses a structure
GErrorand a functiong_set_error. This function takes a pointer to a pointer, setting it to a newGErrorfor the outer caller to receive. The model is designed to capture the first error that occurs; as such,g_set_errorchecks if the supplied (by reference) pointer is already pointing at something. If it is, then it simply emits a warning about this new error and discards it, assuming thaterroralready points at a presumably more-pertinentGError.This semantic is sensible, but it isn't automatically obvious. It makes sense when a function is calling multiple other functions, each of which could return an error, ensuring that the error that gets returned is the first one that happened. But, if you're only calling one function and you don't have prior exposure to this design, it might not be intuitively obvious that it has this intentional behaviour. Instead, the
GError** errorparameter just looks like any oldoutparameter. That can lead to code being written that doesn't bother to initialize the error variable; after all, if no error occurs, it's irrelevant, and if an error does occur, then the function will overwrite it anyway, right? (This latter being the incorrect assumption.)GLib handles the fact that this isn't automatically obvious to someone with no prior experience with straightforward documentation:
Since this is, ultimately, the function used internally by Flutter API functions to return errors through this channel, Flutter effectively has this same semantic. As such:
(edited per @robert-ancell) In addition,
g_autoptrcan be used to make a smart pointer that automatically ensures that the error, if any, is not leaked.Flutter should make a similar mention in its documentation so that people who are just discovering the system don't make the same mistake I did. 🙂
This PR updates the inline documentation comments for public functions that take
GError** errorparameters to warn concisely about this situation. Note that it is not required (at least byg_set_error) that they poin atNULL, specifically, just that they not be uninitialized.Pre-launch Checklist
///).