News for hackers. Stuff that matters.
Re:Three proposals for the C standard WG14 by geofft on Wednesday June 20, 2018 @07:44PM (#17360923)
There aren't things that "can result in" UB, though. The C code itself, before any compilation, is already undefined by the C spec.

For instance, the following code is not valid C code:

    int a[2], b;
    a[2] = 5;
The compiler is free to do anything it wants, because the standard has not defined what it does. It could stop. Most likely it will just overwrite whatever memory is after a[1] with 5, because that's easiest.

If you want the compiler to do something specific, you need to define it. In some cases the standard has language for otherwise-defined behavior that is carved out as undefined (e.g., strict aliasing), and it's easy to go "Never mind"; in some cases it does not (e.g., writing to a string literal). For these ones, the behavior needs to be defined.

Simply saying "Don't optimize this" is just saying "I'm not going to define the behavior, but don't implement it this way," which isn't a particularly useful way to define a standard (e.g., for the null checks example, is the compiler permitted to leave the null check in, but insert a segfault right before it?).

Re:Three proposals for the C standard WG14 by vyodaiken on Wednesday June 20, 2018 @11:43PM (#17361954)
It's completely valid. It's just not conforming.

No the compiler is not entitled to insert a segfault. Segaults come from architectures and operating systems, not from compilers. The compiler is free to leave in the dereference of the null pointer and then, who knows what happens. But the compiler can't break the code by deleting a perfectly conforming null check on the theory that a previous dereference means that the pointer is not null.

The original Bourne shell used signal to catch memory faults so it could operate dynamic paging! If your OS/implementation permits, C is supposed to allow you do do things like that. The compiler is NOT supposed to insulate the programmer from bumps. (Disclaimer: I am not endorsing the horrible design of the Bourne shell which was also written in a macro style that made C into pseudo Algol).

Re:Three proposals for the C standard WG14 by jcelerier on Thursday June 21, 2018 @05:39AM (#17363478)
> Segaults come from architectures and operating systems, not from compilers.

But when you are programming in C, you are programming against the C abstract machine, not against an architecture or operating system. It's this machine that you are breaking when you invoke ub.

Re:Three proposals for the C standard WG14 by vyodaiken on Thursday June 21, 2018 @09:55AM (#17365084)
C is not Java.
Re:Three proposals for the C standard WG14 by jcelerier on Thursday June 21, 2018 @10:38AM (#17365548)
... and ? it still targets an abstract machine, defined in the C standard in section 5.1.2.3 (Program execution) : http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
Re:Three proposals for the C standard WG14 by vyodaiken on Thursday June 21, 2018 @12:08PM (#17366397)
It targets the abstract machine, but the dispute here is about what should happen when the program operation goes into territory that the abstract machine does not specify. And C code is EXPECTED to go beyond the territory of the abstract machine.
Re:Three proposals for the C standard WG14 by geofft on Thursday June 21, 2018 @12:44PM (#17366785)
> And C code is EXPECTED to go beyond the territory of the abstract machine.

Passive voice! You expect C code to go beyond the territory of the abstract machine. The authors of the standard, quite clearly, do not.

I can see both of these arguments. I think there is a place in the world for a C that is machine-specific. But it's clearly not what the standard authors have in mind, there are clearly people who find the genericness of C useful (cf. "portable assembler"), and piecemeal solutions like skipping individual bad optimizations won't solve the underlying problem that there's no way in C to say "Dude, I'm writing for a reasonable UNIX on a reasonable modern machine with a single flat address space for code and data and non-exception-raising two's-complement arithmetic and the ability to do nonaligned reads/writes and other normal things, please stop thinking I might also be writing for a PDP-11 bootloader."

I think you should go to the standards committee with a single proposal, which is that C should stop trying to be portable to weird / old architectures (and people who need them can use weird / old compilers, anyway). Among other things, you can now enable certain types of optimizations if the compiler is permitted to assume that arithmetic is two's-complement and nonaligned reads/writes work and so forth.

Re:Three proposals for the C standard WG14 by vyodaiken on Friday June 22, 2018 @01:09AM (#17371498)
>You expect C code to go beyond the territory of the abstract machine. The authors of the standard, quite clearly, do not.

That is 100% wrong.

>Strictly conforming programs are intended to be maximally portable among conforming implementations. Conforming programs may depend upon nonportable features of a conforming implementation.

The whole concept of "undefined behavior" is to cope with the reality that C programs routinely go beyond the bounds of the abstract machine.

Re:Three proposals for the C standard WG14 by cesarb on Thursday June 21, 2018 @02:02PM (#17367683)
> if the compiler is permitted to assume that [...] nonaligned reads/writes work

One of the most popular architectures for "a reasonable UNIX on a reasonable modern machine with a single flat address space for code and data" is the x86, and on it, some nonaligned reads/writes do trap. Certain optimizations can be done only if the compiler is permitted to assume that the data is aligned.

Re:Three proposals for the C standard WG14 by vyodaiken on Friday June 22, 2018 @10:19AM (#17374124)
As usual, this is pure handwaving: " certain optimizations ... "
Re:Three proposals for the C standard WG14 by palotasb on Thursday June 21, 2018 @04:46AM (#17363247)
What is your definition of valid? It's not valid by any C standard or common compiler implementation. For the sake of any argument, we should at least agree on a common definition for valid.

As for deleting null checks, time-travelling UB etc. the compiler always assumes the code is valid, bug-free for the compiler-specific definition of valid. This is at least the standard definition but it can be expanded by flags and extensions. Then they optimize that code without regard to what happens if the code actually had programming bugs.

Re:Three proposals for the C standard WG14 by vyodaiken on Thursday June 21, 2018 @10:53AM (#17365689)
is k = i+j valid C? Can it be translated sensibly to add i,j; jump on overflow to random; store k; ? How about sometimes omitting the jump to random and sometimes not?
Re:Three proposals for the C standard WG14 by geofft on Thursday June 21, 2018 @11:24AM (#17365982)
Signed integer overflow is undefined, so the only obligation is that the code operates correctly when signed integer overflow doesn't happen. So, yes all those options are permissible, because as far as the C standard specifies, it's "add i,j; if false jump to random; store k".

If you want to add a definition for signed integer overflow (as C++ is considering, see http://wg21.link/P0907r0 ) then it would be defined and the compiler would no longer get to consider "if signed overflow" and "if false" the same.

Re:Three proposals for the C standard WG14 by vyodaiken on Thursday June 21, 2018 @12:09PM (#17366411)
I 100% doubt that that Ritchie would have agreed. This is the existing interpretation of the standard, which is exactly what I propose to change. I believe the standard interpretation has strayed from both the language design and the objectives of the language.
Re:Three proposals for the C standard WG14 by geofft on Thursday June 21, 2018 @09:09AM (#17364701)
> But the compiler can't break the code by deleting a perfectly conforming null check on the theory that a previous dereference means that the pointer is not null.

Why is this different from letting the compiler optimize out the second check here?

    int foo(unsigned int i) {
        if (i < 5)
            return this();
        if (i < 4)
            return that();
        return those();
    }
The C standard knows that NULL is special, a marker value for an invalid pointer. (The implementation does not have to translate it as the pointer with numeric value zero; the abstract machine just needs some value.) Absent an Optional/Maybe/etc. type, C needs some invalid pointer.

What about the following—are you okay with compilers optimizing it?

    struct pointer {
        int *value;
        char valid;
    }

    void *deref(struct pointer p) {
        if (!p.valid)
            abort();
        return *p.value;
    }

    void stuff(struct pointer p) {
        int n = deref(p);
        if (!p.valid) {
            fprintf(stderr, "Hey, that pointer wasn't valid!\n");
            return;
        ...
    }
No NULLs involved.

> The original Bourne shell used signal to catch memory faults so it could operate dynamic paging! If your OS/implementation permits, C is supposed to allow you do do things like that.

I'd believe that (especially given the state of optimizers in Bourne's era) C does allow you to do things like this. I'd also believe that with sufficient -fno-unwanted-cleverness flags. C is the best way to do things like this.

But asking C to be designed to support things like this is quite a change. I get that this is exactly the change you're pushing for, but, the only way it can work is if the C abstract machine becomes hardware-dependent enough that you can embed platform assumptions in your C—and so C is no longer a "portable assembler."

There's precedent for this. One that comes to mind is the ability to cast a data pointer to a function pointer (which doesn't have to be valid; the abstract machine doesn't know if your physical machine uses different address spaces and different representations for the two, and even the brand new architecture WebAssembly uses different address spaces, but compatible representations). dlsym() implicitly requires this, and POSIX.1-2013 finally made an explicit requirement that a C implementation conforming to POSIX must define it in a meaningful way. http://pubs.opengroup.org/onlinepubs/9699919799/functions/dl...

I would certainly support a variant of C that did things like assume a flat address space, validity of all pointer values besides NULL (and an expectation that signals can catch and fix invalid pointer dereferences), char = unsigned char, 8-bit bytes, two's complement arithmetic, etc. It would not support every architecture C supports. It wouldn't be a good fit as a C standard, but as a variant for people who are happy to never target segmented real-mode x86 or the PDP-11, it seems pretty great.

Re:Three proposals for the C standard WG14 by vyodaiken on Friday June 22, 2018 @10:22AM (#17374150)
There is nothing in what I have proposed that requires assuming a flat address space or that pointers can catch and fix invalid pointer dereferences etc.