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
Munkeymon
Aug 14, 2003

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



Volte posted:

Depends on what the constants are for. If they are version-dependent and loaded from a JSON file or even from the web (e.g., the loot tables in Bloodbourne) in practice then it makes sense to abstract them, especially for unit tests. If it just provides the value of pi and e, then it's stupid.

It was created to move stuff out of config files, so now there's an actual file full of public const|static string|int|decimal Thingy = "whatever"; and three layers of stuff between that and the use site :psyduck:

Adbot
ADBOT LOVES YOU

sarehu
Apr 20, 2007

(call/cc call/cc)

Athas posted:

It seems to me that if you want to exploit platform-dependent quirks, which is fine (I do it all the time), don't use a general-purpose compiler. Write in assembly or use a specialised (or properly configured) C compiler that knows about the dialect of C that you want to code in.

I think you've lost track of the proposal in question, which is to replace embedded compilers with a modern compiler (i.e. Clang). This is bad because it would break all the existing code.

Athas posted:

Again, that's not really how compilers work. Removing NULL-checks and branch checks are enabling optimisations that usually do not contribute a great deal, but can simplify control flow, resulting in fewer basic blocks (or whatever), which can enable very important optimisations like vectorisation and all sorts of other things.

For scientific computing maybe, but if you're shipping software, an unstable optimization like that is not important. Replicable behavior from compiler version to compiler version is what's important. So you can keep your dereference-implies-not-null assumptions in user space, where it is true, but on systems where byte 0 is accessible, it should be off by default.

KaneTW
Dec 2, 2011

We should all switch to that one Coq-verified compiler. Every optimization needs to be proven correct. and it's required to specify required assumptions

Vanadium
Jan 8, 2005

If you're storing things at address 0 you should probably fork over for a C implementation that uses a diferent bit pattern for the NULL pointer. :psyduck:

Athas
Aug 6, 2007

fuck that joker

KaneTW posted:

We should all switch to that one Coq-verified compiler. Every optimization needs to be proven correct. and it's required to specify required assumptions

Compcert would still be able to make optimisations based on undefined behaviour in the source program. It wouldn't make a difference in this case.

feedmegin
Jul 30, 2008

Vanadium posted:

If you're storing things at address 0 you should probably fork over for a C implementation that uses a diferent bit pattern for the NULL pointer. :psyduck:

In the embedded world there is often only one compiler and its a crusty version of gcc.

Xarn
Jun 26, 2015

Athas posted:

Compcert would still be able to make optimisations based on undefined behaviour in the source program. It wouldn't make a difference in this case.

It would be able to, but it wouldn't (because its optimizer sucks :ssh:)

brap
Aug 23, 2004

Grimey Drawer

Vanadium posted:

If you're storing things at address 0 you should probably fork over for a C implementation that uses a diferent bit pattern for the NULL pointer. :psyduck:

Yeah, this isn't really something you can choose on many embedded systems. The hardware has an address where it expects to find a call to the handler for a certain interrupt and it's hard coded.

sarehu
Apr 20, 2007

(call/cc call/cc)
Can't wait until some EE tries to get around their newfangled broken Clang compiler with this workaround for dereferencing null pointers:

code:
struct s { uint32_t x; uint32_t y; };

uint32_t read_nulladdr(uint32_t *x) {
  if (x == NULL) {
    x--;
    struct s tmp = *(struct s *)x;
    return tmp.y;
  } else {
    return *x;
  }
}
Take that, clang!

P.S. here's what clang -O3 (edit: or -O1) outputs:

code:
0000000000000000 <read_nulladdr>:
   0:	8b 07                	mov    (%rdi),%eax
   2:	c3                   	retq   

sarehu fucked around with this message at 21:47 on Oct 29, 2015

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
C code:
uint32_t read_nulladdr(uint32_t *x) {
  return *(volatile uint32_t *) x;
}

sarehu
Apr 20, 2007

(call/cc call/cc)
I just tried writing

code:
uint32_t foo(uint32_t *y) {
  uint32_t x = read_nulladdr(y);
  if (y == NULL) {
    printf("hey hey hey!  hey hey hey hey!\n");
  }
  return x;
}

uint32_t bar(uint32_t *y) {
  uint32_t x = *y;
  if (y == NULL) {
    printf("hey hey hey!  hey hey hey hey!\n");
  }
  return x;
}
and clang still generates the null check and branch in both cases. I'm disappoint, such suboptimal compiler. GCC on the other hand gives:

