lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Fri, 10 Apr 2015 17:19:25 +0300
From: Solar Designer <solar@...nwall.com>
To: discussions@...sword-hashing.net
Subject: Re: [PHC] On type aliasing and similar issues

BTW, Samuel replied to me off-list suggesting that the php_mt_seed
example is most likely an icc bug, still present in icc 15 - he found
that the miscompile goes away by simply "swapping the order of vtype and
uint32_t []" in the source code, and that OTOH it still occurs even with
-fno-strict-aliasing.  Thanks, Samuel!

However, there being an icc bug doesn't tell us anything conclusive
about whether the source code is standards-compliant or not.

On Fri, Apr 10, 2015 at 03:59:05PM +0300, Alexander Cherepanov wrote:
> The direct use of member names is relatively clear -- it's alllowed and 
> it's plainly spelled out in a footnote in 6.5.2.3p3 (C99 and C11). The 
> use through pointers is also relatively clear -- it's prohibited, which 
> is plainly spelled out in gcc doc[1].
[...]
> Everything becomes more complicated when a member of a union is an 
> array. It's somewhat in-between these two cases and I'm not sure how 
> it's supposed to be treated.

What about uses like this:

typedef union {
	struct { uint32_t a1, a2; } a;
	uint64_t b;
} any_t;

void copy2(uint32_t *dst, uint32_t *src)
{
	((any_t *)dst)->b = ((any_t *)src)->b;
}

There's no access to members of the union through a pointer (nor even
through an array), but there's expected to be access through uint32_t *
pointers in the caller of copy2().  Would a compiler inlining copy2() be
guaranteed to do what the programmer expected (copy two 32-bit values,
potentially faster and assuming 64-bit alignment)?

Or with the opposite uses of the two integer types:

void add32x2(uint64_t *dst, uint64_t *src)
{
	((any_t *)dst)->a.a1 += ((any_t *)src)->a.a1;
	((any_t *)dst)->a.a2 += ((any_t *)src)->a.a2;
}

where the caller is expected to access through uint64_t * pointers.

(Of course, this example is sensitive to byte order - or rather, to the
order of 32-bit halves in a 64-bit word.)

> Side note: not much have changed between C89 and C99 in this question. 
> Accessing a wrong member in a union is an implementation-defined 
> behavior in C89 but a footnote in 3.3.2.3 implies that the reason for 
> this is indeterminate byte order. OTOH this behavior is defined in C99 
> but the byte order is still not specified. Hence a strictly conforming 
> program shouldn't use it anyway.

There are many use cases where byte order does not matter, such as when
implementing a maybe-faster memset() or memcpy() alike that would use a
wider data type (as long as alignment and total size permit).

Thanks!

Alexander

Powered by blists - more mailing lists