Remix.run Logo
nneonneo 4 days ago

I mean, there is a reason why these sorts of constructs are UB, even if they work on popular architectures. The problems aren’t unique to IA64, either; the better solution is to be aware that UB means UB and to avoid it studiously. (Unfortunately, that’s also hard to do in C).

loeg 4 days ago | parent | next [-]

It's a very weird architecture to have these NAT states representable in registers but not main memory. Register spilling is a common requirement!

amluto 4 days ago | parent | next [-]

Hah, this is IA-64. It has special hardware support for register spills, and you can search for “NaT bits” here:

https://portal.cs.umbc.edu/help/architecture/aig.pdf

to discover at least two magical registers to hold up to 127 spilled registers worth of NaT bits. So they tried.

The NaT bits are truly bizarre and I’m really not convinced they worked well. I’m not sure what happens to bits that don’t fit in those magic registers. And it’s definitely a mistake to have registers where the register’s value cannot be reliably represented in the common in-memory form of the register. x87 FPU’s 80-bit registers that are usually stored in 64-bit words in memory are another example.

dwattttt 3 days ago | parent [-]

CHERI looks at this and says "64+1 bits? A childish effort", and brings 128+1 to the table.

EDIT: to be fair to it, they carry it through to main memory too

amluto 3 days ago | parent [-]

I no real complaints about CHERI here. What’s a pointer, anyway? Lots of old systems thought it was 8 or 16 bits that give a linear address. 8086 thought it was 16 + 16 bits split among two registers, with some interesting arithmetic [0]. You can’t add, say, 20000 to a pointer and get a pointer to a byte 20000 farther into memory. 80286 changed it so those high bits index into a table, and the actual segment registers are much wider than 16 bits and can’t be read or written directly [1]. Unprivileged code certainly cannot load arbitrary values into a segment register. 80386 added bits. Even x86_64 still technically has those extra segment registers, but they mostly don’t work any more.

So who am I to complain if CHERI pointers are even wider and have strange rules? At least you can write a pointer to memory and read it back again.

[0] I could be wrong. I’ve hacked on Linux’s v8086 support, but that’s virtual and I never really cared what its effect was in user mode so long as it worked.

[1] You can read and write them via SMM entry or using virtualization extensions.

Someone 3 days ago | parent | prev | next [-]

Old-time x86 sort-of has “states representable in registers but not main memory”, too.

Compilers used to use its 80-bit floating point registers for 64-bit float computations, but also might spill them to memory as 64-bit float numbers.

https://hal.science/hal-00128124v3/file/floating-point.pdf section 3 has some examples, including one where the assert can fail in:

  int main (void) {
    double x = 0x1p-1022, y = 0x1p100, z;
    do_nothing(&y);
    z = x / y;
    if (z != 0) {
      do_nothing(&z);
      assert(z != 0);
    }
  }
with

  void do nothing (double *x) { }
in a different compilation unit.
mwkaufma 4 days ago | parent | prev [-]

I assume they were stored in an out-of-band mask word

awesome_dude 4 days ago | parent | prev [-]

The bigger problem is that a user cannot avoid an application where someone was writing code with UB, unless they both have the source code, and expertise in understanding it.

eru 3 days ago | parent [-]

Isn't that a general problem?