2
votes

I'd like to understand the trap representation concept in details. The definition is pretty clear Section 3.19.4:

an object representation that need not represent a value of the object type

Okay, I'd like to try it by some examples.

struct test_t{
    uint64_t member;
};

struct test_t *test_ptr = malloc(sizeof(uint32_t));
struct test_t = *test_ptr; //1

I don't think that //1 causes UB here, because Section 6.2.6.1:

If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined.

but

The value of a structure or union object is never a trap representation, even though the value of a member of the structure or union object may be a trap representation.

I think UB will be caused by something like

printf("Test.member = %lu\n", test.member);

But I'm not sure how to prove that in such a case the representation of member is a trap.

1
It's UB, but not because of any possible trap-representations. Instead it's UB because you access memory out of bounds, you read memory that doesn't belong to you. And that happens at //1.Some programmer dude
A trap representation is only possible when the object has bits that aren't used for value representation. Fixed width unsigned integer types use all of their bits for value representation.StoryTeller - Unslander Monica
@Someprogrammerdude So can you give an example of trap representation of a member of a structure?Some Name
@StoryTeller But *test_ptr is an lvalue and the value of a structure is never a trap. Why is this UB? Could you give some reference?Some Name
Code like uint64_t member; ... printf("Test.member = %lu\n", test.member); unnecessarily adds confusion as "lu" is not certainly the matching print specifier for uint64_t, thus making the printf("Test.member = %lu\n", test.member); UB right there. Better to code with "%" PRIu64.chux - Reinstate Monica

1 Answers

3
votes

member has no trap representations, because uint64_t has no trap representations.

7.20.1.1 Exact-width integer types

2 The typedef name uintN_t designates an unsigned integer type with width N and no padding bits. Thus, uint24_t denotes such an unsigned integer type with a width of exactly 24 bits.

No padding bits. And from the following section we learn:

6.2.6.2 Integer types

1 For unsigned integer types other than unsigned char, the bits of the object representation shall be divided into two groups: value bits and padding bits (there need not be any of the latter). If there are N value bits, each bit shall represent a different power of 2 between 1 and 2N - 1, so that objects of that type shall be capable of representing values from 0 to 2N - 1 using a pure binary representation; this shall be known as the value representation. The values of any padding bits are unspecified.53)

Where note 53, despite being non-normative, tells us that those padding bits (if they exist) can be used to trap:

53) Some combinations of padding bits might generate trap representations, for example, if one padding bit is a parity bit. Regardless, no arithmetic operation on valid values can generate a trap representation other than as part of an exceptional condition such as an overflow, and this cannot occur with unsigned types. All other combinations of padding bits are alternative object representations of the value specified by the value bits.

While value bits can never hold a pattern that is illegal.

So you cannot produce a trap representation of uint64_t in a well-formed program. Mind you, that your program has UB due to the out of bounds access, but that is not caused by possibility of trap representations. It's undefined all on its own.