You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-dev@axis.apache.org by Samisa Abeysinghe <sa...@gmail.com> on 2006/11/04 10:23:04 UTC

Re: [Axis2]thoughts re development towards 1.0

Hi Chris,
    Thank you for the detailed review, this really helps - appreciate it 
very much.
    I do agree with your concerns on memory leaks and the difficulty of 
dealing with that in  the absence of a pool.
    And improvements you have suggested makes quite sense.
    However I need more time to understand some of the stuff - I am 
traveling this week, so it will take some time.
    May be others can have look in the mean time :)

Thanks,
Samisa...
Chris Darroch wrote:
> Hi --
>
>    I've been working fairly intensively with Axis2/C over the last month
> or two in order to build some applications, and I thought I might share
> two major concerns that have arisen for me.  I apologize if any of these
> points have been discussed before!
>
>    Before I explain in detail, if I could just put in a request for
> someone to review the latest patches I've attached to AXIS2C-380
> (https://issues.apache.org/jira/browse/AXIS2C-380) regarding a number
> of mod_axis2 cleanups and fixups.  I've tried to fix and clean up
> the configuration directives, add axis2_error_init(), move
> axiom_xml_reader_init(), and enable valid SOAP faults from application
> services and also when services and operations are not found.  Thanks
> in advance!
>
>    In brief, my two concerns are that (A) Axis2/C doesn't use the APR
> libraries (in particular, it doesn't use APR memory pools), and (B)
> that it relies on extensive use of indirect function calls through
> tables of function pointers instead of making simple function calls.
> I'll walk through my thinking on both issues below.
>
>
> A) There's a lot of code duplication between the Axis2/C util library
> and APR.  That's too bad, because it means that bug fixes to APR
> won't be automatically inherited by Axis2/C.  From a presentation
> I attended at last month's ApacheCon U.S. I learned that the original
> plan was to provide an abstraction layer above a portability library
> like APR, and that that got delayed by time constraints.  I don't
> know myself if such an extra layer is really valuable or not, but I
> would have thought that it was better to at least use APR than to
> reproduce portions of it.
>
>    At any rate, I'm not suggesting that much can be done about this
> in the short term, at least for a 1.0 release.  However, I am
> concerned in particular about the absence of APR memory pools and
> the use instead of AXIS2_MALLOC() and AXIS2_FREE().
>
>    My concern comes about because I'm hoping to run mod_axis2 in
> a production system.  That means that I'm worried about gradual
> memory leaks that occur when memory is allocated but not deallocated
> appropriately.  Given the size of the Axis2/C codebase, I think it's
> a reasonable assumption that there are a number of places where
> this occurs -- and that's not a major criticism, since this is one
> of the classic hard things about C programming.
>
>    APR memory pools make life a lot easier.  When writing an
> Apache httpd module, there's basically two kinds of pools one wants
> to consider using -- either a pool that lasts for the lifetime of an
> httpd child process, or a pool that lasts for the lifetime of an
> HTTP request.  (I'm leaving aside for now the threading issues that
> can arise when dealing with process-lifetime pools when using a
> threaded MPM.)
>
>    The attached patchset is a first hack at making mod_axis2 use
> these two kinds of pools.  It works, sort of, but after a few
> requests the child processes segfault.  (It doesn't include
> patches to rampart or guththila, both of which seems to contain
> a few calls to AXIS2_REALLOC which would need to be rewritten.)
> The segfaults always seems to happen at the following level of
> the calling stack (for me, anyway):
>
> axis2_engine_receive()
>   AXIS2_MSG_RECV_RECEIVE()
>     axis2_raw_xml_in_out_msg_recv_receive_sync()
>       axis2_core_utils_create_out_msg_ctx()
>         AXIS2_MSG_CTX_SET_SVC_CTX()
>           axis2_msg_ctx_set_svc_ctx()
>             axis2_msg_ctx_set_svc()
>
>    I don't have time to pursue this further right now, but I think
> it would be really valuable before the 1.0 release to ensure that
> mod_axis2 worked using some kind of similar technique.
>
>    It seems to me that what might be the logical next steps would be:
>
> 1) Add to the env structure a second allocator, named something like
>    resident_allocator or config_allocator or something.
> 2) Analyze which data structures in Axis2/C were effectively
>    "configuration" data and needed to stay in memory for the lifetime
>    of a process.  This should include any such data that needs to
>    be modified or deleted over the lifetime of the server process.
> 3) For each such structure, ensure that it is created, modified,
>    and deleted using only the env->resident_allocator.  This could
>    be accomplished a variety of ways (a private sub-allocator,
>    for example).  The main concern is thread-safety; if multiple
>    threads might be managing this structure at the same time,
>    a thread mutex will need to be used as well.
>
>    At this point, everything else should be data which can be
> cleaned up automatically when the httpd request->pool is cleared
> at the end of each HTTP request.  Then you could even go through
> the code and remove all the calls to AXIS2_FREE() if you really
> felt like it!  The key advantage is that it means that each
> httpd server process is guaranteed to only increase in size if
> the "configuration" data grows, and this should presumably be by
> only a trivial amount.
>
>
> B) I mentioned to a few people I met at a presentation on Axis2/C
> at ApacheCon my concern about the all the function pointers in
> all of the "ops" structures.  The heavy use of all this indirection
> means that the compiler and linker can't help detect when you're
> about to call a function but your function pointer is NULL.
> Making simple, normal function calls means that you can rely on
> the compiler and linker to give you a lot of helpful errors about
> such things before you reach runtime.
>
>    Now, again I understand that this isn't going to be something
> that can change for a 1.0 release.  However, maybe something can
> be done that would help a bit.  Let me point to an example;
> unfortunately I don't have the exact details to hand any more, but
> I think it still illustrates my concern.
>
>    When I was working through the problems I described in AXIS2C-326
> and AXIS2C-322 (https://issues.apache.org/jira/browse/AXIS2C-326 and
> http://issues.apache.org/jira/browse/AXIS2C-322) I came across
> a situation where a valid WSDL file, fed into woden, caused a
> segfault.  It turned out to be because the woden code was expecting
> an attribute where the WSDL spec says you don't absolutely need one.
> I no longer have all the details at hand but it doesn't really matter
> for the purposes of discussion.
>
>    Ideally, obviously, woden should accept the WSDL and proceed.
> But, if it really isn't going to work without the attribute -- if
> the WSDL is just nonsensical, or whatever -- it should at least
> print a nice message like "expecting attribute 'foo' at line 123
> of file 'bar.wsdl'".
>
>    To do that, the first thing it needs to do is not crash.  There
> were two segfault problems I had to work through.  The first is
> a relatively simple coding error that happens to appear in a bunch
> of places in woden; see my nodes in AXIS2C-384
> (https://issues.apache.org/jira/browse/AXIS2C-384) about that.
>
>    The code where I recall the problem turned up looked like this
> (I might be off by a few lines but that doesn't matter to the larger
> point):
>
> int_msg_ref = woden_wsdl10_interface_msg_ref_to_interface_msg_ref_element(
>                   int_msg_ref, env);
> intf_msg_qname = WODEN_WSDL10_INTERFACE_MSG_REF_ELEMENT_GET_QNAME(
>                      int_msg_ref, env);
>
>    The WODEN_WSDL10_INTERFACE_MSG_REF_ELEMENT_GET_QNAME macro is
> defined like this (with some whitespace for clarity):
>
> #define WODEN_WSDL10_INTERFACE_MSG_REF_ELEMENT_GET_QNAME(
>             interface_msg_ref_element, env)
>   (((woden_wsdl10_interface_msg_ref_element_t *) interface_msg_ref_element)->
>             ops->get_qname(interface_msg_ref_element, env))
>
>    The AXIS2C-322/384 issue meant that int_msg_ref was unexpectedly
> NULL and so the macro would cause a segfault.  It seems to me like
> this sort of thing could happen quite a bit, given the way the
> code is structured as a whole, and that's the crux of my concern here.
>
>    At ApacheCon, someone pointed out that the Axis2/C code does
> a lot of parameter checking, but that's not going to help here.
> Suppose that woden_wsdl10_interface_msg_ref_get_qname(), which is
> what the macro calls, performed a nice argument check:
>
> AXIS2_PARAM_CHECK(env->error, interface_msg_ref, AXIS2_FAILURE);
>
> that still won't help, because the macro is still going to fail
> if either its interface_msg_ref_element argument is NULL, or if
> the ops structure pointer is NULL, or if the get_qname function
> pointer is NULL.
>
>    In a more traditional C program, you might have something like:
>
> int_msg_ref = woden_wsdl10_interface_msg_ref_to_interface_msg_ref_element(
>                   int_msg_ref, env);
> intf_msg_qname = woden_wsdl10_interface_msg_ref_get_qname(
>                      int_msg_ref, env);
>
> and if the get_qname() function did an AXIS2_ENV_CHECK() and an
> AXIS2_PARAM_CHECK() on its two arguments, you'd be nicely protected
> against segfaults.  The compiler and linker would caution you if
> were calling a function that wasn't defined.
>
>     Plus, if AXIS2_PARAM_CHECK() did an AXIS2_LOG_ERROR()
> then you'd even get an error message showing exactly which file
> and line of code encountered a NULL function argument.
>
>    With the current indirect function calling scheme, you're at
> the mercy of the various "constructor" functions; if they fail to
> fill in function pointers then you're in trouble.  You're also
> going to fail if you pass a NULL to a macro.  And in all these
> cases there's nothing in the logs to help someone.
>
>    What I might propose is a compromise, since clearly the function
> pointer technique is used extensively and can't just be replaced.
> Here are my proposals:
>
> 1) AXIS2_ENV_CHECK() and AXIS2_PARAM_CHECK() should call
> AXIS2_LOG_ERROR() in the case where the argument is NULL.  Because
> these are macros they'll expand so that AXIS2_LOG_SI gives file
> and line information on the place where the NULL argument was
> encountered.
>
> 2) All the macros that perform indirect function calling through
> the many ops structures should be expanded to first call
> AXIS2_ENV_CHECK() and AXIS2_PARAM_CHECK() on their key env
> and "interface" structure pointer arguments.  It might be good
> to also check for a NULL ops structure pointer and a NULL function
> pointer in the ops structure.
>
>    This would mean that whenever you called one of these many
> macros you'd be automatically protected against failure due to
> NULLs, and you'd get a helpful error message too.
>
>
>    So ... a long email, but hopefully not too unpleasant a read.
> I'm going to have to largely ignore email next week while I work
> toward a deadline, but please do reply to the list or to me
> in person with comments, criticisms, flames, etc.  Thanks for
> listening!
>
> Chris.
>
>   


---------------------------------------------------------------------
To unsubscribe, e-mail: axis-c-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-c-dev-help@ws.apache.org