Skip to content
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

context: Cause does not return Err for a custom context #62582

Closed
ianlancetaylor opened this issue Sep 11, 2023 · 4 comments
Closed

context: Cause does not return Err for a custom context #62582

ianlancetaylor opened this issue Sep 11, 2023 · 4 comments
Labels
NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@ianlancetaylor
Copy link
Contributor

The documentation for context.Cause says that if a context was canceled other than via a call to CancelCauseFunc, then "Cause(c) returns the same value as c.Err()". However, that is not true today for a custom context. CC @Sajmani

Here is a test:

// customCauseContext is a custom Context used to test context.Cause.
type customCauseContext struct {
	mu   sync.Mutex
	done chan struct{}
	err  error
}

func (ccc *customCauseContext) Deadline() (deadline time.Time, ok bool) {
	return
}

func (ccc *customCauseContext) Done() <-chan struct{} {
	ccc.mu.Lock()
	defer ccc.mu.Unlock()
	return ccc.done
}

func (ccc *customCauseContext) Err() error {
	ccc.mu.Lock()
	defer ccc.mu.Unlock()
	return ccc.err
}

func (ccc *customCauseContext) Value(key any) any {
	return nil
}

func (ccc *customCauseContext) cancel() {
	ccc.mu.Lock()
	defer ccc.mu.Unlock()
	ccc.err = context.Canceled
	close(ccc.done)
}

func TestCustomContextCause(t *testing.T) {
	ccc := customCauseContext{
		done: make(chan struct{}),
	}
	ccc.cancel()
	if got := ccc.Err(); got != context.Canceled {
		t.Errorf("ccc.Err() = %v, want %v", got, context.Canceled)
	}
	if got := context.Cause(&ccc); got != context.Canceled {
		t.Errorf("Cause(ccc) = %v, want %v", got, context.Canceled)
	}
}

This fails with

--- FAIL: TestCustomContextCause (0.00s)
    foo_test.go:53: Cause(ccc) = <nil>, want context canceled
@ianlancetaylor ianlancetaylor added the NeedsFix The path to resolution is known, but the work has not been done. label Sep 11, 2023
@ianlancetaylor ianlancetaylor added this to the Go1.22 milestone Sep 11, 2023
@gopherbot
Copy link

Change https://go.dev/cl/527277 mentions this issue: context: support non-standard Context in Cause

@nightlyone
Copy link
Contributor

Should that be backported to Go 1.20 where this behaviour has been introduced or is there a possible workaround for that issue that I am missing to see?

@ianlancetaylor
Copy link
Contributor Author

It's kind of an edge case: code that has a custom Context type and calls context.Cause on that type. There isn't a lot of reason to call context.Cause on a Context that wasn't created by context.WithCancelCause, and by definition that does not return a custom context. So this issue doesn't seem to meet the requirements outlined at https://go.dev/wiki/MinorReleases. Happy to hear counter-arguments.

@colega
Copy link
Contributor

colega commented Dec 20, 2023

It's kind of an edge case: code that has a custom Context type and calls context.Cause on that type.

I don't think it's such an edge case. I hit this while working on a library that does some intensive work and regularly checks for the context cancellation with if err := context.Cause(ctx); err != nil {.

The library doesn't know the type of the context that it has been provided, so in the case of a custom context it won't detect its cancellation and will keep executing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

4 participants