1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2026-06-03 18:35:08 +02:00

sdk/resource: Fix data race with emptyAttributes (#4409)

* Fix ASAN bug with emptyAttributes.

If mutliple instantiations of a Resources struct are happening
in parallel, they can end up modifying the same underlying resource.

* Capture literal

* add test

* remove unwanted change

* Update sdk/resource/resource_test.go

Co-authored-by: Robert Pająk <pellared@hotmail.com>

* Update sdk/resource/resource_test.go

Co-authored-by: Robert Pająk <pellared@hotmail.com>

* Update sdk/resource/resource_test.go

Co-authored-by: Robert Pająk <pellared@hotmail.com>

* Update sdk/resource/resource_test.go

Co-authored-by: Robert Pająk <pellared@hotmail.com>

* Add changelog.

* Update CHANGELOG.md

Co-authored-by: Robert Pająk <pellared@hotmail.com>

---------

Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
Jared Jenkins
2023-08-07 12:22:48 -05:00
committed by GitHub
parent e1e6b96647
commit b221025a4c
3 changed files with 32 additions and 5 deletions
+4 -5
View File
@@ -36,7 +36,6 @@ type Resource struct {
}
var (
emptyResource Resource
defaultResource *Resource
defaultResourceOnce sync.Once
)
@@ -70,7 +69,7 @@ func NewWithAttributes(schemaURL string, attrs ...attribute.KeyValue) *Resource
// of the attrs is known use NewWithAttributes instead.
func NewSchemaless(attrs ...attribute.KeyValue) *Resource {
if len(attrs) == 0 {
return &emptyResource
return &Resource{}
}
// Ensure attributes comply with the specification:
@@ -81,7 +80,7 @@ func NewSchemaless(attrs ...attribute.KeyValue) *Resource {
// If attrs only contains invalid entries do not allocate a new resource.
if s.Len() == 0 {
return &emptyResource
return &Resource{}
}
return &Resource{attrs: s} //nolint
@@ -195,7 +194,7 @@ func Merge(a, b *Resource) (*Resource, error) {
// Empty returns an instance of Resource with no attributes. It is
// equivalent to a `nil` Resource.
func Empty() *Resource {
return &emptyResource
return &Resource{}
}
// Default returns an instance of Resource with a default
@@ -214,7 +213,7 @@ func Default() *Resource {
}
// If Detect did not return a valid resource, fall back to emptyResource.
if defaultResource == nil {
defaultResource = &emptyResource
defaultResource = &Resource{}
}
})
return defaultResource
+27
View File
@@ -21,6 +21,7 @@ import (
"fmt"
"os"
"strings"
"sync"
"testing"
"github.com/google/go-cmp/cmp"
@@ -769,3 +770,29 @@ func TestWithContainer(t *testing.T) {
string(semconv.ContainerIDKey): fakeContainerID,
}, toMap(res))
}
func TestResourceConcurrentSafe(t *testing.T) {
// Creating Resources should also be free of any data races,
// because Resources are immutable.
var wg sync.WaitGroup
for i := 0; i < 2; i++ {
wg.Add(1)
go func() {
defer wg.Done()
d := &fakeDetector{}
_, err := resource.Detect(context.Background(), d)
assert.NoError(t, err)
}()
}
wg.Wait()
}
type fakeDetector struct{}
func (f fakeDetector) Detect(_ context.Context) (*resource.Resource, error) {
// A bit pedantic, but resource.NewWithAttributes returns an empty Resource when
// no attributes specified. We want to make sure that this is concurrent-safe.
return resource.NewWithAttributes("https://opentelemetry.io/schemas/1.3.0"), nil
}
var _ resource.Detector = &fakeDetector{}