-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
*: fix the fmtsafe
linter and fix the fallout
#49660
Conversation
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.
Everything under sql/ LGTM
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @dt, @irfansharif, and @tbg)
@@ -236,11 +236,11 @@ func readInputFiles( | |||
}) | |||
|
|||
if err := grp.Wait(); err != nil { | |||
return errors.Wrap(err, dataFile) |
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 don't like that this a requirement in our codebase, to be honest... does this really feel ergonomic or useful to you as a lint rule? I won't block this PR (thanks very much for doing this toil) but I do feel this deserves some questioning.
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 this rule is trying to make sure we don't pass off PII information as what the error library expects is a simple hardcoded message. The case below is more relevant - errors.Wrap(err, typedExpr.String())
. Do we want the string representation of the typedExpr to be treated as non-PII?
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.
does the error library expect the argument to Wrap
(not wrapf), to be a simple hardcoded message?
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.
does the error library expect the argument to Wrap (not wrapf), to be a simple hardcoded message
No it does not. Jordan is right. I'll explain more in a comment under.
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.
LGTM. I can only imagine how cumbersome these fixes are, thanks for doing them.
@@ -96,29 +97,31 @@ func run(pass *analysis.Pass) (interface{}, error) { | |||
if fd, ok := n.(*ast.FuncDecl); ok { | |||
// This is the function declaration header. Obtain the formal | |||
// parameter. |
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.
[nit] Update comment to mention the enclosing fn name?
@@ -162,7 +162,7 @@ func listFailures( | |||
continue | |||
} | |||
if err := json.Unmarshal([]byte(line), &te); err != nil { | |||
return errors.Wrap(err, line) | |||
return errors.Wrapf(err, "unable to parse %q", line) |
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.
Unrelated to this PR, is it generally 'safer' to use %q over %s for byte slices? If so, is this also something we could/should use a linter for?
pkg/kv/kvserver/replica_command.go
Outdated
// NB: we have to wrap the existing error here as consumers of this | ||
// code look at the root cause to sniff out the changed descriptor. | ||
err = &benignError{errors.Wrap(err, msg)} | ||
if dErr := maybeDescriptorChangedError(desc, true /*wrap*/, err); dErr != nil { |
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.
[nit] Here and below, I have a slight preference for pulling out the wrapping logic out of maybeDescriptorChangedError and simply wrapping at the callsites, as before. I do like the return type being changed to an error
, we should keep that.
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 even keeping the comment block as to why we're wrapping vs. not is a good idea.
Thanks Jordan for this feedback, it forced me to think more about it. I was already unsure about this when I introduced it in #48040. Thanks to your feedback I think I found a solution for some things, but there are other things that are still giving me pause. I think we need some brainstorming on this, so I'd like you to bear with me and provide some mind share. BackgroundHenceforth I will use the word "safe" to mean "known certainly to be free of confidential information, PII or other details which neither telemetry nor support should receive without explicit permission". Then "unsafe" means the negative, when we're not sure (i.e. stuff is unsafe unless proven otherwise). So for context here is where we are:
tldr: Problems solved here (probably no discussion needed)
Problem 1: dynamic, foremost-unsafe payloadsWe have a bunch of calls to Both you and I agree that // Here 'payload' is turned from 'string' into 'interface{}'.
// The WrapV function inspects the type, and considers the value as unsafe
// unless it was constructed with errors.Safe().
func WrapV(err error, maybeSafeVal interface{}) Use with:
This effectively makes Then we'd change the linter to mandate This aligns the API with what we already do for logging. Problem 2 (biggest) literal constants assumed unsafeConsider all the calls to The API consider the argument unsafe. This is the elephant in the room.
Alternative solutions to problem 2Here are the solutions I have considered:
For the record my preference goes for (3). The next best solution IMHO is (1), which is where this PR (and #48040) are going. We haven't yet made the switch to change the API contract, but we need to have the linter and convert the calls first before we can start assuming the argument safe. Edit after Radu's comment below: maybe (4) is better than (1), need to investigate. Any other suggestions? |
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @dt, @irfansharif, and @tbg)
pkg/cmd/github-post/main.go, line 165 at r1 (raw file):
Previously, irfansharif (irfan sharif) wrote…
Unrelated to this PR, is it generally 'safer' to use %q over %s for byte slices? If so, is this also something we could/should use a linter for?
No there is nothing "safer" about it.
It's a question of aesthetics: if the byte slice contains whitespace or other special characters, %q ensures it remains on a single line of output.
(There's nothing semantically wrong for an error message to span multiple lines, but it's likely to confuse the human reader)
pkg/kv/kvserver/replica_command.go, line 409 at r1 (raw file):
Previously, irfansharif (irfan sharif) wrote…
Maybe even keeping the comment block as to why we're wrapping vs. not is a good idea.
Good idea, done.
pkg/testutils/lint/passes/fmtsafe/fmtsafe.go, line 99 at r1 (raw file):
Previously, irfansharif (irfan sharif) wrote…
[nit] Update comment to mention the enclosing fn name?
Done.
What if we define |
I’m more inclined towards 1) I guess — I’m not sure how 3) would work even with bazel — most of our codegen generates entire files but it doesn’t modify the files I wrote, which feels like another level of spooky and hard to reason about. I’d be more inclined to do something simple (build-wise) like say (and lint to enforce that) we only pass string literals to errors.Wrap and if you want to pass a dynamically generated string, you need use another method like Wrapf or the proposed Wrapv |
That is clever and intriguing. I need to think about it a bit more and run some experiments. It'll be alternative (4). |
Some more input here:
|
Ok so I'd like to proceed with this PR with the understanding we're going to shift to solution (1) (or perhaps (4) ) at some point soon. In this later phase, I will extend the linter to recommend using @jordanlewis is this acceptable to you? |
Yes, by no means do I intend to block this work. I'm fine merging this, thanks. |
The `fmtsafe` linter added in cockroachdb#48040 cockroachdb#48048 was actually malfunctioning because it was not stripping the vendor prefix properly. This patch fixes it. Fixing the linter uncovered a range of defects throughout the remainder of the code, some benign and some outright bugs. Examples: ``` return pgerror.Wrapf(err, "while running %s", stmt) ``` (The second argument should be the pgcode, not the error string!) ``` return errors.Errorf(`no consistency checks are defined for %s` + gen.Meta().Name) ``` (Incompatible use of `%s` and string concatenation.) ``` errors.New(fmt.Sprintf("foo %s", blah)) ``` (Should use `Newf()` instead to capture more data in telemetry.) Release note: None
Filed #49752 to track this followup work. |
bors r=irfansharif |
Build succeeded |
Found while working on #49447.
The
fmtsafe
linter added in #48040 #48048 was actuallymalfunctioning because it was not stripping the vendor prefix
properly.
This patch fixes it.
Fixing the linter uncovered a range of defects throughout the
remainder of the code, some benign and some outright bugs.
Examples:
(The second argument should be the pgcode, not the error string!)
(Incompatible use of
%s
and string concatenation.)(Should use
Newf()
instead to capture more data in telemetry.)Release note: None