LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-24-2008, 01:42 PM   #16
ErV
Senior Member
 
Registered: Mar 2007
Location: Russia
Distribution: Slackware 12.2
Posts: 1,202
Blog Entries: 3

Rep: Reputation: 62

Quote:
Originally Posted by PatrickNew View Post
The *new is intentional, and it does not leak. The Applet object created will return a reference to it's Configuration object on request, which is deleted (via the address-of operator) when the Applet is destroyed. As Applet* is an abstract base class, and the factory functions are the only way to instantiate one, there is never an Applet on the stack - they can only be created (and thus destroyed) dynamically, and the program is structured such that all Applets are deleted at one and only one point in the code. There is a class (AppletManager) whose entire purpose is to manage the lifespans of these Applet*'s.

The new snippet is as follows:
Code:
    void* ptr;
    ids[name].second->get_symbol("create_applet", ptr);
    //Create the applet
    Configuration& c = *new Configuration(*backings[id].first, id);
    applet_creator creator = reinterpret_cast<applet_creator>(ptr);
    applets.push_back((*creator)(c));
The warning still appears, this time on the line with the reinterpret_cast. Hrm...

I've confirmed problem:
Code:
#include <stdio.h>

class A{
};

typedef A* (*aCreator)();

int main(int argc, char** argv){
    void* ptr = 0;
    aCreator creator = (aCreator)(ptr);
    return 0;
}
Take a look at this: http://blog.toidinamai.de/en/programming/dlsym
Looks like solution for the problem.
 
Old 08-24-2008, 01:42 PM   #17
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Quote:
Originally Posted by ta0kira View Post
That's because reinterpret_cast is C++'s "non-C" attempt at a C-cast; you haven't changed anything except for the cast operator used, but both operators are equivalent. Nothing actually happens with reinterpret_cast or a C-cast; you're just telling the compiler that you know what you're doing looks silly but that you want to do it anyway.
I agree. My problem is that the compiler is not "taking the hint". I know that it looks silly, but I also know it's correct. That's what I'm looking for, some way to cast this that doesn't generate a warning.

Quote:
A leak isn't the problem: if your process runs out of memory, etc. then you'll unconditionally dereference a NULL pointer.
ta0kira
And I've agreed with you all along. I'm just trying to separate my concerns for the purposes of this post. And there isn't a chance of dereferencing NULL, btw. C++'s new throws an exception on failure rather than returning NULL. Program still halts either way, but the exception-handling code is a bit cleaner.
 
Old 08-24-2008, 01:44 PM   #18
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Quote:
Originally Posted by ErV View Post
Take a look at this: http://blog.toidinamai.de/en/programming/dlsym
Looks like solution for the problem.
Ahah, that's exactly what I was looking for! Thanks. A bit more hackery than I'd like, but I guess that's just what you have to do.
 
Old 08-24-2008, 01:47 PM   #19
ErV
Senior Member
 
Registered: Mar 2007
Location: Russia
Distribution: Slackware 12.2
Posts: 1,202
Blog Entries: 3

Rep: Reputation: 62
Quote:
Originally Posted by PatrickNew View Post
Ahah, that's exactly what I was looking for! Thanks. A bit more hackery than I'd like, but I guess that's just what you have to do.
You are welcome, question was interesting.
There are several discussions about this problem, looks like it is C/C++ awkwardness problem, not compiler fault.
 
Old 08-24-2008, 01:49 PM   #20
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Hrm, well it looks like it's going to be interesting trying to use both that solution and the Glib::Module dlopen wrapping class. I'll try casting the member function, but I might have to decide between the nice OO wrapper and the clean build.
 
Old 08-24-2008, 02:11 PM   #21
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Okay, so here's a working snippet:
Code:
    typedef Applet* (*applet_creator)(Configuration&);
    typedef bool (Glib::Module::*dlload_t)(const string&, applet_creator&);

    applet_creator creator;
    //This hack is unfortunately necessary to shut up the warnings
    dlload_t mem_fun_ptr = (dlload_t)&Glib::Module::get_symbol;
    ((ids[name].second)->*mem_fun_ptr)("create_applet", creator);
    //Create the applet
    Configuration& c = *new Configuration(*backings[id].first, id);
    applets.push_back((*creator)(c));
And yep, I know the *new is still there. :-) This code compiles cleanly and runs properly. Thanks for your help all!
 
Old 08-24-2008, 05:58 PM   #22
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by PatrickNew View Post
And I've agreed with you all along. I'm just trying to separate my concerns for the purposes of this post. And there isn't a chance of dereferencing NULL, btw. C++'s new throws an exception on failure rather than returning NULL. Program still halts either way, but the exception-handling code is a bit cleaner.
Noted that it's a separate issue. While we're on it though, one can build in a way that might not allow exceptions to propagate properly, such as with static linking; therefore it isn't impossible for new to return NULL.
ta0kira
 
Old 08-24-2008, 09:25 PM   #23
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
Quote:
Originally Posted by PatrickNew View Post
Okay, so here's a working snippet:
Code:
    typedef Applet* (*applet_creator)(Configuration&);
    typedef bool (Glib::Module::*dlload_t)(const string&, applet_creator&);

    applet_creator creator;
    //This hack is unfortunately necessary to shut up the warnings
    dlload_t mem_fun_ptr = (dlload_t)&Glib::Module::get_symbol;
    ((ids[name].second)->*mem_fun_ptr)("create_applet", creator);
    //Create the applet
    Configuration& c = *new Configuration(*backings[id].first, id);
    applets.push_back((*creator)(c));
And yep, I know the *new is still there. :-) This code compiles cleanly and runs properly. Thanks for your help all!
It is actually fine to disregard the warning generated as the behaviour is defined, not be C++ but by POSIX.
Quote:
The ISO C standard does not require that pointers to functions can be cast back and forth to pointers to data. Indeed, the ISO C standard does not require that an object of type void * can hold a pointer to a function. Implementations supporting the XSI extension, however, do require that an object of type void * can hold a pointer to a function. The result of converting a pointer to a function into a pointer to another data type (except void *) is still undefined, however. Note that compilers conforming to the ISO C standard are required to generate a warning if a conversion from a void * pointer to a function pointer is attempted as in:

fptr = (int (*)(int))dlsym(handle, "my_function");
The C++ standards committee has also talked about this in the past.
Quote:
In C the cast results in undefined behavior and thus does not require a diagnostic, and Unix C compilers generally do not issue one. This fact is used in the definition of the standard Unix function dlsym, which is declared to return void* but in fact may return either a pointer to a function or a pointer to an object. The fact that C++ compilers are required to issue a diagnostic is viewed as a "competitive disadvantage" for the language.
I feel there are problems with your solution to circumvent the warning. Whilst the casting of a function pointer to a void pointer is defined here, there is no definition of what will happen calling a function which has the wrong signature, the parameter types and the const-ness of the function.

For code which will be shown to prospective employers I would say this is not a good example.
"I'll try casting the member function, but I might have to decide between the nice OO wrapper and the clean build."
Why not use a clean build with defined behaviour and the nice OO wrapper.
Code:
typedef  int(*DEFAULT_FUNC)();
extern char posix_defined_function_pointer_size_check[sizeof(DEFAULT_FUNC) <= sizeof(void*)? 1 : -1];

typedef struct Configuration;
typedef struct Applet;
typedef Applet* (*applet_creator)(Configuration&);

//for this purpose this is the module function
void Module( void*)
{
}

template<typename T>
struct void_cast
{
	void_cast(T t):_t(t){}
	operator void*(){return  * reinterpret_cast<void**>(&_t);}
	T& _t;
};



int main()
{
	applet_creator c;
	Module(void_cast<applet_creator>(c) );
}
 
Old 08-24-2008, 10:54 PM   #24
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
I know it's fine to ignore the error. As I've said before, it's a purely cosmetic thing.

Upon reviewing the documentation, I see that you are correct - a void* need not be capable of holding a function pointer. However, to the best of my knowledge, glib (and consequently glibmm and gtkmm) do not run on such platforms. Your point is valid, but I already have accepted greater limitations to my portability than that.

You are again correct that it is troublesome that I cannot validate the signature of the function pointer. However, everyone who wishes to implement a plugin in C or C++ must live with this same drawback. It's just a limitation of the language - we have to trust that the plugin obeys the interface given to it. Unless of course we want to embed a compiler or a scripting-language interpreter - both of which would be way out of the scope of this project.

I'm unsure what your sample code is attempting to solve. The only casting of the pointer is in the void_cast, and it simply casts the address of the pointer to a void** and dereferences. This attempted solution was discussed in the link given by ErV - it's a valid way to solve the problem, but it generates a warning and the entire purpose was to eliminate warnings.

I'm also unsure about it's relevance to the problem at hand. Our problem is that we have a a method which will put a function pointer into a void*, and we need to recover the original function pointer. But nowhere does your code do that conversion. Instead, it declares a function pointer, then casts it to a void*. A related problem, but the reverse of what we want to do.

Also, for code given to potential employers, I have a hunch that a dose of realism is probably good. Given enough time, anyone could carefully architect an excellent solution, but if I document this section with comments explaining the funky casts, then I've demonstrated that I can work with (and around) the limitations of other parts of the larger system (in this case, the C++ standard, in others perhaps libraries).
 
Old 08-24-2008, 11:56 PM   #25
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
Quote:
Originally Posted by PatrickNew View Post
.
...
You are again correct that it is troublesome that I cannot validate the signature of the function pointer.
This is not the problem, the problem is that you are type casting a function pointer to a function pointer with a different signuture and then calling it. What is the defined behaviour of calling it?

Quote:
I'm unsure what your sample code is attempting to solve. The only casting of the pointer is in the void_cast, and it simply casts the address of the pointer to a void** and dereferences. This attempted solution was discussed in the link given by ErV - it's a valid way to solve the problem, but it generates a warning and the entire purpose was to eliminate warnings.
I have not tested the code, but it should not give a warning.



Quote:
... I've demonstrated that I can work with (and around) the limitations of other parts of the larger system (in this case, the C++ standard, in others perhaps libraries).
IMHO I feel you have demonstrated how to generate undefined behaviour.

Quote:
I'm also unsure about it's relevance to the problem at hand. Our problem is that we have a a method which will put a function pointer into a void*, and we need to recover the original function pointer. But nowhere does your code do that conversion. Instead, it declares a function pointer, then casts it to a void*. A related problem, but the reverse of what we want to do.
It was just to demo the idea and as I said was not tested; yet here is a revised version which has been compiled with no warnings using -Wall -pedantic -ansi

Code:
typedef  int(*DEFAULT_FUNC)();
extern char function_pointer_size_check[sizeof(DEFAULT_FUNC) <= sizeof(void*)? 1 : -1];

struct Configuration{};
struct Applet{};
typedef Applet* (*applet_creator)(Configuration&);


#include <iostream>
Applet* foo(Configuration& c)
{
	std::cout <<__PRETTY_FUNCTION__;
	return 0;
}
/*I see the function which you are calling from glib takes a ref to
void* so this has changed, which also changes the void_cast type
conversion operator and the life of the object needs to be extended.
*/
void Module( void*& ptr)
{
	//cast here but this would be a void * from dlsym
	ptr = (void*)&foo;
}
template<typename T>
struct void_cast
{
	void_cast(T& t):_t(t){}
	operator void*&(){return  * reinterpret_cast<void**>(&_t);}
	T& _t;
};



int main()
{
	applet_creator c;
	Configuration conf;
	void_cast<applet_creator> cast(c);//life extended
	Module(cast);//call function using cast operator and fill the pointer with the &foo the test function.
	c(conf);//call foo through a function pointer.

}

Last edited by dmail; 08-24-2008 at 11:57 PM.
 
Old 08-25-2008, 12:31 AM   #26
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Quote:
Originally Posted by dmail View Post
This is not the problem, the problem is that you are type casting a function pointer to a function pointer with a different signuture and then calling it. What is the defined behaviour of calling it?
Ah, I see what you mean here, you are referring to the cast of the member function (the attempted solution), not the cast of the void* (the original problem). I agree that the behavior here is undefined. I would have been willing to live with this undefined-ness, but I did find a better way (thanks to your help).


Quote:
Originally Posted by dmail View Post
I have not tested the code, but it should not give a warning.
I have tested the solution of taking the address, casting that to a void** and dereferencing. It gives the warning "dereferencing type-punned pointer will break strict-aliasing rules".

Quote:
Originally Posted by dmail View Post
IMHO I feel you have demonstrated how to generate undefined behaviour.
I can respect that. I was trading undefined behavior for a cosmetic concern. I just didn't quite realize the level of undefined-ness I was introducing.

Quote:
Originally Posted by dmail View Post
It was just to demo the idea and as I said was not tested; yet here is a revised version which has been compiled with no warnings using -Wall -pedantic -ansi
The following code does generate a warning with -Wall -pedantic -ansi on my compiler (g++ (Debian 4.3.1-8) 4.3.1). It generates the original "ISO C++ forbids casting between pointer-to-function and pointer-to-object". However, the warning is within the Module function, whose
parallel in the original problem is within Glib, and not my code.

I got a working, cleanly compiling solution here. The real magic that made it work was found within your void_cast conversion to void*&. I've structured it a bit differently, but that's what did it - using both the casting the address to a pointer-to-pointer and a reinterpret_cast<>.

Code:
    void* ptr;
    ids[name].second->get_symbol("create_applet", ptr);
    Configuration* c=new Configuration(*backings[id].first, id);
    applets.push_back( (*reinterpret_cast<applet_creator*>(&ptr))(*c) );
Thanks for your help. I'm glad to see this sorted out so well!

Last edited by PatrickNew; 08-25-2008 at 12:32 AM. Reason: quote tags
 
Old 08-25-2008, 01:25 PM   #27
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by PatrickNew View Post
You are again correct that it is troublesome that I cannot validate the signature of the function pointer. However, everyone who wishes to implement a plugin in C or C++ must live with this same drawback. It's just a limitation of the language - we have to trust that the plugin obeys the interface given to it. Unless of course we want to embed a compiler or a scripting-language interpreter - both of which would be way out of the scope of this project.
This really isn't that big of a deal. Any global function should be extern "C", as declared by a header associated with the plug-in system, and member functions needn't ever be be linked from a program-loaded library: the plug-ins should hard link to the library with the member definitions and abstract definitions will be called via the vtable, making it strictly an ABI link where there's a slim possibility of differences between the original declaration and the way it's called at run time.
ta0kira
 
Old 08-25-2008, 01:30 PM   #28
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Quote:
Originally Posted by ta0kira View Post
This really isn't that big of a deal. Any global function should be extern "C", as declared by a header associated with the plug-in system, and member functions needn't ever be be linked from a program-loaded library: the plug-ins should hard link to the library with the member definitions and abstract definitions will be called via the vtable, making it strictly an ABI link where there's a slim possibility of differences between the original declaration and the way it's called at run time.
ta0kira
The point I was trying to make was that either through accidental placement or malicious intent, it is possible that a plugin could export the symbol "create_applet" without that plugin having been compiled against the same headers, etc. "create_applet" might not even be a function, it could be a global int, for example. I can see no reason to create such an applet (as it would just cause screwy behavior in the daemon), but it is *possible* to create one.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
( C ) How do you declare a function pointer where a parameter is a function pointer? spursrule Programming 5 11-27-2007 07:56 PM
pointer cast c++ santana Programming 10 10-19-2007 07:55 AM
makes pointer from integer without a cast ? hubabuba Programming 2 01-28-2005 05:28 PM
pointer from integer without a cast bcf2 Programming 7 12-30-2004 02:04 PM
makes pointer from interger without a cast y0shi Linux - General 4 10-21-2004 08:17 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:27 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration