 | Hi,
I have been trying to track down a SEGV in a module pushed into a stream and I have found the problem.
If you pass a stack-based, or member variable task into an ACE_Module, you set the close flag to M_DELETE_NONE, which in Module.h is 0 (zero).
The module will adhere to this allocation policy if used in a stand-alone test, i.e., if you dynamically allocate a module, initialize it with stack based tasks, and delete the module, then no SEGV occurs.
However, if you push that same module into a stream, a SEGV occurs when the stream destructs that module!?
The issue is that the Stream::close() function also has a set of flags, and the default is M_DELETE = 3, whereas the Module::close() default is M_DELETE_NONE = 0.
Inside Module::close() is the comment:
// Only pay attention to the flags parameter if we haven't already // set the task delete policies. if (this->flags_ == 0) ACE_SET_BITS (flags_, flags);
However, the value 0 IS a delete policy, it says to delete NONE. If stream.close() is called, then the default stream close argument of 3 is passed down to the module close inside Stream::pop() and the conditional code above changes the delete policy from M_DELETE_NONE to M_DELETE, which triggers the attempt by the module to delete its tasks.
I believe the solution to this might be to introduce either a default flags_ value of -1, and change the test above to check for flags_ < 0, or to introduce another member to the enumeration, eg. M_DELETE_UNKNOWN (delete policy unknown, not set).
There is also some confusion with regard to the use of flags in the Streams module. The flags parameter is used to determine both the module tasks deletion policy AND the deletion policy of the module itself (I believe this is incorrect). For example:
template int ACE_Stream::pop (int flags) { ACE_TRACE ("ACE_Stream::pop"); if (this->stream_head_->next () == this->stream_tail_) return -1; else { // Skip over the ACE_Stream head. ACE_Module *top_mod = this->stream_head_->next (); ACE_Module *new_top = top_mod->next ();
this->stream_head_->next (new_top);
// Close the top ACE_Module. top_mod->close (flags);
>>>> This line calls module close, with a flags parameter that determines >>>> the task deletion policy, possibly over-riding M_DELETE_NONE >>>> with M_DELETE and causing a SEGV. (as discussed above)
// Don't delete the Module unless the flags request this. if (flags != ACE_Module::M_DELETE_NONE) delete top_mod;
>>>> Hang on, if I have stack allocated tasks in a dynamically >>>> allocated module, then this line of code will not delete >>>> the dynamically allocated module! >>>> Similarly, if I have dynamically allocated tasks in a >>>> stack allocated module, this code will try to delete the >>>> statically allocated module! >>>> The task delete flags can NOT be used to determine both >>>> the deletion policy of the tasks AND the module.
this->stream_head_->writer ()->next (new_top->writer ()); new_top->reader ()->next (this->stream_head_->reader ()); return 0; } }
Its not clear to me why the Stream::close flags are not just the deletion policy of the MODULE, since the module deletion policy has ALREADY been setup during the creation of the module. In that case, the top_mod call above should just be top_mod->close(), and the Stream could just have its own enumeration to indicate the deletion policy of the modules it contains.
One could argue that if you always dynamically allocate your tasks and your modules, that you'll never see this issue. True, but the code still has bugs. I'd prefer to report, and if possible assist in fixing the bugs to make ACE a better package.
Here is a set of tests, one of which exibits the SEGV:
Test number: 1. Dynamic tasks 2. Dynamic tasks, stream.close(0) 3. Stack tasks ** will SEGV ** 4. Stack tasks, stream.close(0)
http://www.ovro.caltech.edu/~dwh/ace/stream_segv.cpp
The third test SEGV's since exit from main triggers the default Stream::close(M_DELETE) call, which over-writes the M_DELETE_NONE policy setup in the module.
I'm sorry for posting questions so much. I figure this is the ACE users group, and I am a new ACE user. I'm kind of surprized to find I am the first to stumble over these issues. Especially since I only stumbled over them by starting from the example in C++NPv2. If an ACE developer could respond as to whether I should come up with a set of tests, and a patch to the module/stream files. Then I'll happily do that.
Cheers Dave Hawkins Caltech.
|
|