Projects > cpp > Issues > Bug #3555

We are migrating issue tracker of Cocos2d-x Project to Github, please create new issue there. Thanks.

Create Issue on Github

Not standard conformant casting of member function pointers (selectors)

Bug #3555 [Closed]
kuhar 2013-12-31 21:07 . Updated about 2 years ago

Cocos2d-x 2.x uses not standard conformant C-style casting for member function pointers.

Consider following code from CCObject.h:
typedef void (CCObject::*SEL_CallFuncN)(CCNode*);
#define callfuncN_selector(_SELECTOR) (SEL_CallFuncN)(&_SELECTOR)

The C-style cast is used to cast between pointers to member functions.
C-style casts use following casts:
# const_cast
# static_cast
# static_cast followed by const_cast
# reinterpret_cast
# reinterpret_cast followed by const_cast

The key-part of this bug report is what the standard says about performing casts on member function pointers: http://www.open-std.org/jtc1/sc22/WG21/docs/wp/html/nov97-2/conv.html\#conv.mem

An rvalue of type “pointer to member of B of type cv T,” where B is a class type, can be converted to an rvalue of type “pointer to member of D of type cv T,” where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D’s instance of B. Since the result has type “pointer to member of D of type cv T,” it can be dereferenced with a D object. The result is the same as if the pointer to member of B were dereferenced with the B sub-object of D. The null member pointer value is converted to the null member pointer value of the destination type. 52)
>
52)The rule for conversion of pointers to members (from pointer to member of base to pointer to member of derived) appears inverted compared to the rule for pointers to objects (from pointer to derived to pointer to base) (4.10, clause 10). This inversion is necessary to ensure type safety. Note that a pointer to member is not a pointer to object or a pointer to function and the rules for conversions of such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a void**.
Thus, dereeferencing a member function pointer is an Undefined Behavior.
Now consider what the standard says about static_cast: http://www.open-std.org/jtc1/sc22/WG21/docs/wp/html/nov97-2/expr.html\#expr.static.cast
An rvalue of type “pointer to member of D of type cv1 T” can be converted to an rvalue of type “pointer to member of B of type cv2 T”, where B is a base class of D, if a valid standard conversion from “pointer to member of B of type T” to “pointer to member of D of type T” exists , and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.11) The null member pointer value is converted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined.
>
11) Function types are never cv-qualified; see 8.3.5 dcl.fct.
Hence, member function pointers can be only casted with static_cast and dereferanced later. Note that you can assign a member function pointer form Derived to Base class if and only if:
** object on witch the is going to be performed is created with proper constructor from the came or derived class as class of method pointer
* static_cast is used
* const-correctness is preserved

Casting with C-style cast will finally result with reinterpet_cast, that leads directly to UB. Moreover, they allow you to cast even between pointer to methods of different signatures without a warning.

The situation is even more complicated on Visual C++ compiler that can generate wrong code due to different pointer to member representation. Despite of using static_cast you’ll often get warning C4407 (http://msdn.microsoft.com/en-us/library/1s6193tt.aspx) when casting objects with multiple inheritance.
It is caused by incorrect implementation of member function pointer in VC.
http://social.msdn.microsoft.com/Forums/vstudio/en-US/a9cfa5c4-d90b-4c33-89b1-9366e5fbae74/strange-error-while-casting-pointers-to-member-functions?forum=vclanguage

The solution is to add /vmg flag to the compiler.

So the actual bugfix’d be to change C-style cast in all selector to static_cast and add /vmg flag to Visual Studio projects.

kuhar 2014-01-01 16:45

Thus, dereeferencing a member function pointer is an Undefined Behavior.
My mistake, it should be “dereferencing a member function pointer that was casted with reinterpret_cast is an Undefined Behavior (based on 5.2.10/9).”

walzer@cocos2d-x.org 2014-10-08 02:52

Redmine issue system is closed, we are using github issue system instead.

This issue was moved to https://github.com/cocos2d/cocos2d-x/issues/8292

Atom PDF

Status:Closed
Start date:2013-12-31
Priority:Low
Due date:
Assignee:-
% Done:

0%

Category:all, windows, wp8
Target version:-
Estimated time:0.50 point

Sign up for our newsletter to keep up with the latest developments, releases and updates for Cocos2d-x.