Repository: uber-go/fx
Pull request #917 (2022-08-08 18:18:41)

Fix nil panic on lifecycle OnStart/OnStop
If fx lifecycle OnStart/OnStop is called with a nil context, we
panic.

Added tests that test this.

Also tagging another release with this fix.

codecov[bot]: # [Codecov](https://codecov.io/gh/uber-go/fx/pull/917?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go) Report
> Merging [#917](https://codecov.io/gh/uber-go/fx/pull/917?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go) (0792c04) into [master](https://codecov.io/gh/uber-go/fx/commit/1973f9f6aee1cc45d21b3740df86c2e87de0b213?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go) (1973f9f) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff           @@
##           master     #917   +/-   ##
=======================================
  Coverage   98.71%   98.72%           
=======================================
  Files          30       30           
  Lines        1328     1332    +4     
=======================================
+ Hits         1311     1315    +4     
  Misses         11       11           
  Partials        6        6           
```


| [Impacted Files](https://codecov.io/gh/uber-go/fx/pull/917?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go) | Coverage Δ | |
|---|---|---|
| [internal/lifecycle/lifecycle.go](https://codecov.io/gh/uber-go/fx/pull/917/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go#diff-aW50ZXJuYWwvbGlmZWN5Y2xlL2xpZmVjeWNsZS5nbw==) | `100.00% <100.00%> (ø)` | |

:mega: Codecov can now indicate which changes are the most critical in Pull Requests. [Learn more](https://about.codecov.io/product/feature/runtime-insights/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=uber-go)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b6d7b7..e1f534d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## [1.18.1] = 2022-08-08
+### Fixed
+- Fix a nil panic when `nil` is passed to `OnStart` and `OnStop` lifecycle methods.
+
 ## [1.18.0] - 2022-08-05
 ### Added
 - Soft value groups that lets you specify value groups as best-effort dependencies.
diff --git a/internal/lifecycle/lifecycle.go b/internal/lifecycle/lifecycle.go
index af458fa..7c6d102 100644
--- a/internal/lifecycle/lifecycle.go
+++ b/internal/lifecycle/lifecycle.go
@@ -22,6 +22,7 @@ package lifecycle
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"io"
 	"strings"
@@ -72,6 +73,10 @@ func (l *Lifecycle) Append(hook Hook) {
 // Start runs all OnStart hooks, returning immediately if it encounters an
 // error.
 func (l *Lifecycle) Start(ctx context.Context) error {
+	if ctx == nil {
+		return errors.New("called OnStart with nil context")
+	}
+
 	l.mu.Lock()
 	l.startRecords = make(HookRecords, 0, len(l.hooks))
 	l.mu.Unlock()
@@ -129,6 +134,10 @@ func (l *Lifecycle) runStartHook(ctx context.Context, hook Hook) (runtime time.D
 // Stop runs any OnStop hooks whose OnStart counterpart succeeded. OnStop
 // hooks run in reverse order.
 func (l *Lifecycle) Stop(ctx context.Context) error {
+	if ctx == nil {
+		return errors.New("called OnStop with nil context")
+	}
+
 	l.mu.Lock()
 	l.stopRecords = make(HookRecords, 0, l.numStarted)
 	l.mu.Unlock()
diff --git a/version.go b/version.go
index 32f7d0a..e0e113b 100644
--- a/version.go
+++ b/version.go
@@ -21,4 +21,4 @@
 package fx
 
 // Version is exported for runtime compatibility checks.
-const Version = "1.18.0"
+const Version = "1.18.1"


Test patch:
diff --git a/internal/lifecycle/lifecycle_test.go b/internal/lifecycle/lifecycle_test.go
index 4fe75e2..2fdc15f 100644
--- a/internal/lifecycle/lifecycle_test.go
+++ b/internal/lifecycle/lifecycle_test.go
@@ -291,6 +291,32 @@ func TestLifecycleStop(t *testing.T) {
 		cancel()
 		require.Error(t, l.Stop(ctx))
 	})
+
+	t.Run("nil ctx", func(t *testing.T) {
+		t.Parallel()
+
+		l := New(testLogger(t), fxclock.System)
+		l.Append(Hook{
+			OnStart: func(context.Context) error {
+				assert.Fail(t, "this hook should not run")
+				return nil
+			},
+			OnStop: func(context.Context) error {
+				assert.Fail(t, "this hook should not run")
+				return nil
+			},
+		})
+		//lint:ignore SA1012 this test specifically tests for the lint failure
+		err := l.Start(nil)
+		require.Error(t, err)
+		assert.Contains(t, err.Error(), "called OnStart with nil context")
+
+		//lint:ignore SA1012 this test specifically tests for the lint failure
+		err = l.Stop(nil)
+		require.Error(t, err)
+		assert.Contains(t, err.Error(), "called OnStop with nil context")
+
+	})
 }
 
 func TestHookRecordsFormat(t *testing.T) {