Earlier quoted context omitted.
As an aside, this is one of the spots where GPT does a really good job of fixing things. Reword the following passage. Change euphemisms to wording that has similar meaning though no negative conotations. Indicate changed words by putting them in "{{word}}" ### Standards are supposed to lead ... Why are such requests made? Often because of arithmetic bugs. And what is a non-null pointer from malloc(0) good for? Absol…
I guess that's be the way to detect if the text has been written by the AI - it'd be completely devoid of metaphors and cleansed from anything that could possibly offend somebody. I wouldn't ever call it a "good job" but I guess it's useful.
Catch-23: The New C Standard Sets the World on Fire
171–180 of 275 posts
Re: Catch-23: The New C Standard Sets the World on Fire
#172Earlier quoted context omitted.
> many things that are UB in C/C++ are UB because they are really hard to verify at compile time which makes them almost impossible to program around The second half of the sentence doesn't follow from the first. Take everyone's favorite example, signed integer overflow: all you have to do to avoid UB on signed integer overflow is check for overflow before doing the operation (and C23 finally adds features to do that…
> all you have to do to avoid UB on signed integer overflow is check for overflow before doing the operation (and C23 finally adds features to do that for you). …making your code practically unreadable, since you have to write ckd_add(ckd_add(ckd_mul(a,a),ckd_mul(ckd_mul(2,a),b)),ckd_mul(b,b)) instead of a * a + 2 * a * b + b * b.
Re: Catch-23: The New C Standard Sets the World on Fire
#173Did we ever legalize type punning?
Re: Catch-23: The New C Standard Sets the World on Fire
#174I don't agree with this in the slightest. I'm not "outraged" by undefined behaviour, it's a fundamental tool for writing performant code. Ensuring that dereferencing a null pointer or accessing outside the bounds of an array is undefined behaviour is what lets the compiler not emit a branch on every array access and pointer dereference.
Furthermore, I really don't understand the outrage that there is another explicit tool to achieve behaviour the author may or may not consider harmful. If it's an explicit macro, it's not a tarpit!
Re: Catch-23: The New C Standard Sets the World on Fire
#175> C23 furthermore gives the compiler license to use an unreachable annotation on one code path to justify removing, without notice or warning, an entirely different code path that is not marked unreachable: see the discussion of puts() in Example 1 on page 316 of N3054.9 I don't agree with that description at all. Here's the code: 1 if (argc The only code path that's "entirely different" is lines 1,4,5 and in that ca…
Re: Catch-23: The New C Standard Sets the World on Fire
#176Earlier quoted context omitted.
First, you might have meant c = a+b; The other way isn't really definable as an assignment mathematically. And there is a lot more to it than just pass/fail. First, an addition doesn't fail, from a computer architecture perspective, the addition will always succeed, the only thing that could fail (in all the usual architectures) are possible memory fetch and store operations when not strictly dealing in register or i…
> First, you might have meant c = a+b; > The other way isn't really definable as an assignment mathematically. This correction is condescending and unnecessary. Unless the person had never written a single line of code in their life, then they would obviously know "a+b" is not a modifiable lvalue. And the point about pass/fail was also obviously not mean to capture the full complexity of the flags set by a CPU operat…
I do strongly disagree on the second one about pass/fail. This kind of nitpicking is necessary here, because the discussion is about a standard intended to precisely describe such operations, and how the underlying hardware might be utilized to execute them. Being imprecise in this context is dangerous, wrong, problematic and leads to the whole point of the discussion being lost in a sea of handwaving.
Re: Catch-23: The New C Standard Sets the World on Fire
#177Earlier quoted context omitted.
Is the improved performance of C over say Java, or Rust (which both have much less undefined behaviour -- Java almost none) worth the pain and bugs which have been caused by UB? Honestly, I don't think so, and as computers get more powerful and the amount of the world which relies on their correct functioning grows, I feel the arguments for UB become increasingly difficult to justify.
I went to look up undefined behaviour in Rust and I got this scary warning: Warning: The following list is not exhaustive. There is no formal model of Rust's semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe. The following list is just what we know for sure is undefined behavior. Please read the Rustonomicon before writing unsafe code. After the warning was a lis…
I often write programs that have unsafe code. However, the unsafe code is never more than 100 lines, which means I have a very small amount of code to reason about — Rust users expect (of course, you as a programmer has to enforce) that it should be possible to cause UB from safe code, so my “safe interface” to my unsafe code ensures my code can’t cause UB, no matter what I call.
On problem with Rust is generally when you mess up it panics — I think that’s better than buffer overflows and the like, but still not a good user experience.
This means there is a very small amount of code I have to really think about, while in C or C++, basically any place x[i] appears (regardless of if x is a pointer or a std::vector).
You can of course write safe C code, people do, but it’s hard, and it only takes one slip up anywhere in your program to blow it.
Re: Catch-23: The New C Standard Sets the World on Fire
#178Earlier quoted context omitted.
> all you have to do to avoid UB on signed integer overflow is check for overflow before doing the operation (and C23 finally adds features to do that for you). …making your code practically unreadable, since you have to write ckd_add(ckd_add(ckd_mul(a,a),ckd_mul(ckd_mul(2,a),b)),ckd_mul(b,b)) instead of a * a + 2 * a * b + b * b.
That's not the correct syntax for the ckd_ operations. They take 3 operands, the first being a pointer to an integer where the result should be stored. And they return a bool, which you need to check in a conditional. If you're just going to throw out the bool and ignore the overflows, why bother with checked operations in the first place?
int aa,twoa,twoab,bb,aaplustwoab,aaplustwoabplusbb;
if (ckd_mul(a,a,&aa)) { return error; }
if (ckd_mul(2,a,&twoa)) { return error; }
// …
if (ckd_add(aaplustwoab,bb,aaplustwoabplusbb)) { return error; }
return aaplustwoabplusbb;
So ergonomic!> If you're just going to throw out the bool and ignore the overflows, why bother with checked operations in the first place?
I'd expect the functions to return the result on success and crash on failure. Or better, raise an exception, but C doesn't have exceptions…
Re: Catch-23: The New C Standard Sets the World on Fire
#179This is written with quite a lot of hyperbole. The predominant focus is realloc(pre,0) becoming UB instead of what the author misleadingly describes as useful, consistent behaviour. It is far from that, and that’s the entire reason that it was declared UB in the first place: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf . Note that this wasn’t a proposal to change something, it’s a defect report: the ori…
Wrong. UB never happens. That is the promise the program writer makes to the compiler. UB never happens. A correct C program never executes UB. This allows the compiler to assume that anything that is UB never happens. Does some branch of your program unconditionally execute realloc(..., 0) after constant propagation? That branch never happens and can just be deleted.
Reading the defect report, they state "Classifying a call to realloc with a size of 0 as undefined behavior would allow POSIX to define the otherwise undefined behavior however they please." which is wrong. UB cannot be defined, if you define it, you are no longer writing standard C. It should instead have been classified as "implementation-defined behaviour".
In any case it's not that hard to just write a sane wrapper. This one is placed in the Public Domain:
void *sane_realloc(void *ptr, size_t sz)
{
if (sz == 0) {
free(ptr); /*free(NULL) is no-op*/
return NULL;
}
if (ptr == NULL) {
return malloc(sz);
}
return realloc(ptr, sz);
}
I am calling it sane and not safe, because it is not safe. You still have the confusion of what happens when the function returns NULL (was it allocation failure or did we free the object?) - check errno. However, it has the same fully defined semantics on most all implementations and acts like people would expect.You may be tempted to make the function return the value of errno, mark it [[nodiscard]] and take a pointer-to-pointer-to-void, so that the value of the pointer will only be changed if the reallocation was successful. I am not sure if that is safer. You are trading one possible bug - null pointer on allocation failure, which then will cause a segmentation fault for another - stale pointer on allocation failure, but with updated size. The latter is more likely to be used in buffer overflow attacks than the former.
Re: Catch-23: The New C Standard Sets the World on Fire
#180Earlier quoted context omitted.
That sounds good in theory, but many things that are UB in C/C++ are UB because they are really hard to verify at compile time which makes them almost impossible to program around. Any signed addition in C is potential UB unless you have a proof that all numbers that will ever be input to the addition won't cause overflow (which is made harder because C doesn't define the size of the default integer types). Furthermo…
> many things that are UB in C/C++ are UB because they are really hard to verify at compile time which makes them almost impossible to program around The second half of the sentence doesn't follow from the first. Take everyone's favorite example, signed integer overflow: all you have to do to avoid UB on signed integer overflow is check for overflow before doing the operation (and C23 finally adds features to do that…
All you have to do is add a check for overflow _that the compiler will not throw away because "UB won't happen"_. The very thing you want to avoid makes avoiding it very hard, and lots of bugs have resulted from compilers "optimizing" away such overflow checks.