Zero attribute value length limit preserves a single invalid UTF-8 byte

#9053 · open · 0 comments

View on GitHub ↗

pellared

### Description With an attribute value length limit of `0`, a string containing exactly one malformed UTF-8 byte is retained instead of truncated to an empty string. The shared truncation helper is used by both the trace and log SDKs. A zero limit is available through `sdk/trace.WithRawSpanLimits`, the trace environment variable, and `sdk/log.WithAttributeValueLengthLimit`. ### Environment - OS / architecture: independent - Go version: 1.25+ - opentelemetry-go versions: `go.opentelemetry.io/otel/[email protected]` and `go.opentelemetry.io/otel/sdk/[email protected]`; the logic is also present on `main` ### Steps to reproduce Add this test in either generated `attrnorm` package (`sdk/internal/attrnorm` or `sdk/log/internal/attrnorm`): ```go func TestTruncateZeroSingleInvalidByte(t *testing.T) { if got := truncate(0, "\x80"); got != "" { t.Fatalf("truncate(0, invalid byte) = %q, want empty string", got) } } ``` Actual result: `truncate(0, "\x80")` returns `"\x80"`. In the [shared template](https://github.com/open-telemetry/opentelemetry-go/blob/main/internal/shared/attrnorm/truncate.go.tmpl#L362-L375), the invalid-byte branch calls `b.Grow(len(s) - 1)`. For a one-byte input this is `b.Grow(0)`, and writing the empty prefix does not allocate either. The subsequent `b.Cap() == 0` check therefore mistakes this path for one with no invalid input and returns the original byte. ### Expected behavior A zero attribute value length limit should yield `""` for every string value, including malformed UTF-8. The [attribute-limits specification](https://opentelemetry.io/docs/specs/otel/common/#attribute-limits) requires a truncated string to have a length no greater than the configured limit. Please add the regression case to `internal/shared/attrnorm/truncate_test.go.tmpl` so both generated test copies cover it. The truncation logic should track whether invalid input was seen independently of the builder's capacity, or handle the zero limit before scanning. ### Additional affected path [`trace/auto.go`](https://github.com/open-telemetry/opentelemetry-go/blob/main/trace/auto.go) has an independent copy of the same `truncate` implementation in the `go.opentelemetry.io/otel/trace` module (present since `trace/v1.35.0`). For `truncate(0, "\x80")`, it also calls `Grow(0)` and then treats `b.Cap() == 0` as proof that no invalid byte was seen, returning the original byte. Its `convAttrValue` path processes auto-instrumented span, event, and link attributes. Please fix this copy and add a regression test in `trace/auto_test.go` too; updating the shared template alone will not change it.

Comments