@@ -252,33 +252,81 @@ std::shared_ptr<StructValueView> KTestObjectParser::structView(const std::vector
252252 size_t offsetInBits,
253253 types::PointerUsage usage) {
254254 std::vector<InitReference> tmpInitReferences;
255- return structView (byteArray, curStruct, offsetInBits, usage, {}, " " , {}, tmpInitReferences);
255+ return structView (byteArray, curStruct, offsetInBits, usage, {}, false , " " , {}, tmpInitReferences);
256256}
257257
258258std::shared_ptr<StructValueView> KTestObjectParser::structView (const std::vector<char > &byteArray,
259259 const StructInfo &curStruct,
260260 size_t offsetInBits,
261261 PointerUsage usage,
262262 const std::optional<const Tests::MethodDescription> &testingMethod,
263+ const bool anonymousField,
263264 const std::string &name,
264265 const MapAddressName &fromAddressToName,
265266 std::vector<InitReference> &initReferences) {
266267 std::vector<std::shared_ptr<AbstractValueView>> subViews;
267268
269+ size_t fieldIndexToInitUnion = SIZE_MAX;
270+ size_t sizeOfFieldToInitUnion = 0 ;
271+ size_t prevFieldEndOffset = offsetInBits;
272+ size_t structEndOffset = offsetInBits + curStruct.size ;
273+ size_t fieldIndex = 0 ;
274+ bool dirtyInitializedStruct = false ;
268275 for (const auto &field: curStruct.fields ) {
276+ bool dirtyInitializedField = false ;
269277 size_t fieldLen = typesHandler.typeSize (field.type );
270- size_t fieldOffset = offsetInBits + field.offset ;
278+ size_t fieldStartOffset = offsetInBits + field.offset ;
279+ size_t fieldEndOffset = fieldStartOffset + fieldLen;
280+ if (curStruct.subType == types::SubType::Union) {
281+ prevFieldEndOffset = offsetInBits;
282+ }
283+
284+ auto dirtyCheck = [&](int i) {
285+ if (i >= byteArray.size ()) {
286+ LOG_S (ERROR) << " Bad type size info: " << field.name << " index: " << fieldIndex;
287+ } else if (byteArray[i] == 0 ) {
288+ return false ;
289+ }
290+ // the field cannot init the union in this state
291+ dirtyInitializedField = true ;
292+ return true ;
293+ };
294+
295+ if (prevFieldEndOffset < fieldStartOffset) {
296+ // check an alignment gap
297+ for (int i = prevFieldEndOffset/8 ; i < fieldStartOffset/8 ; ++i) {
298+ if (dirtyCheck (i)) {
299+ break ;
300+ }
301+ }
302+ }
303+ if (!dirtyInitializedField && curStruct.subType == types::SubType::Union) {
304+ // check the rest of the union
305+ for (int i = fieldEndOffset/8 ; i < structEndOffset/8 ; ++i) {
306+ if (dirtyCheck (i)) {
307+ break ;
308+ }
309+ }
310+ }
271311
272312 switch (typesHandler.getTypeKind (field.type )) {
273313 case TypeKind::STRUCT_LIKE:
274- subViews.push_back (structView (byteArray, typesHandler.getStructInfo (field.type ), fieldOffset, usage, testingMethod,
275- PrinterUtils::getFieldAccess (name, field), fromAddressToName, initReferences));
314+ {
315+ auto sv = structView (byteArray, typesHandler.getStructInfo (field.type ),
316+ fieldStartOffset, usage, testingMethod, field.anonymous ,
317+ PrinterUtils::getFieldAccess (name, field), fromAddressToName,
318+ initReferences);
319+ dirtyInitializedField |= sv->isDirtyInit ();
320+ subViews.push_back (sv);
321+ }
276322 break ;
277323 case TypeKind::ENUM:
278- subViews.push_back (enumView (byteArray, typesHandler.getEnumInfo (field.type ), fieldOffset, fieldLen));
324+ subViews.push_back (enumView (byteArray, typesHandler.getEnumInfo (field.type ),
325+ fieldStartOffset, fieldLen));
279326 break ;
280327 case TypeKind::PRIMITIVE:
281- subViews.push_back (primitiveView (byteArray, field.type .baseTypeObj (), fieldOffset,
328+ subViews.push_back (primitiveView (byteArray, field.type .baseTypeObj (),
329+ fieldStartOffset,
282330 std::min (field.size , fieldLen)));
283331 break ;
284332 case TypeKind::ARRAY: {
@@ -296,21 +344,22 @@ std::shared_ptr<StructValueView> KTestObjectParser::structView(const std::vector
296344 }
297345 if (onlyArrays) {
298346 size *= typesHandler.typeSize (field.type .baseTypeObj ());
299- subViews.push_back (multiArrayView (byteArray, field.type , size,
300- fieldOffset, usage));
347+ subViews.push_back (multiArrayView (byteArray, field.type , size, fieldStartOffset, usage));
301348 } else {
302349 std::vector<std::shared_ptr<AbstractValueView>> nullViews (
303350 size, std::make_shared<JustValueView>(PrinterUtils::C_NULL));
304351 subViews.push_back (std::make_shared<ArrayValueView>(nullViews));
305352 }
306353 } else {
307- auto view = arrayView (byteArray, field.type .baseTypeObj (), fieldLen, fieldOffset, usage);
354+ auto view = arrayView (byteArray, field.type .baseTypeObj (), fieldLen,
355+ fieldStartOffset, usage);
308356 subViews.push_back (view);
309357 }
310358 }
311359 break ;
312360 case TypeKind::OBJECT_POINTER: {
313- std::string res = readBytesAsValueForType (byteArray, PointerWidthType, fieldOffset,
361+ std::string res = readBytesAsValueForType (byteArray, PointerWidthType,
362+ fieldStartOffset,
314363 PointerWidthSizeInBits);
315364 subViews.push_back (getLazyPointerView (fromAddressToName, initReferences,
316365 PrinterUtils::getFieldAccess (name, field), res, field.type ));
@@ -330,15 +379,35 @@ std::shared_ptr<StructValueView> KTestObjectParser::structView(const std::vector
330379 LOG_S (ERROR) << message;
331380 throw NoSuchTypeException (message);
332381 }
382+
383+ if (!dirtyInitializedField && sizeOfFieldToInitUnion < fieldLen) {
384+ fieldIndexToInitUnion = fieldIndex;
385+ sizeOfFieldToInitUnion = fieldLen;
386+ } else {
387+ dirtyInitializedStruct = true ;
388+ }
389+ prevFieldEndOffset = fieldEndOffset;
390+ ++fieldIndex;
333391 }
334392
335393 std::optional<std::string> entryValue;
336- if (curStruct.hasAnonymousStructOrUnion ) {
337- auto bytesType = types::Type::createSimpleTypeFromName (" utbot_byte" );
338- const std::shared_ptr<AbstractValueView> rawDataView = arrayView (byteArray, bytesType, curStruct.size , offsetInBits, usage);
339- entryValue = PrinterUtils::convertBytesToUnion (curStruct.name , rawDataView->getEntryValue (nullptr ));
394+ if (curStruct.subType == types::SubType::Union) {
395+ if (fieldIndexToInitUnion == SIZE_MAX && !curStruct.name .empty ()) {
396+ // init by memory copy
397+ entryValue = PrinterUtils::convertBytesToUnion (
398+ curStruct.name ,
399+ arrayView (byteArray,
400+ types::Type::createSimpleTypeFromName (" utbot_byte" ),
401+ curStruct.size ,
402+ offsetInBits, usage)->getEntryValue (nullptr ));
403+ dirtyInitializedStruct = false ;
404+ }
405+ if (fieldIndexToInitUnion != SIZE_MAX) {
406+ dirtyInitializedStruct = false ;
407+ }
340408 }
341- return std::make_shared<StructValueView>(curStruct, subViews, entryValue);
409+ return std::make_shared<StructValueView>(curStruct, subViews, entryValue,
410+ anonymousField, dirtyInitializedStruct, fieldIndexToInitUnion);
342411}
343412
344413std::string KTestObjectParser::primitiveCharView (const types::Type &type, std::string value) {
@@ -962,7 +1031,7 @@ std::shared_ptr<AbstractValueView> KTestObjectParser::testParameterView(
9621031 switch (typesHandler.getTypeKind (paramType)) {
9631032 case TypeKind::STRUCT_LIKE:
9641033 return structView (rawData, typesHandler.getStructInfo (paramType), 0 ,
965- usage, testingMethod, param.varName , fromAddressToName, initReferences);
1034+ usage, testingMethod, false , param.varName , fromAddressToName, initReferences);
9661035 case TypeKind::ENUM:
9671036 return enumView (rawData, typesHandler.getEnumInfo (paramType), 0 , SizeUtils::bytesToBits (rawData.size ()));
9681037 case TypeKind::PRIMITIVE:
0 commit comments