Skip to content

Fix null dereference in JSON printer for unions without type field - #9308

Open
xhon-pelushi wants to merge 1 commit into
google:masterfrom
xhon-pelushi:fix-9033
Open

xhon-pelushi wants to merge 1 commit into
google:masterfrom
xhon-pelushi:fix-9033

Conversation

@xhon-pelushi

Copy link
Copy Markdown

Fixes #9033

When JsonPrinter::PrintOffset() (src/idl_gen_text.cpp) prints a union, it reads the discriminator through prev_val, a pointer that GenStruct() sets to the field printed just before the union. Corrupt buffers that have the union value but not its _type field broke this in two ways:

  1. Null. If no earlier field was present, prev_val is nullptr. The only guard was FLATBUFFERS_ASSERT(prev_val), which release builds compile out, so *prev_val segfaults. This is the crash in the issue: flatc --json --raw-binary on the 40-byte file exits with SIGSEGV on master.
  2. Stale. GenStruct() only updated prev_val for fields that were present. If the _type field is absent but an earlier field was present, prev_val still points at that earlier field, and its byte is silently read as the union type. For example, with table Root { a: ubyte; u: MyUnion; }, {a: 1, u_type: Inner, u: {x: 42}} and the u_type vtable slot zeroed, master prints { a: 1, u: { x: 42 } } with no error, using a as the type.

The fix:

  • In PrintOffset(), the assert is replaced with if (!prev_val) return "union type field not present";, which reports the problem through the existing error path (GenText() / GenTextFromTable() / GenTextFile() already return const char* errors).
  • In GenStruct(), prev_val is reset to nullptr when a field is absent, so a union only ever reads its own _type field.

Both parts are needed. With only the null check, the stale case in the new test still fails.

The new test is JsonUnionMissingTypeTest in tests/json_test.cpp. It builds a buffer from JSON, zeroes one vtable slot, and checks GenText(): the unmodified buffer still prints, and errors are returned when u_type is missing (with and without an earlier present field) and when v_type is missing for a vector of unions.

Testing (Release build, -DNDEBUG):

  • flattests: all tests pass with this change.
  • Master with only the new test applied: flattests segfaults inside JsonUnionMissingTypeTest → GenText → PrintOffset.
  • Master with only the null check plus the new test: the stale case fails (json_test.cpp:250).
  • The issue's flatc repro now prints Unable to generate text for corrupt (union type field not present) and exits with 1 instead of crashing. A valid buffer prints as before.

A corrupt buffer can hold a union value while its type field is absent.
PrintOffset() only guarded this with FLATBUFFERS_ASSERT, so release builds
dereferenced a null prev_val and crashed (e.g. `flatc --json` on such a
binary). If an earlier unrelated field was present, prev_val still pointed
at it and its value was silently used as the union type.

Return an error when prev_val is null, and reset prev_val for absent
fields so a union never picks up a stale type field.

Fixes google#9033

This branch has not been deployed

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

Labels

c++ codegen Involving generating code from schema

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Null Pointer Dereference in JsonPrinter::PrintOffset() for Union Types

1 participant