QBinaryJson: reject a misaligned Value offset


The third and last offset that the validator turns into a pointer
without checking its alignment. isValidValueOffset() checks that the
offset is at least sizeof(Base) and that it leaves room for a uint
before the table, but not that it is a multiple of 4, so Value::data()
and everything built on it - base(), asString(), asLatin1String() -
can be misaligned.

No pre-existing file in invalidBinaryData/ covers this: they all fail
in Object::isValid() first. invalidBinaryData/43.bjson is a new
AI-generated 32 byte array holding a single string Value at offset 13,
which passes both existing conditions (13 >= sizeof(Base), 13 + 4 <=
tableOffset) but is not a multiple of 4, and which is still rejected
afterwards - the String there claims a length of 2 where only 1 fits -
so invalidBinaryData() keeps passing.

Says ubsan:

  qbinaryjson_p.h:190:20: runtime error: member access within misaligned address 0x7c43ffee0a65 for type 'const struct Data', which requires 4 byte alignment
  0x7c43ffee0a65: note: pointer points here
   00 00 00 00 02 00 00  00 41 00 00 a3 01 00 00  00 be 00 00 00 00 00 00  00 00 00 00 00 00 00 00  b9
               ^
    #0 0x7fe40e1d071d in QBinaryJsonPrivate::String::isValid(unsigned int) const qbinaryjson_p.h:190
    #1 0x7fe40e1d071d in QBinaryJsonPrivate::Value::isValidHelper(QBinaryJsonPrivate::Base const*, QVarLengthArray<QBinaryJsonPrivate::IsValidFrame, 16ll>&) const qbinaryjson.cpp:546
    #2 0x7fe40e1d3779 in QBinaryJsonPrivate::Array::isValidHelper(unsigned int, QVarLengthArray<QBinaryJsonPrivate::IsValidFrame, 16ll>&) const qbinaryjson.cpp:471
    #3 0x7fe40e1d506e in QBinaryJsonPrivate::ConstData::isValid() const qbinaryjson.cpp:321
    #4 0x7fe40e1d9cb3 in QBinaryJson::fromRawData(char const*, int, QBinaryJson::DataValidation) qbinaryjson.cpp:82
    #5 0x556b423cc535 in tst_QtJson::invalidBinaryData() tst_qtjson.cpp:141

Rejecting an unaligned Value offset cannot reject anything the writer
produces: Value::requiredStorage() only ever returns 0, sizeof(double),
an alignedSize(), or a nested Base::size, all multiples of 4.

With this commit, tst_qt5compat_json is ubsan-clean.

Amends qtbase/8e47474baf06b3884e9173302395dd25fc09eba9 (picked to
5.6), which introduced isValidValueOffset() with exactly these two
conditions while fixing QTBUG-61969. Qt 5.15 has it in qtbase's
src/corelib/serialization/qbinaryjson.cpp.

Pick-to: 6.12 6.11 6.8 6.5 5.15
Fixes: QTBUG-149219
Change-Id: I4da9eb1af637930626c96a91cc965d30f7e7ee01
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
commita0597ec13fdd126bd55b1e51e7c2dde622fb887c
parente18e0b0ae6b44346cf115fe245e5040fe98ccb00
authorMarc Mutz <marc.mutz@qt.io>
committerMarc Mutz <marc.mutz@qt.io>
commit timeWed, 2 Sep 2026 06:36:28 +0000