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
Foxfire_
Nov 8, 2010

I was wrong about the ordering thing! Standard lets you put the pointer argument and integral argument in either order as long as there's exactly one of each.

Forming an invalid pointer is definetly undefined though.

C0x 6.5.6 posted:

When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand.

If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression.

In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)−N (where N has the value n) point to, respectively, the i+n-th and i-n-th elements of the array object, provided they exist.

Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)−1 points to the last element of the array object.

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow;

otherwise, the behavior is undefined.

And from the rationale doc since that's hard to parse

C0x Rationale 6.5.6 1171 posted:

Any pointer arithmetic that takes a pointer outside of the pointed-to object (apart from the one past exception)
is undefined behavior. There is no requirement that the pointer be dereferenced; creating it within a
subexpression is sufficient.

It gives a Motorola 56000 as an example of a real processor still in use where invalid addresses will fault in a footnote.

Adbot
ADBOT LOVES YOU

comedyblissoption
Mar 15, 2006

If you try to clean it up, remember that not all days have 24 hours.

Spatial
Nov 15, 2007

I wish language lawyers wouldn't pop out of the woodwork trying to one-up each other every time C is mentioned. Keep it in your pants please.

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe

comedyblissoption posted:

If you try to clean it up, remember that not all days have 24 hours.

Days have a defined capacity and there are no rules about 24 hour when overbooking

Absurd Alhazred
Mar 27, 2010

by Athanatos

Spatial posted:

I wish language lawyers wouldn't pop out of the woodwork trying to one-up each other every time C is mentioned. Keep it in your pants please.

I actually enjoy those arguments because I always learn something new. :shobon:

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Spatial posted:

I wish language lawyers wouldn't pop out of the woodwork trying to one-up each other every time C is mentioned. Keep it in your pants please.

lol no

Anyway, the restriction people keep quoting is specifically about pointer arithmetic, and it only prevents you from using pointer arithmetic to exceeds the bounds of an object (where those bounds include the one-past-the-end pointer), primarily as a way to allow the compiler to assume that subscripting into an array does not alias arbitrary other memory. It is not a general prohibition against forming or having a pointer that does not point at anything. It is of course undefined behavior to dereference a pointer that does not validly point to an object, outside of the specific exception for &*. The only general restriction on pointer values is that you cannot legally create a pointer that is less aligned than its pointee type; that is a rule that compilers are usually lax about until you actually use it to access the underlying memory.

But if you cast 7 to a pointer type, that is legal (assuming the pointee type is byte-aligned); and if there happens to be an object of that type at address 7, then it is legal to dereference the resulting pointer; and since compilers generally cannot know statically every possible valid address of an object, it has to let you get away with it. (But null is different.)

Jethro
Jun 1, 2000

I was raised on the dairy, Bitch!
e. no wait, I misread you, you're more or less saying what I said.

ROFLburger
Jan 12, 2006

Spatial posted:

I wish language lawyers wouldn't pop out of the woodwork trying to one-up each other every time C is mentioned. Keep it in your pants please.

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

Spatial posted:

I wish language lawyers wouldn't pop out of the woodwork trying to one-up each other every time C is mentioned. Keep it in your pants please.

C is the only language with which I can tolerate these talks. It's such a slow moving language with so many weird corners that will *never* be fixed.

JawnV6
Jul 4, 2004

So hot ...

Jabor posted:

For example, merely computing the value can cause an overflow trap if it's outside the allowed range (while if the newly-computed pointer is inside the allowed range, the compiler must ensure that it doesn't overflow).

rjmccall posted:

compilers generally cannot know statically every possible valid address of an object, it has to let you get away with it.
Now I'm confused, why could an index into an object not overflow? That seems like the runtime's job to allocate things, if it puts an object right at the edge of memory or going over, the compiler can't know that indexing the last element would overflow.

Also it's fun that I can't generate pointers outside objects, but the compiler's free to make them and leave them in memory willy nilly.

ThisIsNoZaku
Apr 22, 2013

Pew Pew Pew!
This code had lots of spots where unrecoverable errors are caught and logged, then the methods return unexpected nulls, to blow up elsewhere.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

JawnV6 posted:

Now I'm confused, why could an index into an object not overflow? That seems like the runtime's job to allocate things, if it puts an object right at the edge of memory or going over, the compiler can't know that indexing the last element would overflow.

One past the last element, but yes, the runtime should generally not allocate things all the way up to the end of the address space. Typically this is not a problem because that part of the address space is either not allocable or allocated for something that's normally addressed.

This is required by two rules: one, the end address must compare greater than all the addresses in an arary, and two, it's not allowed to compare equal to null (I think). Of course, null doesn't have to be the zero address, and you don't have to use normal integer comparison to compare pointers, but you'd still have a boundary condition somewhere.

JawnV6 posted:

Also it's fun that I can't generate pointers outside objects, but the compiler's free to make them and leave them in memory willy nilly.

Yep! We do it just to mock your pathetic inability to violate the norms of the language we've trapped you within.

rjmccall fucked around with this message at 23:26 on Jul 26, 2017

idiotmeat
Apr 3, 2010

rjmccall posted:

(But null is different.)
Except on OS390 where NULL can be dereferenced. :doh:

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

idiotmeat posted:

Except on OS390 where NULL can be dereferenced. :doh:

By which you mean it's mapped? A lot of operating systems let you map the zero page; it's not a good idea, but they let you do it. It's still undefined behavior even if it doesn't trap.

We get requests on Clang sporadically to support dereferencing the zero address for some embedded / boot-loader project where zero is actually a significant address (that they often need to address by literal value, no less) and I'm always like, how much feature work exactly would you like us to do to simplify this task for you, and would you actually use that feature if we did it?

rjmccall fucked around with this message at 01:12 on Jul 27, 2017

idiotmeat
Apr 3, 2010
Not mapped - it can always be dereferenced.

john donne
Apr 10, 2016

All suitors of all sorts themselves enthral;

So on his back lies this whale wantoning,

And in his gulf-like throat, sucks everything

That passeth near.
What does it dereference? 0? Undefined behavior?

idiotmeat
Apr 3, 2010

john donne posted:

What does it dereference? 0? Undefined behavior?

There is some OS related structure which is always located at virtual address 0.

Simulated
Sep 28, 2001
Lowtax giveth, and Lowtax taketh away.
College Slice

rjmccall posted:

By which you mean it's mapped? A lot of operating systems let you map the zero page; it's not a good idea, but they let you do it. It's still undefined behavior even if it doesn't trap.

We get requests on Clang sporadically to support dereferencing the zero address for some embedded / boot-loader project where zero is actually a significant address (that they often need to address by literal value, no less) and I'm always like, how much feature work exactly would you like us to do to simplify this task for you, and would you actually use that feature if we did it?

My totally controversial opinion is that the CPU should hardware fault if you attempt to access the first pointer-sized bytes of memory even on embedded hardware without an MMU because seriously... gently caress that. On anything 386-class or newer it should be the entire first page.

Anyone who thinks otherwise is wrong and I condemn to hell CPU and system designers that require use of address zero.

Foxfire_
Nov 8, 2010

rjmccall posted:

lol no

Anyway, the restriction people keep quoting is specifically about pointer arithmetic, and it only prevents you from using pointer arithmetic to exceeds the bounds of an object (where those bounds include the one-past-the-end pointer), primarily as a way to allow the compiler to assume that subscripting into an array does not alias arbitrary other memory. It is not a general prohibition against forming or having a pointer that does not point at anything. It is of course undefined behavior to dereference a pointer that does not validly point to an object, outside of the specific exception for &*. The only general restriction on pointer values is that you cannot legally create a pointer that is less aligned than its pointee type; that is a rule that compilers are usually lax about until you actually use it to access the underlying memory.

But if you cast 7 to a pointer type, that is legal (assuming the pointee type is byte-aligned); and if there happens to be an object of that type at address 7, then it is legal to dereference the resulting pointer; and since compilers generally cannot know statically every possible valid address of an object, it has to let you get away with it. (But null is different.)

I was curious and found this in the section for conversions:

C0x 6.3.2.3 posted:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
Conversion of a null pointer to another pointer type yields a null pointer of that type.
Any two null pointers shall compare equal.
An integer may be converted to any pointer type.
Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

A compiler isn't allowed to refuse to compile char* a = (char*)5; and is supposed to document what it does, but doesn't have to do any particular thing.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Again, unless the compiler knows for certain that there is not a valid object at address 5 — which in general it cannot — it has no choice but to emit the accesses as given. In the absence of undefined behavior, the compiler must implement the abstract machine. The null pointer is a special case precisely because the compiler is allowed to assume that there is never a valid object at that address.

Now, if LLVM sees that you've constructed a constant address like that, it will assume that that pointer does not alias any other sort of declared memory. That is, it assumes that (char*) 0xf00 is not a correct guess of the address of const char *myGlobalString; or int myLocalCount;, even though, yes, it is possible to write a linker script that will force a variable to be loaded at a specific address. Our request is that, if you do have some memory-mapped use case where that's important, you should please use either constant addresses or that kind of linker script but don't awkwardly combine them.

JewKiller 3000
Nov 28, 2006

by Lowtax

Spatial posted:

I wish language lawyers wouldn't pop out of the woodwork trying to one-up each other every time C is mentioned. Keep it in your pants please.

language lawyers are the only reason your certified retarded c code even compiles, much less runs efficiently. how dare you, sir, how dare you.

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
LLVM = Language Lawyer Virtual Machine

LOOK I AM A TURTLE
May 22, 2003

"I'm actually a tortoise."
Grimey Drawer
Better call/cc Saul

Absurd Alhazred
Mar 27, 2010

by Athanatos
Bytecode Legal

Fergus Mac Roich
Nov 5, 2008

Soiled Meat

JewKiller 3000 posted:

language lawyers are the only reason your certified retarded c code even compiles, much less runs efficiently. how dare you, sir, how dare you.

Where can I go to get my C code certified as retarded?

Factor Mystic
Mar 20, 2006

Baby's First Post-Apocalyptic Fiction
Law & Order of operations

ChaosArgate
Oct 10, 2012

Why does everyone think I'm going to get in trouble?

code:
if (!a && !b) {
    if (b) {
        c = true;
    } else {
        c = false;
    }
}
It's obfuscated but I found this in a massive file at work. :psyduck:

fritz
Jul 26, 2003

JawnV6 posted:

Also it's fun that I can't generate pointers outside objects, but the compiler's free to make them and leave them in memory willy nilly.


See also go generics.

idiotmeat
Apr 3, 2010

ChaosArgate posted:

code:
if (!a && !b) {
    if (b) {
        c = true;
    } else {
        c = false;
    }
}
It's obfuscated but I found this in a massive file at work. :psyduck:

Photons.

Dr. Stab
Sep 12, 2010
👨🏻‍⚕️🩺🔪🙀😱🙀

Baryons.

Doc Hawkins
Jun 15, 2010

Dashing? But I'm not even moving!


Factor Mystic posted:

Law & Order of operations

In the software system, the people are represented by two separate, yet equally important, groups: the coders, who write programs; and the posters, who prosecute the coders for their language crimes.

DaTroof
Nov 16, 2000

CC LIMERICK CONTEST GRAND CHAMPION
There once was a poster named Troof
Who was getting quite long in the toof

Doc Hawkins posted:

In the software system, the people are represented by two separate, yet equally important, groups: the coders, who write programs; and the posters, who prosecute the coders for their language crimes.

These are their user stories.

Phobeste
Apr 9, 2006

never, like, count out Touchdown Tom, man

Fergus Mac Roich posted:

Where can I go to get my C code certified as retarded?

GCC

Absurd Alhazred
Mar 27, 2010

by Athanatos

DaTroof posted:

These are their user stories.

UXXX Design

Rubellavator
Aug 16, 2007

Today I broke a jasmine test that looked like this:

code:
controller.js

vm.foo = 
{ 
	p1: "stuff",
	p2: "things",
	bar: function (params) { //do stuff }
}

controller-spec.js

var foo = 
{
	p1: "stuff",
	p2: "things",
	bar: function (params) { //do stuff } 
}

expect(vm.foo).toEqual(foo);

Doom Mathematic
Sep 2, 2008

Rubellavator posted:

Today I broke a jasmine test that looked like this:

code:
controller.js

vm.foo = 
{ 
	p1: "stuff",
	p2: "things",
	bar: function (params) { //do stuff }
}

controller-spec.js

var foo = 
{
	p1: "stuff",
	p2: "things",
	bar: function (params) { //do stuff } 
}

expect(vm.foo).toEqual(foo);

How did that ever pass?

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Doom Mathematic posted:

How did that ever pass?

Since it’s JavaScript, I’m not ruling out the possibility that it compared functions using toString and they happened to match.

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

The unreasonably optimistic alternative is that equality between function objects compares their pointers, and this particular JS engine is smart enough to de-duplicate a redundant function definition.

LOOK I AM A TURTLE
May 22, 2003

"I'm actually a tortoise."
Grimey Drawer
Or it silently ignored fields it didn't know how to compare.

Adbot
ADBOT LOVES YOU

Rubellavator
Aug 16, 2007

Whoops. It was pretty late yesterday when I came across that and I didn't play with it very much. The actual call was toEqualData, which only compares the value of the properties, but had the entire object copied from the source including the functions. Still a pretty silly test. The value of the properties aren't derived, so I guess it's just a test for whether someone accidentally changed a property.

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