PR 53255 discussion

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[Moved from Bugzilla to somewhere more appropriate]


(In reply to comment #28)
> New is not bared from the standard from seeing the type.

Yes it is.

In the scope of a member function of A, the type of "this_type" is A.

If you cast some raw memory to A*, how is operator new supposed to
know that you really wanted to cast it to B* ?  If you want to use
that memory as a B instance, cast the memory to B*.  It's not rocket
science.  If you lie to the compiler expect to get hurt.  If you don't
want that, don't lie to the compiler about the type.

> So I continue to say it is wrong to close this.  Either the compiler should be
> giving at least an error for illegal access to the object,

The compiler can't always tell when you do something wrong.

Let's look at your code from
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53225#add_comment

For this statement:

  B *b_pt = new(5) B;

The compiler does two things, call an allocation function, and construct a B:

  void* mem = operator new(sizeof(B), 5);
  B *b_pt = new(mem) B;

Fir the first step the compiler looks for a suitable allocation
function for this type, and it finds A::operator new and it calls
A::operator new(sizeof(B), 5)

Inside operator new:

  void* operator new(size_t enfacia_size, uint count){
      size_t total_size
    = enfacia_size
    + sizeof(int) * count; // the 'tail'
    ;

      this_type *new_pt = (this_type *)malloc(total_size);

Let's break this into into its two constituent expressions:

      void* vp = malloc(total_size);
      this_type *new_pt = (this_type *)vp;

The malloc calls returns some memory, let's say it's 0x08.

Then you cast that memory to this_type* which is a typedef for A* (I
hope you now agree that this_type* is A*, it can't possibly be
anything else because you never declared another this_type, and the
one in scope in A::operator new is A::this_type.)

      new_pt->count = count;

Now you assign to the "count" member of an A object at 0x08.  The
A::count member is at offset 0 inside an A object, so that write
happens to 0x08.

      return new_pt;

The operator new function returns the memory address 0x08.

So now we've got to here:

  void* mem = 0x08;   // value 5 written to integer at address 0x08
  B *b_pt = new(mem) B;

The next statement constructs a B at the address 0x08.

That constructs the C sub-object (that subobject will be at address
0x08 i.e. the 'this' pointer inside the C constructor will be 0x08)
Then it constructs the A sub-object at the next memory location, i.e
in the A::A constructor the 'this' pointer is the address 0x0a.  That
means that the "count" member of the A object is also at address 0x0a.

Finally the compiler calls the B constructor, with this=0x08.

So now when you say b_ptr->count you are accessing 0x0a, but when you
wrote to new_ptr->count in operator new you wrote to 0x08.

So there's no compiler bug, it's doing exactly what you told it to.
You cast the memory returned by malloc to A* and accessed it as an A
object, but when the compiler constructed a B at that address the A
base class is placed at a different location.


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux