44 "bytes"
55 "encoding/json"
66 "fmt"
7+ "math"
78 "sort"
89 "strconv"
910)
@@ -53,7 +54,12 @@ func UnknownJSONFieldsFromMap(fields map[string]json.RawMessage) UnknownJSONFiel
5354 }
5455 buf .Write (keyBody )
5556 buf .WriteByte (':' )
56- buf .Write (CloneRawJSON (fields [key ]))
57+ rawValue := CloneRawJSON (fields [key ])
58+ if len (rawValue ) == 0 {
59+ buf .WriteString ("null" )
60+ continue
61+ }
62+ buf .Write (rawValue )
5763 }
5864 buf .WriteByte ('}' )
5965 return UnknownJSONFields {raw : buf .Bytes ()}
@@ -133,7 +139,11 @@ func mergeUnknownJSONObject(baseBody, extraBody []byte) ([]byte, error) {
133139 return CloneRawJSON (extraBody ), nil
134140 }
135141
136- merged := make ([]byte , 0 , len (baseBody )+ len (extraBody )- 1 )
142+ totalCap , err := mergedJSONObjectCap (len (baseBody ), len (extraBody ))
143+ if err != nil {
144+ return nil , err
145+ }
146+ merged := make ([]byte , 0 , totalCap )
137147 merged = append (merged , baseBody [:len (baseBody )- 1 ]... )
138148 if ! bytes .Equal (extraBody , []byte ("{}" )) {
139149 merged = append (merged , ',' )
@@ -142,6 +152,16 @@ func mergeUnknownJSONObject(baseBody, extraBody []byte) ([]byte, error) {
142152 return merged , nil
143153}
144154
155+ func mergedJSONObjectCap (baseLen , extraLen int ) (int , error ) {
156+ if extraLen <= 0 {
157+ return 0 , fmt .Errorf ("unknown JSON fields are empty" )
158+ }
159+ if baseLen > math .MaxInt - (extraLen - 1 ) {
160+ return 0 , fmt .Errorf ("combined JSON object too large" )
161+ }
162+ return baseLen + extraLen - 1 , nil
163+ }
164+
145165func readJSONObjectKey (dec * json.Decoder ) (string , bool ) {
146166 keyToken , err := dec .Token ()
147167 if err != nil {
@@ -205,8 +225,22 @@ func extractUnknownJSONFieldsObjectByScan(data []byte, knownFields ...string) (U
205225 }
206226
207227 i = skipJSONWhitespace (data , valueEnd )
208- if i < len (data ) && data [i ] == ',' {
228+ if i >= len (data ) {
229+ return UnknownJSONFields {}, fmt .Errorf ("unterminated JSON object" )
230+ }
231+ switch data [i ] {
232+ case ',' :
209233 i = skipJSONWhitespace (data , i + 1 )
234+ if i >= len (data ) {
235+ return UnknownJSONFields {}, fmt .Errorf ("unterminated JSON object" )
236+ }
237+ if data [i ] == '}' {
238+ return UnknownJSONFields {}, fmt .Errorf ("unexpected trailing comma in JSON object" )
239+ }
240+ case '}' :
241+ // The next loop iteration will terminate cleanly on the closing brace.
242+ default :
243+ return UnknownJSONFields {}, fmt .Errorf ("expected ',' or '}' after object value" )
210244 }
211245 }
212246
@@ -233,12 +267,19 @@ func scanJSONValue(data []byte, start int) (int, error) {
233267 for i < len (data ) {
234268 switch data [i ] {
235269 case ',' , '}' , ']' :
236- return i , nil
270+ goto validateLiteral
237271 case ' ' , '\n' , '\r' , '\t' :
238- return i , nil
272+ goto validateLiteral
239273 }
240274 i ++
241275 }
276+ validateLiteral:
277+ if i == start {
278+ return 0 , fmt .Errorf ("expected JSON literal" )
279+ }
280+ if err := validateJSONLiteral (data [start :i ]); err != nil {
281+ return 0 , err
282+ }
242283 return i , nil
243284 }
244285}
@@ -267,8 +308,22 @@ func scanJSONObject(data []byte, start int) (int, error) {
267308 return 0 , err
268309 }
269310 i = skipJSONWhitespace (data , valueEnd )
270- if i < len (data ) && data [i ] == ',' {
271- i ++
311+ if i >= len (data ) {
312+ return 0 , fmt .Errorf ("unterminated JSON object" )
313+ }
314+ switch data [i ] {
315+ case ',' :
316+ i = skipJSONWhitespace (data , i + 1 )
317+ if i >= len (data ) {
318+ return 0 , fmt .Errorf ("unterminated JSON object" )
319+ }
320+ if data [i ] == '}' {
321+ return 0 , fmt .Errorf ("unexpected trailing comma in JSON object" )
322+ }
323+ case '}' :
324+ return i + 1 , nil
325+ default :
326+ return 0 , fmt .Errorf ("expected ',' or '}' after object value" )
272327 }
273328 }
274329 return 0 , fmt .Errorf ("unterminated JSON object" )
@@ -289,13 +344,40 @@ func scanJSONArray(data []byte, start int) (int, error) {
289344 return 0 , err
290345 }
291346 i = skipJSONWhitespace (data , valueEnd )
292- if i < len (data ) && data [i ] == ',' {
293- i ++
347+ if i >= len (data ) {
348+ return 0 , fmt .Errorf ("unterminated JSON array" )
349+ }
350+ switch data [i ] {
351+ case ',' :
352+ i = skipJSONWhitespace (data , i + 1 )
353+ if i >= len (data ) {
354+ return 0 , fmt .Errorf ("unterminated JSON array" )
355+ }
356+ if data [i ] == ']' {
357+ return 0 , fmt .Errorf ("unexpected trailing comma in JSON array" )
358+ }
359+ case ']' :
360+ return i + 1 , nil
361+ default :
362+ return 0 , fmt .Errorf ("expected ',' or ']' after array element" )
294363 }
295364 }
296365 return 0 , fmt .Errorf ("unterminated JSON array" )
297366}
298367
368+ func validateJSONLiteral (raw []byte ) error {
369+ var value any
370+ if err := json .Unmarshal (raw , & value ); err != nil {
371+ return fmt .Errorf ("invalid JSON literal: %w" , err )
372+ }
373+ switch value .(type ) {
374+ case nil , bool , float64 :
375+ return nil
376+ default :
377+ return fmt .Errorf ("invalid JSON literal" )
378+ }
379+ }
380+
299381func scanJSONString (data []byte , start int ) (int , error ) {
300382 if start >= len (data ) || data [start ] != '"' {
301383 return 0 , fmt .Errorf ("expected JSON string" )
0 commit comments