Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
dick traceroute
Feb 24, 2010

Open the pod bay doors, Hal.
Grimey Drawer

fritz posted:

Is this a bit. If you're doing a bit you have to tell us.

are you a cop

Adbot
ADBOT LOVES YOU

taqueso
Mar 8, 2004


:911:
:wookie: :thermidor: :wookie:
:dehumanize:

:pirate::hf::tinfoil:

Why does C++ only have 2 plusses at this point? It should be 30 or 40.

xtal
Jan 9, 2011

by Fluffdaddy

taqueso posted:

Why does C++ only have 2 plusses at this point? It should be 30 or 40.

my friend, the language you seek is C#

fritz
Jul 26, 2003

taqueso posted:

Why does C++ only have 2 plusses at this point? It should be 30 or 40.

C++20 or C20++

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
I always got C++98 mixed up with C99

redleader
Aug 18, 2005

Engage according to operational parameters

QuarkJets posted:

If you want c++ to die then it may be counterproductive to create two of them

it worked to blunt the momentum of python!

QuarkJets
Sep 8, 2008

redleader posted:

it worked to blunt the momentum of python!

It's not really killing Python though, it's just created a newer, popular Python and an older Python that grognards will keep using forever.

Zopotantor
Feb 24, 2013

...und ist er drin dann lassen wir ihn niemals wieder raus...

fritz posted:

C++20 or C20++

C(++)20 or C+=20

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

qsvui posted:

YOU DON'T PAY FOR WHAT YOU DON'T USE

This is now fusing in my head with baby shampoo NO MORE TEARS.

fritz
Jul 26, 2003

qsvui posted:

YOU DON'T PAY FOR WHAT YOU DON'T USE

YOU DON'T PAY FOR THE WHOLE SEAT BECAUSE YOU'LL ONLY NEED THE EDGE

Ghost of Reagan Past
Oct 7, 2003

rock and roll fun
Good coding horror.

In YAML, you have the null value. Python YAML libraries, smartly, load this as None. A dev needed to pass a null value to a feature in Django, and added None to the YAML. Django raised a shitfit, because the string 'None' is not the same as None. So what did this developer do?

Thought this was a bug in Django and added middleware to support this, and implemented it in a way that results in incorrect behavior. And then I spent an hour smashing my head against why it was throwing this weird error and not working when I needed to set that value to one in the Django docs.

She refuses to remove the middleware and wants me to make a PR to fix it. And the director of engineering doesn't want to remove it because he thinks it's "good" to support the string 'None'. I will have wasted at least three hours on this by the time all is said and done because someone misread the docs and misunderstood YAML and nobody caught them :suicide:

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.
Did you honestly expect a different response? Did you really?

In any case, :sever: !

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Xarn posted:

Speaking of C++, I am going to crosspost this from the C++ thread. https://godbolt.org/z/P3qvPN

Is this something to do with static initialization weirdness?

nielsm
Jun 1, 2009



Munkeymon posted:

Is this something to do with static initialization weirdness?

What I assume is happening:
There is only one way the static function variable can get a value (it's static so it's not visible outside the translation unit). Since main() does not check that it's a valid value (not nullptr), the compiler is allowed to assume the variable does have a valid value, anything else would be undefined behavior. So with only one possible valid value, the compiler just assigns that to the static initialization.

Theoretically, something else linked into the program (which the compiler can't know of) could be calling the NeverCalled() function in a static initializer, causing the variable to be properly initialized.

b0lt
Apr 29, 2005

Munkeymon posted:

Is this something to do with static initialization weirdness?

It's undefined behavior: calling nullptr is UB and there's no way for the function pointer to be set from outside because it's static, so the compiler can legally assume that NeverCalled actually does get called (e.g. by a static initializer in another object file) and then inlines everything.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Munkeymon posted:

Is this something to do with static initialization weirdness?

No, it's a pretty straightforward example of how writing undefined behaviour can give you undesired results.

Your program is not allowed to have undefined behaviour. Invoking Do() before it has a value assigned to it would be undefined behaviour, which your program is not allowed to have. So, since absolutely no valid program could possibly invoke Do() before it has a value assigned to it, the compiler can do whatever it likes with the value of Do up until that point - including prematurely setting it to the only thing that it could ever possibly be set to (and replacing the function that does the setting with a no-op).

Jewel
May 2, 2009

Jabor posted:

No, it's a pretty straightforward example of how writing undefined behaviour can give you undesired results.

Your program is not allowed to have undefined behaviour. Invoking Do() before it has a value assigned to it would be undefined behaviour, which your program is not allowed to have. So, since absolutely no valid program could possibly invoke Do() before it has a value assigned to it, the compiler can do whatever it likes with the value of Do up until that point - including prematurely setting it to the only thing that it could ever possibly be set to (and replacing the function that does the setting with a no-op).

A question because I'm a little confused; why does setting "static Function Do = nullptr;" still give UB? If you set "Do = nullptr" within main it works as expected, but not during declaration?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Jewel posted:

A question because I'm a little confused; why does setting "static Function Do = nullptr;" still give UB? If you set "Do = nullptr" within main it works as expected, but not during declaration?

Calling nullptr is undefined behaviour. Any sequence of characters that ends up calling nullptr is not a correct C++ program.

One of the possible outcomes of a program that contains undefined behaviour is that it behaves similarly to how a correct C++ program would behave - but you can't rely on it doing that. Perhaps if you set it a different optimization level, or you updated the compiler to one that ran optimization passes in a different order, it would start doing something rather more unexpected.

Ghost of Reagan Past
Oct 7, 2003

rock and roll fun

Sagacity posted:

Did you honestly expect a different response? Did you really?

In any case, :sever: !
No of course I didn't expect a different response and I'm loving on that :sever: poo poo.

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...
Am I the only one who is horrified by this and thinks that -O3 should not silently inline "well duh obviously they meant this" results without some sort of "yes I know this looks bad but it's going to be set beforehand, it's fine" keyword? If you're not legally allowed to create a program with undefined behavior, maybe the compiler should yell at you a little and require you specifically override it?

I know that would just end up being a compiler flag that gets stuffed into every call blindly but still. This feels like the exact thing kotlin has the "lateinit" keyword for.

lifg
Dec 4, 2000
<this tag left blank>
Muldoon

Ghost of Reagan Past posted:

Good coding horror.

In YAML, you have the null value. Python YAML libraries, smartly, load this as None. A dev needed to pass a null value to a feature in Django, and added None to the YAML. Django raised a shitfit, because the string 'None' is not the same as None. So what did this developer do?

Thought this was a bug in Django and added middleware to support this, and implemented it in a way that results in incorrect behavior. And then I spent an hour smashing my head against why it was throwing this weird error and not working when I needed to set that value to one in the Django docs.

She refuses to remove the middleware and wants me to make a PR to fix it. And the director of engineering doesn't want to remove it because he thinks it's "good" to support the string 'None'. I will have wasted at least three hours on this by the time all is said and done because someone misread the docs and misunderstood YAML and nobody caught them :suicide:

The more I read about YAML the more I think it was a mistake.

Athas
Aug 6, 2007

fuck that joker

Volmarias posted:

Am I the only one who is horrified by this and thinks that -O3 should not silently inline "well duh obviously they meant this" results without some sort of "yes I know this looks bad but it's going to be set beforehand, it's fine" keyword? If you're not legally allowed to create a program with undefined behavior, maybe the compiler should yell at you a little and require you specifically override it?

The compiler doesn't look at the program the way a human does, and it doesn't have some demonic logic engine for carefully exploiting undefined behaviour in as nasty a way as possible.

My guess is that in this case, the compiler has an optimisation rule that says that if the program contains an uninitialised variable, and that variable is only ever set to a single value in the entire program, just initialise the variable with that value in the first place. It is undefined behaviour that makes this possible, because no valid program would read the variable before it is set to a value anyway.

Edit: this case is a little more tricky, because the value is initialised (to nullptr), but the compiler sees that this value is not valid anywhere the variable is actually used, so clearly no conforming program is going to use it.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Yes. If you add a second setter you can see that the compiler does not make that same inference.

https://godbolt.org/z/W7Kznc

Jewel posted:

A question because I'm a little confused; why does setting "static Function Do = nullptr;" still give UB? If you set "Do = nullptr" within main it works as expected, but not during declaration?

statics are always initialized to 0 / nullptr. Setting it twice likely does the same thing as above where the compiler is now unsure about it being only ever set to one possible value, and doesn't make the same guess. Compiler optimizations are fragile.

Xarn
Jun 26, 2015

nielsm posted:

What I assume is happening:
There is only one way the static function variable can get a value (it's static so it's not visible outside the translation unit). Since main() does not check that it's a valid value (not nullptr), the compiler is allowed to assume the variable does have a valid value, anything else would be undefined behavior. So with only one possible valid value, the compiler just assigns that to the static initialization.

Theoretically, something else linked into the program (which the compiler can't know of) could be calling the NeverCalled() function in a static initializer, causing the variable to be properly initialized.

Yup, this is 100% correct.

Volmarias posted:

Am I the only one who is horrified by this and thinks that -O3 should not silently inline "well duh obviously they meant this" results without some sort of "yes I know this looks bad but it's going to be set beforehand, it's fine" keyword? If you're not legally allowed to create a program with undefined behavior, maybe the compiler should yell at you a little and require you specifically override it?

I know that would just end up being a compiler flag that gets stuffed into every call blindly but still. This feels like the exact thing kotlin has the "lateinit" keyword for.

You are not, but I find that most people who complain do not understand why this actually happens. :v:

This whole "let's mangle the code to something different" is not motivated by the compiler being a sadistic rear end in a top hat, nor by the compiler writers being sadistic assholes, but by compilers trying to extract every possible bit of information about the code to better optimize it. However, this also means that any kind of "warn when optimizing by avoiding UB" flag/option would be unusably noisy, because it happens all the time, and usually we do want it to happen.

Consider trivial example:
C++ code:
void debug_print(int* ptr) {
    if (!ptr) {
        std::printf("{nullptr}");
    } else {
        std::printf("%d", *ptr);
    }
}

void frobnicate(int& number) {
    // bwah, something is going to poo poo, let me debug print this
    debug_print(&number);
    
    // actual frobnication...
}
It is quite likely that if you enable optimizations your compiler's optimizer will inline debug_print into frobnicate. Then, assuming your compiler's optimizer is not complete and utter shite, it will simplify the inlined body to just std::printf("%d", number);. If my compiler did not do the simplification after inlining, I would file a bug report...

... but for this optimization to happen, the compiler already had to reason about UB, and assume that it does not happen. If it did not, it would have to allow for null-reference, and could not prune out the branches in inlined body of debug_print.

NtotheTC
Dec 31, 2007


Ghost of Reagan Past posted:

Good coding horror.

In YAML, you have the null value. Python YAML libraries, smartly, load this as None. A dev needed to pass a null value to a feature in Django, and added None to the YAML. Django raised a shitfit, because the string 'None' is not the same as None. So what did this developer do?

Thought this was a bug in Django and added middleware to support this, and implemented it in a way that results in incorrect behavior. And then I spent an hour smashing my head against why it was throwing this weird error and not working when I needed to set that value to one in the Django docs.

She refuses to remove the middleware and wants me to make a PR to fix it. And the director of engineering doesn't want to remove it because he thinks it's "good" to support the string 'None'. I will have wasted at least three hours on this by the time all is said and done because someone misread the docs and misunderstood YAML and nobody caught them :suicide:

In this nest of horrors, the one that pisses me off the most is that she created a middleware for this. Is this a "only tool is a hammer" situation or are serialisers a dirty word where you work?

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
also recommend reading https://gist.github.com/rygorous/e0f055bfb74e3d5f0af20690759de5a7

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

lifg posted:

The more I read about YAML the more I think it was a mistake.

YAML has lots of problems, but I don't think it's particularly egregious in this case.

Tei
Feb 19, 2011
Probation
Can't post for 4 days!
I believe YAML is for simple configuration systems for quick and dirty applications. If you are using it for something else than that, heres your problem. You are the problem.

b0lt
Apr 29, 2005

Athas posted:

The compiler doesn't look at the program the way a human does, and it doesn't have some demonic logic engine for carefully exploiting undefined behaviour in as nasty a way as possible.

My guess is that in this case, the compiler has an optimisation rule that says that if the program contains an uninitialised variable, and that variable is only ever set to a single value in the entire program, just initialise the variable with that value in the first place. It is undefined behaviour that makes this possible, because no valid program would read the variable before it is set to a value anyway.

Edit: this case is a little more tricky, because the value is initialised (to nullptr), but the compiler sees that this value is not valid anywhere the variable is actually used, so clearly no conforming program is going to use it.

Variables with static lifetime are zero-initialized if not initialized explicitly, so it's purely relying on "calling nullptr is UB".

Additional crazy UB: infinite loops without side effects are UB.

Athas
Aug 6, 2007

fuck that joker

Coincidentally, my job is writing a compiler that generates C code, and the other day I had my first bug due to signed integer multiplication overflow being compiled in an interesting way by the C compiler. My solution was to actually compile all signed integer addition/subtraction/multiplications as unsigned, since this is well-defined. (I was a bit uncertain about the conversion back from unsigned to signed, but I think that's implementation-defined rather than undefined in case of overflow.) I still need to handle some division edge cases - isn't INT_MAX/-1 undefined behaviour, too?

Is there a clean way to get twos-complement overflow behaviour in C? I'm OK with implementation-defined behaviour, as long as it's very widely supported, but I'd rather stay away from anything that involves adding more command line options to the C compiler.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Command line options are your best bet.

Xarn
Jun 26, 2015
-fwrapv and hope that your compiler does not contain any bugs when it just ignores it :v: (I would generally assume it doesn't contain any more bugs in that than in other common flags, as this particular dialect seems fairly common)

b0lt
Apr 29, 2005

Athas posted:

Coincidentally, my job is writing a compiler that generates C code, and the other day I had my first bug due to signed integer multiplication overflow being compiled in an interesting way by the C compiler. My solution was to actually compile all signed integer addition/subtraction/multiplications as unsigned, since this is well-defined. (I was a bit uncertain about the conversion back from unsigned to signed, but I think that's implementation-defined rather than undefined in case of overflow.) I still need to handle some division edge cases - isn't INT_MAX/-1 undefined behaviour, too?

Is there a clean way to get twos-complement overflow behaviour in C? I'm OK with implementation-defined behaviour, as long as it's very widely supported, but I'd rather stay away from anything that involves adding more command line options to the C compiler.

If you're generating code, you can just cast to unsigned, do your operation, and cast back: technically this can fail to roundtrip if you're on some esoteric system with trap representations or something, but in practice it'll work.

(There's also the slight problem that signed and unsigned multiplication aren't equivalent like addition or subtraction)

Athas
Aug 6, 2007

fuck that joker

b0lt posted:

If you're generating code, you can just cast to unsigned, do your operation, and cast back: technically this can fail to roundtrip if you're on some esoteric system with trap representations or something, but in practice it'll work.

What about division? Here signed and unsigned has different rounding characteristics.

b0lt posted:

(There's also the slight problem that signed and unsigned multiplication aren't equivalent like addition or subtraction)

Wait, what? Explain. Not even LLVM distinguishes signed and unsigned integer multiplication, and I can't think of why there would ever be a difference.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

QuarkJets posted:

It's not really killing Python though, it's just created a newer, popular Python and an older Python that grognards will keep using forever.

Py3k definitely hurt the moment of both languages. I've seen the excuse "well we have to rewrite anyway to move to the new version of Python so we might as well rewrite in the hot new language I want to play with" in quite a few blog posts. It's mostly nonsense, but the 2/3 split provided people who already wanted to move off python a clear exit point that they could use to justify it.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Athas posted:

Wait, what? Explain. Not even LLVM distinguishes signed and unsigned integer multiplication, and I can't think of why there would ever be a difference.

It matters for wide multiplies, and on the machine level some architectures only do wide multiplies, so you see different instructions for e.g. mul and imul on x86.

Arsenic Lupin
Apr 12, 2012

This particularly rapid💨 unintelligible 😖patter💁 isn't generally heard🧏‍♂️, and if it is🤔, it doesn't matter💁.


Zopotantor posted:

Oh hey, a language with strict left-to-right evaluation order and no operator precedence.

Not quite. Left-to-right, yes, but unary messages take precedence over binary messages take precedence over keyword messages. This matters if you're doing a chain of method invocations.

QuarkJets
Sep 8, 2008

Plorkyeran posted:

Py3k definitely hurt the moment of both languages. I've seen the excuse "well we have to rewrite anyway to move to the new version of Python so we might as well rewrite in the hot new language I want to play with" in quite a few blog posts. It's mostly nonsense, but the 2/3 split provided people who already wanted to move off python a clear exit point that they could use to justify it.

Sure, I'm just saying that the momentum loss was nothing like a death blow. It's like throwing a pencil at a freight train

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?
Undefined behavior can have its uses, but sometimes you just feel the standards committee got lazy. These are all (allegedly) UB in c:

quote:

A nonempty source file does not end in a new-line character which is not immediately preceded by a backslash character or ends in a partial preprocessing token or comment

A character not in the basic source character set is encountered in a source file, except in an identifier, a character constant, a string literal, a header name, a comment, or a preprocessing token that is never converted to a token

An unmatched ’ or ” character is encountered on a logical source line during tokenization

A reserved keyword token is used in translation phase 7 or 8 for some purpose other than as a keyword

The initial character of an identifier is a universal character name designating a digit

The identifier __func__ is explicitly declared

A structure or union is defined as containing no named members, no anonymous structures, and no anonymous unions

The specification of a function type includes any type qualifiers

Two identifiers differ only in nonsignificant characters

Adbot
ADBOT LOVES YOU

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Well, some of those are understandable, actually. If you’re going to have non-significant characters in identifiers, there’s not really any way to describe what might happen to a program that contains conflicts except UB — an identifier might resolve unexpectedly to a macro, calls might go to the wrong function or use the wrong type signature, etc. Same thing with reserved keywords — if your program is suddenly interpreted differently, it might have UB. The lexing violations, though, I dunno; always felt like they were standardizing that some compilers might have weird bugs.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply