Hacker News new | ask | show | jobs
by haberman 4803 days ago
> It's a valid operation regardless of whether a standards body says it's not.

Whoa there, cowboy. You may not feel personally beholden to standards bodies, but compiler vendors are following their lead. The major compilers are getting more and more aggressive about optimizing away undefined behavior every year.

> The effect is to set y to the first two bytes of memory from x.

No, it's really not. It's undefined behavior and the compiler is free to do absolutely whatever it wants.

> One source of confusion is that int and short are essentially, for all intents and purposes, undefined -- they are of course defined by the standards, but their implementation is allowed to vary so much that no programmer can make any assumptions about their size (in bytes) at runtime.

I agree with this, and have made this argument before: http://blog.reverberate.org/2013/03/cc-gripe-1-integer-types...

But this is an entirely separate issue.

1 comments

No, it's really not. It's undefined behavior and the compiler is free to do absolutely whatever it wants.

The point is that compilers do some specific thing, regardless of the fact that the standards bodies say they're free to reboot your computer.

As long as all you care about is x86/x86_64/PowerPC (and probably ARM as well), then you can trust that the compiler is going to generate code which copies the first two bytes of x into the memory occupied by y.

>As long as all you care about is x86/x86_64/PowerPC (and probably ARM as well), then you can trust that the compiler is going to generate code which copies the first two bytes of x into the memory occupied by y.

That's the thing that haberman is trying to tell you, you can't trust that any more, even with architectures you think you know. What you said was true about 10 years ago, but things have changed. Go read about "-fno-strict-aliasing" [1].

[1] http://thiemonagel.de/2010/01/no-strict-aliasing/

There be dragons. The following program prints 10 on gcc 4.6.3, x86-64:

  #include <stdio.h>
  #include <stdint.h>

  void f(uint32_t *x, uint16_t *y) {
    *x = 5;
    printf("%d\n", *y);
  }

  int main() {
    uint32_t x = 10;
    f(&x, (uint16_t*)&x);
  }
The antidote is to put a memory barrier in between the assignment and the printf.

  *x = 5;
  __sync_synchronize();
  printf("%d\n", *y);
http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins....

The reason this example is fundamentally different from my example is because mine doesn't create two objects that point to the same memory. In such situations, memory barriers are necessary. Also, your program won't work on different platforms due to endianness.

That is not what memory barriers are for, at all. Memory barriers are a sequencing primitive for shared-memory concurrency (an excellent intro is here: http://lxr.linux.no/linux/Documentation/memory-barriers.txt). They are never required for correctness in valid single-threaded programs.

The memory barrier "fixed" this program similarly to how a cruise missile "fixes" a termite problem. It was just a coincidence and it was the wrong tool for the job.

Except we're talking about an invalid program. The program is invalid as written. Therefore memory barriers are the antidote because they're necessary in this situation.

A tool doesn't have a purpose. It has capabilities, and understanding why something works (and why it can be relied upon) is all that matters.

Yes, it is an invalid program. The antidote is to fix it, not to jigger it in a way that happens to work. The memory barrier is not "necessary" -- it is not even a correct fix. Even with a memory barrier as you added it, it is still an invalid program that invokes undefined behavior. The memory barrier may have coincidentally fixed the problem on your system, but there is still no guarantee it will work on another architecture, another compiler, or even another version of the same compiler.

The problem with my program is that it casts an int32_t pointer to int16_t pointer. The correct fix is to not do that. "Fixing" the problem with a memory barrier is a step in the wrong direction.