diff --git a/changelog/pending/20221028--sdk-go-yaml--prevent-race-on-resource-output.yaml b/changelog/pending/20221028--sdk-go-yaml--prevent-race-on-resource-output.yaml new file mode 100644 index 000000000000..855e425d88ee --- /dev/null +++ b/changelog/pending/20221028--sdk-go-yaml--prevent-race-on-resource-output.yaml @@ -0,0 +1,4 @@ +changes: +- type: fix + scope: sdk/go,yaml + description: Prevent race on resource output diff --git a/sdk/go/pulumi/context.go b/sdk/go/pulumi/context.go index d3c0515724c8..0ec0534d9ab8 100644 --- a/sdk/go/pulumi/context.go +++ b/sdk/go/pulumi/context.go @@ -1178,8 +1178,6 @@ func (state *resourceState) resolve(ctx *Context, err error, inputs *resourceInp return } - state.rawOutputs.getState().resolve(outprops, true, false, nil) - outprops["urn"] = resource.NewStringProperty(urn) if id != "" || !dryrun { outprops["id"] = resource.NewStringProperty(id) @@ -1204,6 +1202,10 @@ func (state *resourceState) resolve(ctx *Context, err error, inputs *resourceInp } } + // We need to wait until after we finish mutating outprops to resolve. Resolving + // unlocks multithreaded access to the resolved value, making mutation a data race. + state.rawOutputs.getState().resolve(outprops, true, false, nil) + for k, output := range state.outputs { // If this is an unknown or missing value during a dry run, do nothing. v, ok := outprops[resource.PropertyKey(k)] diff --git a/sdk/go/pulumi/types.go b/sdk/go/pulumi/types.go index 19b4157ec35f..bf6187e1f712 100644 --- a/sdk/go/pulumi/types.go +++ b/sdk/go/pulumi/types.go @@ -133,6 +133,8 @@ func (o *OutputState) dependencies() []Resource { if o == nil { return nil } + o.cond.L.Lock() + defer o.cond.L.Unlock() return o.deps } @@ -520,7 +522,10 @@ func (o *OutputState) ApplyTWithContext(ctx context.Context, applier interface{} // IsSecret returns a bool representing the secretness of the Output func IsSecret(o Output) bool { - return o.getState().secret + s := o.getState() + s.cond.L.Lock() + defer s.cond.L.Unlock() + return s.secret } // Unsecret will unwrap a secret output as a new output with a resolved value and no secretness