Skip to content

AVRO-3194: [c++] Throw instead of segfaulting on GenericDatum::value<T>() type mismatch - #3965

Open
iemejia wants to merge 1 commit into
apache:mainfrom
iemejia:AVRO-3194-genericdatum-value-guard
Open

AVRO-3194: [c++] Throw instead of segfaulting on GenericDatum::value<T>() type mismatch#3965
iemejia wants to merge 1 commit into
apache:mainfrom
iemejia:AVRO-3194-genericdatum-value-guard

Conversation

@iemejia

@iemejia iemejia commented Aug 24, 2026

Copy link
Copy Markdown
Member

What changes were proposed in this pull request?

GenericDatum::value<T>() (both the mutable and const overloads) returned:

return (type_ == AVRO_UNION) ? std::any_cast<GenericUnion>(&value_)->datum().value<T>()
                             : *std::any_cast<T>(&value_);

The pointer form of std::any_cast<T>(&value_) returns nullptr when the requested C++ type T does not match the type actually held by the datum. Dereferencing that result is an unchecked null-pointer dereference (CWE-476): undefined behaviour that manifests as a segmentation fault as soon as the returned reference is read or copied.

This is the crash reported in AVRO-3194, where user code that binds/copies the result — e.g. const avro::GenericRecord record = datum.value<avro::GenericRecord>() when the datum is not actually a GenericRecord — segfaults instead of receiving a diagnosable error.

How was this patch fixed?

Both overloads now check the any_cast result and throw an avro::Exception describing the datum type on a mismatch, instead of dereferencing a null pointer. Correct-type access and the union-unwrapping path are unchanged.

How was this patch tested?

New regression case testGenericDatumValueTypeMismatch in test/unittest.cc:

  • correct-type access still returns the value;
  • mismatched-type access (value<int32_t>() / value<std::vector<uint8_t>>() on a string datum) now throws avro::Exception through both the mutable and const overloads.

Verified against the current code: without the fix the test reports exception avro::Exception expected but not raised (the null reference is UB and segfaults when the value is copied, as in the report); with the fix the full unittest suite passes (*** No errors detected).

…T>() type mismatch

GenericDatum::value<T>() returned *std::any_cast<T>(&value_). When the
requested C++ type T does not match the type actually stored in the datum,
std::any_cast on a pointer returns nullptr, so dereferencing it is an
unchecked null-pointer dereference (CWE-476) that leads to undefined
behaviour and a segmentation fault (e.g. const GenericRecord r =
datum.value<GenericRecord>() when the datum does not hold a GenericRecord).

Guard both the mutable and const overloads: throw an avro::Exception on a
type mismatch instead of dereferencing the null pointer.
@github-actions github-actions Bot added the C++ Pull Requests for C++ binding label Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C++ Pull Requests for C++ binding

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant