[Development] QJsonPrivate::Parser::parseObject broken on big endian

lars.knoll at nokia.com lars.knoll at nokia.com
Thu Sep 13 13:23:16 CEST 2012


On Sep 13, 2012, at 12:56 PM, ext Konstantin Tokarev <annulen at yandex.ru> wrote:

> 03.09.2012, 15:21, "Olivier Goffart" <olivier at woboq.com>:
> 
>>  On Sunday 02 September 2012 23:10:18 Konstantin Tokarev wrote:
>>>   Hi all,
>>> 
>>>   When building Qt 5 on big endian host (PPC) I've found moc breaking on Qt
>>>   classes containing Q_PLUGIN_METADATA with
>>> 
>>>   ASSERT: "idx >= 0 && idx < s" in file
>>>   ../../../include/QtCore/../../src/corelib/tools/qvarlengtharray.h, line 111
>>> 
>>>   It turned out to be a fault of QJsonPrivate::Parser::parseObject which has
>>>   different code for handling of big endian and little endian cases:
>>> 
>>>       if (parsedObject.offsets.size()) {
>>>           int tableSize = parsedObject.offsets.size()*sizeof(uint);
>>                                                       ^^^^^^^^^^^^^
>> 
>>  The error is there:  one should multiply tableSize by sizeof(uint) only if one
>>  do a memcpy.
>>>           table = reserveSpace(tableSize);
>>>   #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
>>>           memcpy(data + table, parsedObject.offsets.constData(), tableSize);
>>>   #else
>>>           offset *o = (offset *)(data + table);
>>>           for (int i = 0; i < tableSize; ++i)
>>>               o[i] = parsedObject.offsets[i];
>>> 
>>>   #endif
>>>       }
>>> 
>>>   Could anyone explain why memcpy cannot be used for big endian case here?
>>  I guess that's because the offsets needs to be stored in little endian.
>>  offset is a typedef to a class that has an assignement operator which swap the
>>  bytes.
> 
> It turned out to be not the only place where memcpy is working incorrectly.
> Unit test segfaults on memcpy in Value::copyData 
> 
> 404     case QJsonValue::Array:
> 405     case QJsonValue::Object: {
> 406         const QJsonPrivate::Base *b = v.base;
> 407         if (!b)
> 408             b = (v.t == QJsonValue::Array ? &emptyArray : &emptyObject);
> 409         memcpy(dest, b, b->size);
> 410         break;
> 411     }
> 
> I tried to understand why memcpy fails here and how to replace it for BE case,
> but still don't have a clue. I'm also quite disappointed to see so heavily endian-
> dependent code written nowadays.

That's what you have to do when doing binary formats unfortunately. I think the main problem is that we currently don't have a big endian machine at hand for testing. I've tried to make it as endian independent as possible already, but without being able to test you're bound to have bugs in such code.

As to why this would fail: The only reason I can see is if either dest is invalid, or b->size contains garbage.

Cheers,
Lars




More information about the Development mailing list