Skip to content

Commit

Permalink
Fix nil panic on lifecycle OnStart/OnStop (#917)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sywhang committed Aug 8, 2022
1 parent 1973f9f commit b220b95
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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.
Expand Down
9 changes: 9 additions & 0 deletions internal/lifecycle/lifecycle.go
Expand Up @@ -22,6 +22,7 @@ package lifecycle

import (
"context"
"errors"
"fmt"
"io"
"strings"
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down
26 changes: 26 additions & 0 deletions internal/lifecycle/lifecycle_test.go
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion version.go
Expand Up @@ -21,4 +21,4 @@
package fx

// Version is exported for runtime compatibility checks.
const Version = "1.18.0"
const Version = "1.18.1"

0 comments on commit b220b95

Please sign in to comment.