Skip to content

Instantly share code, notes, and snippets.

@bcantrill
Created January 11, 2019 18:41
Show Gist options
  • Save bcantrill/7b30914541fe6c3306fc174992d497ec to your computer and use it in GitHub Desktop.
Save bcantrill/7b30914541fe6c3306fc174992d497ec to your computer and use it in GitHub Desktop.
Punishment doesn't fit the crime?
#define NULL ((void *)0)
static char *arr[2] = { "nasal", "demons" };
long
func()
{
int i;
for (i = 0; i <= 2; i++) {
if (arr[i] == NULL && i == 0)
return (0xbad);
}
return (0xfad);
}
@rileyberton
Copy link

GCC 6.3 or earlier doesn't even produce output under -O2. Heh.

https://godbolt.org/z/s3O6JH

@bcantrill
Copy link
Author

So, adding -fno-aggressive-loop-optimizations makes this code run correctly -- a flag that itself was added because the aggressive loop optimization broke SPEC CPU 2006. As for the GCC code itself, it is remarkably frank about this optimization.

@sebres
Copy link

sebres commented Jan 14, 2019

More weird example (https://godbolt.org/z/VM3nMo):

static char *arr[2] = { "nasal", "demons" };

long
func_n()
{
    int i;
    for (i = 0; i <= 2; i++) {
        if (!arr[i])
            return (1);
    }
    return (0);
}
long
func_p()
{
    int i;
    for (i = 0; i <= 2; i++) {
        if (arr[i])
            return (1);
    }
    return (0);
}

long
func_control(int control)
{
    int i;
    for (i = 0; i <= 2; i++) {
        if ( (!control && !arr[i]) || (control && arr[i]) )
            return (1);
    }
    return (0);
}

results into:

func_n:
  mov eax, 1
  ret
func_p:
  mov eax, 1
  ret
func_control:
  mov edx, 3
  mov eax, 1
  test edi, edi
  jne .L4
.L9:
  sub edx, 1
  jne .L9
  xor eax, eax
.L4:
  ret

As one could see the UB is abruptly "conditional" (in func_control) if one extend it with control-switch.

And as already said, what on this UB is unexpected for developer (sorry for tautology):

  • this does not produce the warning array subscript 2 is above array bounds of 'char *[2]' [-Warray-bounds].
    Even not with -Wall or -Wextra;
  • small amends (like variable control condition in func_control) change the UB drastically;
  • it is extremely unstable between gcc-versions (and of course the compile-flags).
    Clear, it is an UB, but why this could not be a bit "stable" UB, remaining the same result between versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment