Comment 9 for bug 437726

Revision history for this message
Ulrich Weigand (uweigand) wrote :

The problem is in the operator== and operator!= routines for UUID, in include/xplc/uuidops.h:

inline int operator==(const UUID& uuid1, const UUID& uuid2) {
    return
      (&uuid1 == &uuid2) ||
      ((static_cast<const u_int32_t*>(&uuid1.Data1)[0] == static_cast<const u_int32_t*>(&uuid2.Data1)[0]) &&
       (static_cast<const u_int32_t*>(&uuid1.Data1)[1] == static_cast<const u_int32_t*>(&uuid2.Data1)[1]) &&
       (static_cast<const u_int32_t*>(&uuid1.Data1)[2] == static_cast<const u_int32_t*>(&uuid2.Data1)[2]) &&
       (static_cast<const u_int32_t*>(&uuid1.Data1)[3] == static_cast<const u_int32_t*>(&uuid2.Data1)[3]));
}

Since UUID (and GUID) is defined like this:

typedef struct _GUID {
  u_int32_t Data1;
  u_int16_t Data2;
  u_int16_t Data3;
  u_int8_t Data4[8];
} GUID;

those static_casts above cause the aliasing violation. Note how uuid1.Data2/3/4 have effective type u_int16_t or u_int8_t, but are accessed via an lvalue of type u_int32_t ? This causes undefined behavior.

To avoid this, there are basically two standards-compliant ways I can see: either, you compare all elements separately, or else you compare the whole struct via a memcmp. (The latter could in theory cause spurious failures if there were padding bytes in the structure; but in practice this does not occur on any system I'm aware of.)