-
Notifications
You must be signed in to change notification settings - Fork 9.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 runtime error: comparing uncomparable type #18893
base: main
Are you sure you want to change the base?
Conversation
Hi @ktalg. Thanks for your PR. I'm waiting for a etcd-io member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: ktalg The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Signed-off-by: KT <416432526@qq.com>
289e041
to
c18c353
Compare
Could you kindly review this? @serathius |
} | ||
|
||
ctx, cancel := context.WithCancel(context.Background()) | ||
rc, kerr := lapi.KeepAlive(uncomparableCtx{Context: ctx}, resp.ID) |
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.
The easiest workaround is to pass in a pointer &uncomparableCtx{Context: ctx}
.
Thanks for raising this PR. The root cause is that the etcd client SDK tries to compare two context intances, which might not be comparable. Line 351 in 4186283
Is this your a real use case in your production code? The easiest workaround is to pass in a pointer of your customized context intance as mentioned in #18893 (comment). We can attach an unique ID for each context passed to KeepAlive something like below, and compare the IDs when we need to identify the context,
We also need to review the source code to check if there are other places which compare the context as well. |
Or we can add a function something like below,
I am not sure whether there is an existing linter which can detect direct context comparison like below case. Probably we can add a such linter and integrate into golangci-lint if possible? @ivanvc @mmorel-35 @ldez Line 351 in 4186283
|
Hello,
There is no linter on this specific case.
The contexts are just structs so they are technically comparable. https://go.dev/play/p/dyfw2rkHfTi I understand your current issue, I need to investigate to kown if there are "valid" use cases behind this kind of comparison. |
Thanks for the confirmation.
Not really. Firstly the applications (including etcd) interact with with interface Secondly, struct types are comparable if all their field types are comparable. In other words, if any field isn't comparable, then the struct isn't comparable. Usually the default implementations of contexts included golang std lib are comparable. But users' customized implementation might not be comparable. |
I'm aware of the interface I still need to investigate the feasibility and the relevance of a linter on this topic. |
It might not be reasonable to create a linter for this. Comparing structs or interfaces using an comparison operators (i.e. The problem in this case is that users may pass in a customized implementation of The simplest solution is as I mentioned above in #18893 (comment) and #18893 (comment). But it's the first time we see such issue, and most likely it isn't a real production use case. So it's low priority to me. |
FYI, I created a quick linter about context comparison to evaluate the relevance. I analyzed several large projects, and I found no context comparison. But I found 2 comparisons inside Go itself: And as you said, struct comparison is not an anti-pattern. For now, I think it's not worth adding a linter for this. |
Thanks @ldez @ktalg Could you please confirm if this is a real use case from your production environment or a hypothetical scenario? The workaround is to pass in a pointer as mentioned in #18893 (comment) |
Thank you very much for reviewing this PR and providing detailed feedback!
I encountered this issue while working on production-grade project code. The problem arose not from creating a new Context implementation but from passing a struct embedding a Context into the KeepAlive function, as illustrated in the test case I added. This situation highlights two key points:
I didn't anticipate that KeepAlive would internally use == to compare the type I passed in. My perspective is that robust code should rely solely on the declared contract of an interface, not on implicit assumptions. In this case, it seems to "assume" that the interface implementation is always comparable, which isn't guaranteed. I believe this change improves the robustness of the code, ensuring it adheres to these principles. |
@@ -348,7 +353,7 @@ func (l *lessor) keepAliveCtxCloser(ctx context.Context, id LeaseID, donec <-cha | |||
|
|||
// close channel and remove context if still associated with keep alive | |||
for i, c := range ka.ctxs { | |||
if c == ctx { | |||
if val := c.Value(ctx); val != 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.
I am confused about this change.
Have you considered #18893 (comment) and also #18893 (comment)?
Fixes a runtime panic that occurs when KeepAlive is called with a Context implemented by an uncomparable type, which is later canceled. The panic message is:
To reproduce the issue, the existing test has been updated to include a custom uncomparable Context implementation. Previously, this test consistently caused a panic due to the uncomparable Context type. The updated implementation modifies keepAliveCtxCloser to properly handle such cases.