code:
0000000000000000 <read_nulladdr>:
   0:	48 85 ff             	test   %rdi,%rdi
   3:	74 0b                	je     10 <read_nulladdr+0x10>
   5:	8b 07                	mov    (%rdi),%eax
   7:	c3                   	retq   
   8:	0f 1f 84 00 00 00 00 	nopl   0x0(%rax,%rax,1)
   f:	00 
  10:	8b 04 25 00 00 00 00 	mov    0x0,%eax
  17:	0f 0b                	ud2    
  19:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)

0000000000000020 <foo>:
  20:	48 85 ff             	test   %rdi,%rdi
  23:	74 0b                	je     30 <foo+0x10>
  25:	8b 07                	mov    (%rdi),%eax
  27:	c3                   	retq   
  28:	0f 1f 84 00 00 00 00 	nopl   0x0(%rax,%rax,1)
  2f:	00 
  30:	8b 04 25 00 00 00 00 	mov    0x0,%eax
  37:	0f 0b                	ud2    
  39:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)

0000000000000040 <bar>:
  40:	8b 07                	mov    (%rdi),%eax
  42:	c3                   	retq   
So uh... I guess it works? The test is still there!

Works better than volatile uint32_t * anyway...

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Sorry, what exactly is wrong with that use of volatile? The sole purpose of C volatile is to serve as a "shut up and do exactly what I'm telling you to do" tool. Your workaround, on the other hand, is just waiting for a slightly smarter compiler to miscompile it.

sarehu
Apr 20, 2007

(call/cc call/cc)

rjmccall posted:

Sorry, what exactly is wrong with that use of volatile? The sole purpose of C volatile is to serve as a "shut up and do exactly what I'm telling you to do" tool. Your workaround, on the other hand, is just waiting for a slightly smarter compiler to miscompile it.

(In gcc) it doesn't prevent the null check from being optimized away. Such as in

code:
uint32_t bar(uint32_t *y) {
  uint32_t x = *(volatile uint32_t *)y;
  if (y == NULL) {
    printf("hey hey hey!  hey hey hey hey!\n");  /* woof */
  }
  return x;
}

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

rjmccall posted:

The sole purpose of C volatile is to serve as a "shut up and do exactly what I'm telling you to do" tool

Does this actually work all the time? For some reason I had it in my head that compilers were still allowed to elide stores to a given volatile variable when they could prove there were no loads from that volatile variable thereafter - a pretty evil thing to do IMO, could really gently caress you over with SFRs and suchlike, but I'm not a compiler guy.

Plorkyeran
Mar 22, 2007

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

Blotto Skorzany posted:

Does this actually work all the time? For some reason I had it in my head that compilers were still allowed to elide stores to a given volatile variable when they could prove there were no loads from that volatile variable thereafter - a pretty evil thing to do IMO, could really gently caress you over with SFRs and suchlike, but I'm not a compiler guy.

That would completely defeat the point. Some of the things volatile is for will never have loads from the volatile, because they're write-only...

sarehu
Apr 20, 2007

(call/cc call/cc)
This'll force the null check. I mean in GCC, don't ask me about the C standard.
code:
uint32_t bar2(uint32_t *y) {
  uint32_t x = *y;
  if (*(uint32_t *volatile*)&y == NULL) {
    printf("hey hey hey!  hey hey hey hey!\n");  /* woof */
  }
  return x;
}
Edit: Also this:
code:
uint32_t read_nulladdr(uint32_t *x) {
  return **(uint32_t *volatile*)&x;
}

sarehu fucked around with this message at 22:15 on Oct 29, 2015

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Plorkyeran posted:

That would completely defeat the point. Some of the things volatile is for will never have loads from the volatile, because they're write-only...

Right, I get that, I just had it in the back of my head (from an LLVM project blog post, I think, but I may be misremembering) that the standard allowed it to happen and my mental image of a typical compiler writer as a sort of combination of a mustache-twirling villain from a Vaudeville melodrama, Comic Book Guy and Hermes Conrad makes it seem plausible that if this freedom exists someone will use it.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Today I learned that on 2 European versions of one model of popular Android phone, the runtime sometimes doesn't find certain methods in our application. :suicide:

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

sarehu posted:

(In gcc) it doesn't prevent the null check from being optimized away.

Bugs like that are just waiting to become some sort of security issue anyway. Kernel programmers like to obsess about the compiler's role here over the twenty broken things that led to that exploit because arguing about C semantics is a lot more fun than admitting that a bunch of kernel programmers made a long series of embarrassing mistakes.

Blotto Skorzany posted:

Does this actually work all the time? For some reason I had it in my head that compilers were still allowed to elide stores to a given volatile variable when they could prove there were no loads from that volatile variable thereafter - a pretty evil thing to do IMO, could really gently caress you over with SFRs and suchlike, but I'm not a compiler guy.

In general, compiler writers have no incentives to try to optimize volatile accesses. It's almost always going to mess up some obscure corner case — either some weird embedded / memory-mapped-I/O thing (and believe it or not, there are a lot of viable and successful embedded projects using Clang with standard optimizations enabled, which I know because part of my job is to support them), or something with setjmp/longjmp, or something else — and there is no significant pool of programmers heavily using volatile and complaining that their code isn't being optimized very well.

Some people on Clang used to argue (five years ago?) that it was valid to infer that volatile accesses to local variables did not have crazy side effects and could be removed, and they were eventually convinced that making that argument was just not worth the trouble.

Oh, the other reasonable approach to mapping things to address zero is to make them an external global and then just tell the linker to put that at address zero. EDIT: this will probably lead to weird results like &interrupt_table != NULL having an unspecified result, but that is probably not something you end up writing in practice, which makes it generally good enough for embedded programming.

rjmccall fucked around with this message at 22:34 on Oct 29, 2015

Vanadium
Jan 8, 2005

fleshweasel posted:

Yeah, this isn't really something you can choose on many embedded systems. The hardware has an address where it expects to find a call to the handler for a certain interrupt and it's hard coded.

Then blame your C impl for representing the "not a valid pointer" value with the same bit pattern as the interrupt table address, not for emitting code based on totally legit assumptions like "the not-a-valid-pointer value is not a valid pointer"!

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Subjunctive posted:

Today I learned that on 2 European versions of one model of popular Android phone, the runtime sometimes doesn't find certain methods in our application. :suicide:

Blame Unicode.

Dylan16807
May 12, 2010

rjmccall posted:

Bugs like that are just waiting to become some sort of security issue anyway. Kernel programmers like to obsess about the compiler's role here over the twenty broken things that led to that exploit because arguing about C semantics is a lot more fun than admitting that a bunch of kernel programmers made a long series of embarrassing mistakes.
When they dereference the pointer before a null check, sure. That's their problem.

But it's a lot harder to defend it being undefined to construct such a pointer without ever using it. Are there architectures where that flexibility even helps?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Dylan16807 posted:

But it's a lot harder to defend it being undefined to construct such a pointer without ever using it.

It's a good thing that nobody's actually defending this then (mostly because it's not true, and everyone agrees that it would be really dumb if assigning null to a pointer was undefined behaviour).

Dylan16807
May 12, 2010

Jabor posted:

It's a good thing that nobody's actually defending this then (mostly because it's not true, and everyone agrees that it would be really dumb if assigning null to a pointer was undefined behaviour).
I'm sorry, I was unclear.

I lost part of my post when I was rewording. "such a pointer" was talking about a pointer inside a struct, like the original example. If the base pointer is null, then it's undefined to add an offset, or do any other kind of arithmetic to it.

If you make a pointer to a member before your null check, you invalidate the null check. Dereferencing isn't necessary.

pseudorandom name
May 6, 2007

Dylan16807 posted:

If you make a pointer to a member before your null check, you invalidate the null check. Dereferencing isn't necessary.

That's not the Linux bug in question, are you sure this is true?

Dylan16807
May 12, 2010

pseudorandom name posted:

That's not the Linux bug in question, are you sure this is true?
Pretty sure. C is extremely picky about what you can do with pointers.

pseudorandom name
May 6, 2007

I just checked, neither gcc nor clang delete the NULL check if you do &s->m before if (!s).

clang is even clever enough to realize that if s is NULL than it can just CMOV from the register containing s instead of loading an immediate 0 into another register and CMOVing that.

sarehu
Apr 20, 2007

(call/cc call/cc)

Dylan16807 posted:

When they dereference the pointer before a null check, sure. That's their problem.

But it's a lot harder to defend it being undefined to construct such a pointer without ever using it. Are there architectures where that flexibility even helps?

Yes, there's architectures where forming an invalid pointer will make an exception (like, a processor exception, this ain't C++) happen. So it's undefined behavior in the standard.

Harik
Sep 9, 2001

From the hard streets of Moscow
First dog to touch the stars


Plaster Town Cop
The first time one of my programs crashed with SIGILL on a UB2 instruction threw me for a loop. Once I figured out what happened (dumb brainfart, fell out of a function without returning a value in one branch) I was really happy that it did that instead of going on to be unstable.

In short, thanks rjmccall.

Soricidus
Oct 21, 2010
freedom-hating statist shill

sarehu posted:

Yes, there's architectures where forming an invalid pointer will make an exception (like, a processor exception, this ain't C++) happen. So it's undefined behavior in the standard.

neat, but how do they even tell, surely an invalid pointer is just a number until you try to dereference it? do they have special pointer registers or something?

Athas
Aug 6, 2007

fuck that joker

Soricidus posted:

do they have special pointer registers or something?

Yes, some architectures do.

Also, some architectures (like Itanium) keep a special "valid" bit for each (or some?) registers. This means that reading from an uninitialised variable might trigger an interrupt.

C permits lots of things that are actually exploited on sufficiently weird architectures.

Athas fucked around with this message at 20:48 on Nov 1, 2015

sarehu
Apr 20, 2007

(call/cc call/cc)

Soricidus posted:

do they have special pointer registers or something?

Yeah, x86 does.

Soricidus
Oct 21, 2010
freedom-hating statist shill

sarehu posted:

Yeah, x86 does.

good point, i am enlightened

Death Chicken
Aug 15, 2015
Hidden deep within an ancient codebase, in an abstract class that was implemented once, I found this gem:

code:

for(int i = 400; i < 9999999; i++)
{
	Field bound_check= Integer.class.getDeclaredField("value");
        bound_check.setAccessible(true);
        bound_check.set(i, 400); //prevent customer tampering with combobox indexes
}
 
This is not the way you sanitize input.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
More level-headed and respectful criticism of open source contributions from Linus.

http://lkml.iu.edu/hypermail/linux/kernel/1510.3/02866.html

Drastic Actions
Apr 7, 2009

FUCK YOU!
GET PUMPED!
Nap Ghost

Hammerite posted:

More level-headed and respectful criticism of open source contributions from Linus.

http://lkml.iu.edu/hypermail/linux/kernel/1510.3/02866.html



From Gizmodo, who truly knows lovely code.

senrath
Nov 4, 2009

Look Professor, a destruct switch!


Hammerite posted:

More level-headed and respectful criticism of open source contributions from Linus.

http://lkml.iu.edu/hypermail/linux/kernel/1510.3/02866.html

Apparently Linus self-censors after the fact? Because there's instances of both sh*t and poo poo.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Hammerite posted:

More level-headed and respectful criticism of open source contributions from Linus.

http://lkml.iu.edu/hypermail/linux/kernel/1510.3/02866.html

I'm surprised more people don't pull an Alan Cox after this sort of semiliterate dressing-down

quote:

I've been working on fixing it. I have spent a huge amount of time
working on the tty stuff trying to gradually get it sane without breaking
anything and fixing security holes along the way as they came up. I spent
the past two evenings working on the tty regressions.

However I've had enough. If you think that problem is easy to fix you fix
it.

Have fun.

I've zapped the tty merge queue so anyone with patches for the tty layer
can send them to the new maintainer.

--- MAINTAINERS~ 2009-07-23 15:36:41.000000000 +0100
+++ MAINTAINERS 2009-07-28 20:09:32.200685827 +0100
@@ -5815,10 +5815,7 @@
S: Maintained

TTY LAYER
-P: Alan Cox
-M: alan@lxorguk.ukuu.org.uk
-S: Maintained
-T: stgit http://zeniv.linux.org.uk/~alan/ttydev/
+S: Unmaintained
F: drivers/char/tty_*
F: drivers/serial/serial_core.c
F: include/linux/serial_core.h

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
I actually find the overflow_usub version easier to read.

Adbot
ADBOT LOVES YOU

Kazinsal
Dec 13, 2011

Suspicious Dish posted:

I actually find the overflow_usub version easier to read.

So do I. And if Torvalds is complaining about too many helper functions that no one knows what they do, he should just delete the Linux git repo and start over, because the kernel is loving full of them.

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