Found one (the?) ARM bug: (Pointer) aliasing issues

Iain Buclaw ibuclaw at ubuntu.com
Sat Nov 2 19:10:20 PDT 2013


On 2 November 2013 20:07, Johannes Pfau <nospam at example.com> wrote:

> I think I finally found the root cause for one of the remaining ARM
> bugs (the codegen bug which only appears on -O2 or higher).
>
> What happened in the test case was that the gcc backend illegally moved
> a read to a memory location before the write. It turns out that GCC
> assumed that the read and write locations were in different alias sets
> and therefore could not possibly reference the same memory location. One
> alias set was for 'ubyte[]' and one for 'char[]'.
>
> The code that triggers this issue is in std.algorithm.find:
> --------
> R1 find(...)(R1 haystack, R2 needle) if (/* are strings*/)
> {
>     return cast(char[]) .find!(ubyte[], ubyte[])
>         (cast(ubyte[]) haystack, cast(ubyte[])needle);
> }
> --------
> (Real code:
>
> https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/src/std/algorithm.d#L3555
> )
>
> The generic emitted by gdc:
> --------
> return <retval> = *(struct  *) &find (*(struct  *) &haystack, *(struct
> *) &needle);
> --------
>
> Or in the raw form:
> @44 = ubyte[]
> @11 = string
> --------
> @11     record_type      name: @17      size: @18      algn: 32
>                          tag : struct   flds: @19
> @31     pointer_type     size: @15      algn: 32       ptd : @11
> @40     pointer_type     size: @15      algn: 32       ptd : @44
> @41     call_expr        type: @44      fn  : @45      0   : @46
>                          1   : @47
> @44     record_type      name: @49      size: @18      algn:
>                          tag : struct   flds: @50
> @46     indirect_ref     type: @44      op 0: @53
> @47     indirect_ref     type: @44      op 0: @54
> @53     nop_expr         type: @40      op 0: @58
> @54     nop_expr         type: @40      op 0: @59
> @58     addr_expr        type: @31      op 0: @30
> @59     addr_expr        type: @31      op 0: @61
> --------
>
> Here it's easy to see that we essentially generate this code:
> *(cast(ubyte[]*)(&haystack))
> and this is AFAIK a violation of the aliasing rules.
>
> This problem is not observed at -O1 as the function call generates a
> new stackframe and we therefore have two distinct memory locations. But
> with -O2 inlining removes this copy and we now have variables
> referencing the same memory location with type ubyte[] and char[].
>
> I can not provide a reduced testcase as the smallest changes in
> compiler codegen (gcc version, gdc commit) or the test case can hide
> this issue. It's always reproducible with test15.d in the test suite.
> (In older gdc versions the test case does not segfault but it produces
> wrong output at -O2. This can be a very subtle difference)
>
> But here's a working code snippet which illustrates the generic
> generated by GDC:
>
> -----------------
> void main()
> {
>         char[] in1 = "Test".dup;
>         char[] in2 = "Test2".dup;
>
>         char[] result = cast(char[])find(cast(ubyte[])in1,
>             cast(ubyte[])in2);
> }
>
> ubyte[] find(ubyte[] a, ubyte[] b)
> {
>     return a;
> }
> -----------------
>
>
> So the important question here: Is this a bug in GDC codegen or is the
> code in std.algorithm invalid? According to
> http://dlang.org/expression.html
> "The cast is done as a type paint" so this could indeed be interpreted
> as a user mistake. But OTOH that page also talks about a runtime check
> of the array .lengths which is clearly missing here.
>
> I'm also wondering if that runtime check can actually fix this
> aliasing issue or if it can come up again if the runtime check itself
> is inlined?
>


I guess D does not have any aliasing rules.  Question: does this occur when
you pass -fno-strict-aliasing?

By default, GDC defines -fstrict-aliasing (which is also enabled by default
in -O2 in GCC), which is nice to have, but if it's proving to be
non-trivial, we can always disallow the optimisation being done in the
middle-end.  See the LANG_HOOKS_GET_ALIAS_SET langhook - last time I
checked, returning 0 disables aliasing rules from taking effect.

Regards.
-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/d.gnu/attachments/20131103/ec99c292/attachment.html>


More information about the D.gnu mailing list