Skip to content

Commit b3613ec

Browse files
committed
chore: prevent nil derefs in non-critical paths
1 parent 5981abd commit b3613ec

File tree

1 file changed

+17
-5
lines changed

1 file changed

+17
-5
lines changed

cli/cliui/agent.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,12 @@ func Agent(ctx context.Context, writer io.Writer, agentID uuid.UUID, opts AgentO
200200

201201
switch agent.LifecycleState {
202202
case codersdk.WorkspaceAgentLifecycleReady:
203-
sw.Complete(stage, agent.ReadyAt.Sub(*agent.StartedAt))
203+
sw.Complete(stage, safeDuration(agent.ReadyAt, agent.StartedAt))
204204
case codersdk.WorkspaceAgentLifecycleStartTimeout:
205205
sw.Fail(stage, 0)
206206
sw.Log(time.Time{}, codersdk.LogLevelWarn, "Warning: A startup script timed out and your workspace may be incomplete.")
207207
case codersdk.WorkspaceAgentLifecycleStartError:
208-
sw.Fail(stage, agent.ReadyAt.Sub(*agent.StartedAt))
208+
sw.Fail(stage, safeDuration(agent.ReadyAt, agent.StartedAt))
209209
// Use zero time (omitted) to separate these from the startup logs.
210210
sw.Log(time.Time{}, codersdk.LogLevelWarn, "Warning: A startup script exited with an error and your workspace may be incomplete.")
211211
sw.Log(time.Time{}, codersdk.LogLevelWarn, troubleshootingMessage(agent, "https://coder.com/docs/v2/latest/templates#startup-script-exited-with-an-error"))
@@ -221,7 +221,7 @@ func Agent(ctx context.Context, writer io.Writer, agentID uuid.UUID, opts AgentO
221221
case agent.LifecycleState.ShuttingDown():
222222
// We no longer know if the startup script failed or not,
223223
// but we need to tell the user something.
224-
sw.Complete(stage, agent.ReadyAt.Sub(*agent.StartedAt))
224+
sw.Complete(stage, safeDuration(agent.ReadyAt, agent.StartedAt))
225225
return errAgentShuttingDown
226226
}
227227
}
@@ -238,13 +238,12 @@ func Agent(ctx context.Context, writer io.Writer, agentID uuid.UUID, opts AgentO
238238
sw.Log(time.Now(), codersdk.LogLevelWarn, "Wait for it to reconnect or restart your workspace.")
239239
sw.Log(time.Now(), codersdk.LogLevelWarn, troubleshootingMessage(agent, "https://coder.com/docs/v2/latest/templates#agent-connection-issues"))
240240

241-
disconnectedAt := *agent.DisconnectedAt
242241
for agent.Status == codersdk.WorkspaceAgentDisconnected {
243242
if agent, err = fetch(); err != nil {
244243
return xerrors.Errorf("fetch: %w", err)
245244
}
246245
}
247-
sw.Complete(stage, agent.LastConnectedAt.Sub(disconnectedAt))
246+
sw.Complete(stage, safeDuration(agent.LastConnectedAt, agent.DisconnectedAt))
248247
}
249248
}
250249
}
@@ -257,6 +256,19 @@ func troubleshootingMessage(agent codersdk.WorkspaceAgent, url string) string {
257256
return m
258257
}
259258

259+
// safeDuration returns a-b. If a or b is nil, it returns 0.
260+
// This is because we often dereference a time pointer, which can
261+
// cause a panic. These dereferences are used to calculate durations,
262+
// which are not critical, and therefor should not break things
263+
// when it fails.
264+
// A panic has been observed in a test.
265+
func safeDuration(a, b *time.Time) time.Duration {
266+
if a == nil || b == nil {
267+
return 0
268+
}
269+
return a.Sub(*b)
270+
}
271+
260272
type closeFunc func() error
261273

262274
func (c closeFunc) Close() error {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy