Skip to content

Conversation

@Yoone
Copy link

@Yoone Yoone commented Jul 30, 2025

Summary

  • ParseBytes(json []byte) Result now uses the bytesString helper function (unsafe cast) over string(...) conversion to avoid copying the byte slice.
  • A new result.Bytes() helper was added to access result.Raw as []byte without copying data.

Motivation

This change aims at allowing the use of []byte over string as input when using gjson without having to copy data or perform extra memory allocations, since one of the selling points of this library is its ability to parse and process JSON with no copy / zero allocations.

@mirecl
Copy link

mirecl commented Aug 28, 2025

@tidwall , what do you think about this change?

@tidwall
Copy link
Owner

tidwall commented Aug 28, 2025

This PR breaks the rules of immutability for strings in Go.

Using the change in this PR, run this code:

json := []byte(`{ "first": "Janet", "last": "Prichard" }`)
first := gjson.ParseBytes(json).Get("first").String()
println(first)
copy(json[11:18], `"Carol"`)
println(first)
// Output:
// Janet
// Carol

It should not be possible to change the backed memory of a string, but in the example above the string first was changed from "Janet" to "Carol".

This is because the json byte slice was unsafely cast as a string in ParseBytes and returned as a string field in the Result type. Then further calls to Result expects that string to be immutable.

A safer workaround would be to cast before parse, then immediately copy the result (which contains a mutable string), back into an immutable string.

json := []byte(`{ "first": "Janet", "last": "Prichard" }`)
jsonStr := *(*string)(unsafe.Pointer(&json))  // cast []bytes to string, zero-copy
first := Parse(jsonStr).Get("first").String() // use Parse instead of ParseBytes
first = string([]byte(first))                 // copy result back into string
println(first)
copy(json[11:18], `"Carol"`)
println(first)
// Output:
// Janet
// Janet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants