Reputation: 1886
Access and change value of private class member:
#include <stdio.h>
class hack_Me
{
private:
size_t age;
public:
size_t getAge() const
{
return this->age;
}
explicit hack_Me(size_t age):age(age) { }
};
void change_age(hack_Me* h)
{
*((int*)h) = 100;
}
int main(int argc, char* argv[])
{
hack_Me h(12);
printf("%d \n", h.getAge());
change_age(&h);
printf("%d \n", h.getAge());
getchar();
return 0;
}
It prints 100 after 12.
It works on MSVC 14.
Is this behavior undefined and/or compiler dependent?
UPDATE: Does StackOverflow give you points for downvotes?
Upvotes: 1
Views: 1238
Reputation: 206557
Is this behavior undefined and/or compiler dependent?
Using int*
to access a variable of type size_t
is bad regardless of whether the variable is inside a class or it is by itself.
If you use
*(reinterpret_cast<size_t*>(h)) = 100;
It is not undefined behavior and it is not compiler dependent. I suspect, it won't be any different if you use:
*((size_t*)h) = 100;
Your class meets the requirements of a standard-layout struct
.
From the C++11 Standard:
9 Classes
...
7 A standard-layout class is a class that:
— has no non-static data members of type non-standard-layout class (or array of such types) or reference,
— has no virtual functions (10.3) and no virtual base classes (10.1),
— has the same access control (Clause 11) for all non-static data members,
— has no non-standard-layout base classes,
— either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
— has no base classes of the same type as the first non-static data member.
8 A standard-layout struct is a standard-layout class defined with the class-key
struct
or the class-keyclass
.
For standard-layout struct
s, the pointer to an object can be aliased to the pointer to the first member variable.
From the C++11 Standard:
9.2 Class members
...
20 A pointer to a standard-layout struct object, suitably converted using a
reinterpret_cast
, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note ]
Upvotes: 4
Reputation: 1109
Inside the hack_Me you have size_t age;
which may be smaller than int (e.g. under 8-bit architecture it might be that sizeof(size_t) == 1 and sizeof(int) == 2). If your compiler doesn't generate padding at an end of hack_Me, it may happen that the whole hack_Me is smaller than int and thus the *((int*)h) = 100;
might overwrite more memory than only the first member of hack_Me. Change the hack to *((size_t*)h) = 100;
and it will be probably OK (see other answers).
Upvotes: 1