]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json/v2: restrict presence of default options
authorJoe Tsai <joetsai@digital-static.net>
Sat, 11 Oct 2025 18:37:58 +0000 (11:37 -0700)
committerJoseph Tsai <joetsai@digital-static.net>
Tue, 14 Oct 2025 00:01:45 +0000 (17:01 -0700)
Originally, DefaultOptionsV1 and DefaultOptionsV2 represented
the full set of all options with specific ones set to true or false.

However, there are certain options such as WithIndent or WithMarshalers
that are neither v1 or v2 specific.
At some point we removed whitespace related options from the set:
https://github.com/go-json-experiment/json/pull/26

This avoids DefaultOptionsV1 or DefaultOptionsV2 from affecting
any previously set whitespace. However, why are whitespace options
special and thus excluded from the set? What about Marshalers?

As a more principaled way to address this, we restrict
DefaultOptionsV1 and DefaultOptionsV2 to only be the options
where the default setting changes between v1 and v2.
All other options are unpopulated.

This avoids a panic with GetOption(DefaultOptionsV2, WithMarshalers)
since DefaultOptionsV2 previously had the presence bit for
Marshalers set to true, but had no actual value.
Now, the presence bit is set to false, so the value is not consulted.

Fixes #75149

Change-Id: I30b45abd35404578b4135cc3bad1a1a2993cb0cf
Reviewed-on: https://go-review.googlesource.com/c/go/+/710878
Reviewed-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
src/encoding/json/internal/jsonopts/options.go
src/encoding/json/internal/jsonopts/options_test.go
src/encoding/json/v2/options.go
src/encoding/json/v2_options.go

index e4c3f47d36adc8f686c79dccef897d05d5999465..39da81b34549ec96f6e2100859a906bcf382693b 100644 (file)
@@ -48,16 +48,16 @@ type ArshalValues struct {
 // DefaultOptionsV2 is the set of all options that define default v2 behavior.
 var DefaultOptionsV2 = Struct{
        Flags: jsonflags.Flags{
-               Presence: uint64(jsonflags.AllFlags & ^jsonflags.WhitespaceFlags),
-               Values:   uint64(0),
+               Presence: uint64(jsonflags.DefaultV1Flags),
+               Values:   uint64(0), // all flags in DefaultV1Flags are false
        },
 }
 
 // DefaultOptionsV1 is the set of all options that define default v1 behavior.
 var DefaultOptionsV1 = Struct{
        Flags: jsonflags.Flags{
-               Presence: uint64(jsonflags.AllFlags & ^jsonflags.WhitespaceFlags),
-               Values:   uint64(jsonflags.DefaultV1Flags),
+               Presence: uint64(jsonflags.DefaultV1Flags),
+               Values:   uint64(jsonflags.DefaultV1Flags), // all flags in DefaultV1Flags are true
        },
 }
 
index ebfaf05c833e0574cd8eb60a035f7c505a29a7c9..caa686e4f0d579c9c8f70b6636bbb5cb4fc4426f 100644 (file)
@@ -200,6 +200,9 @@ func TestGet(t *testing.T) {
        if v, ok := json.GetOption(opts, json.WithUnmarshalers); v != nil || ok {
                t.Errorf(`GetOption(..., WithUnmarshalers) = (%v, %v), want (nil, false)`, v, ok)
        }
+       if v, ok := json.GetOption(json.DefaultOptionsV2(), json.WithMarshalers); v != nil || ok {
+               t.Errorf(`GetOption(..., WithMarshalers) = (%v, %v), want (nil, false)`, v, ok)
+       }
 }
 
 var sink struct {
index 0942d2d30784f96a738967ccebeb53ff1cc2f521..9685f20f9f805f220142366e8f72467c50f7bca5 100644 (file)
@@ -97,9 +97,8 @@ func GetOption[T any](opts Options, setter func(T) Options) (T, bool) {
 }
 
 // DefaultOptionsV2 is the full set of all options that define v2 semantics.
-// It is equivalent to all options under [Options], [encoding/json.Options],
-// and [encoding/json/jsontext.Options] being set to false or the zero value,
-// except for the options related to whitespace formatting.
+// It is equivalent to the set of options in [encoding/json.DefaultOptionsV1]
+// all being set to false. All other options are not present.
 func DefaultOptionsV2() Options {
        return &jsonopts.DefaultOptionsV2
 }
index 819fe59f412c683be5d6d411e306e8695465f57e..2bdec86fdeab5b16ef3818ae2fab81c7b4957197 100644 (file)
@@ -227,9 +227,7 @@ type Options = jsonopts.Options
 //   - [jsontext.EscapeForJS]
 //   - [jsontext.PreserveRawStrings]
 //
-// All other boolean options are set to false.
-// All non-boolean options are set to the zero value,
-// except for [jsontext.WithIndent], which defaults to "\t".
+// All other options are not present.
 //
 // The [Marshal] and [Unmarshal] functions in this package are
 // semantically identical to calling the v2 equivalents with this option: