httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andre Pang <oz...@algorithm.com.au>
Subject Bug with __stdcall modules on Windows
Date Wed, 05 Jan 2005 00:06:05 GMT
Hi all,

I've been writing some Apache 2.0 (HTTP Server) modules, and I've found  
a problem with Windows calling conventions.  Apache assumes that the  
module is compiled with Windows' __cdecl calling convention.  This is  
OK.  If an Apache module is compiled with a __stdcall calling  
convention, the compiler should stop the compilation and prevent  
linking from taking place.  However, the compiler merrily proceeds to  
compile and link things, resulting in a segfault at run-time.

Normally, the compiler will catch the calling convention  
incompatibility, but this doesn't happen with APR because since the  
module is compiled with __stdcall, the Apache _headers_ (which are  
included by the module's source code) that declare the function  
prototypes are also assumed to be __stdcall.

The bug fix is to put the __cdecl pragma directly into the APR/Apache  
headers, so that the compiler knows that any entry points into the  
module should be __cdecl.  This is similar to how APR has an  
AP_MODULE_DECLARE_DATA macro which expands to __declspec(dllexport):  
what is needed is another macro (e.g. "APR_MODULE_ENTRY_POINT") which  
expands to __cdecl.  I suspect that the right place to put this is in  
APR, but httpd may also need to have some of its headers changed.

Since it's all a bit complex, I've pasted in some example code from my  
project which shows what I currently have to do, which may shed some  
light on what's happening.

So, a standard module declaration which currently looks like this:

   module AP_MODULE_DECLARE_DATA timeslice_module = {
       STANDARD20_MODULE_STUFF,
       NULL,                  /* create per-dir    config structures */
       NULL,                  /* merge  per-dir    config structures */
       NULL,                  /* create per-server config structures */
       NULL,                  /* merge  per-server config structures */
       NULL,                  /* table of config file commands       */
       foo_register_hooks     /* register hooks */
   };

When a module is compiled as __stdcall, the foo_register_hooks function  
is thus assumed to be __stdcall, when it should really be __cdecl,  
since that's what Apache expects.  To solve this, I've added a macro to  
declare the function as __cdecl:

   #ifdef WIN32
   # define AP_MODULE_ENTRY_POINT __cdecl
   #else
   # define AP_MODULE_ENTRY_POINT
   #endif

   static void AP_MODULE_ENTRY_POINT foo_register_hooks(apr_pool_t *p)
   {
     ap_hook_handler(foo_handler, NULL, NULL, APR_HOOK_MIDDLE);
   }

Note that foo_register_hooks registers foo_handler as an  
ap_hook_handler, which means that foo_handler also has to be declared  
__cdecl (since it's a direct entry point into the module, called by  
Apache).

This doesn't quite work however, because foo_handler is declared to be  
of the ap_HOOK_handler_t type.  Since the ap_HOOK_handler_t typedef is  
declared in the Apache headers files without __cdecl, the compiler  
type-checks ap_HOOK_handler_t as __stdcall (because the header files  
are included by the module, and since the module is compiled with  
__stdcall, any header declarations are also presumed to be __stdcall).   
I'm currently "solving" this problem by type-casting the function  
argument to ap_hook_handler as __stdcall (which is actually a lie!),  
like so:

   #ifdef WIN32
   # define AP_HOOK_HANDLER_FUNCTION(x) (ap_HOOK_handler_t (__stdcall  
*)) x
   #else
   # define AP_HOOK_HANDLER_FUNCTION(x) x
   #endif

   static void AP_MODULE_ENTRY_POINT foo_register_hooks(apr_pool_t *p)
   {
       ap_hook_handler(AP_HOOK_HANDLER_FUNCTION(foo_handler),
   		            NULL, NULL, APR_HOOK_MIDDLE);
   }

This forces the compiler to think that foo_handler is an __stdcall so  
it can be used as a parameter to ap_hook_handler, thus complying with  
the incorrect header file declarations.  The same problem exists for  
any function arguments in the module declaration.

I think the proper solution is to:

   * Add an AP_MODULE_ENTRY_POINT macro to declare direct function entry  
points into a module, similar to how AP_MODULE_DECLARE_DATA is needed  
for module declarations.  Or, change the AP_MODULE_DECLARE_NONSTD macro  
so that it contains __cdecl on Windows.

   * Modify the ap_HOOK_handler_t typedef in FOO.h so that any function  
parameters are __cdecl.

   * Similarly, modify the module typedef in BAR.h so that any function  
parameters are __cdecl.

I'd offer a patch, but I can't find where the module/ap_HOOK_handler_t  
typedefs are in the Apache header files.  Can anybody assist me here?

A complete example can be found at

    
http://trac.xiph.org/cgi-bin/trac.cgi/browser/trunk/oggdsf/src/tools/ 
mod_timeslice/

for those interested.  In particular, see the mod_timeslice.cpp and  
apr_stdcall.h files.


-- 
% Andre Pang : trust.in.love.to.save


Mime
View raw message