Michael
2008-08-19 21:44:45 UTC
Hello,
this was a more complicated one, so I'm giving you some background:
We run a any serialization service with a signature like:
string anyToXml(in any a) raises (x,y,z);
We had issues when serializing certain dynamically created structures
from python, which resulted (based on the machine used) in Segfaults or
infinite hangs (but no CPU usage).
I could track down the problem to the following case in python:
serializer.anyToXml(any.to_any({'a':None}))
After inspecting what's going on, I figured that to_any does create
sequences and structures containing members of type TC_null (which IMHO
should not happen, instead they should put in an any "containing" TC_null).
I wrote a little test script for python:
from omniORB import any
import CORBA
print "Sequence test 1 (any.to_any([None, \"123\"]):"
print any.to_any([None, "123"])
print "\nSequence test 2 (any.to_any([None]):"
print any.to_any([None])
print "\nSequence test 3 (any.to_any([None,None]):"
print any.to_any([None,None])
print "\nStruct test1:"
print any.to_any({'a':None})
print "\nStruct test2:"
print any.to_any({'a':CORBA.Any(CORBA.TC_null, None)})
print "\nDirect None Test1:"
print any.to_any(CORBA.Any(CORBA.TC_null, None))
print "\nDirect None Test2:"
print any.to_any(None)
The output of this script is:
Sequence test 1 (any.to_any([None, "123"]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_any),
[CORBA.Any(CORBA.TC_null, None), CORBA.Any(CORBA.TC_string, '123')])
Sequence test 2 (any.to_any([None]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_null),
[None])
Sequence test 3 (any.to_any([None,None]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_null),
[None, None])
Struct test1:
CORBA.Any(CORBA.TypeCode("omni:3cc98447:00000001"),
UnknownStruct<omni:3cc98447:00000001>(a=None))
Struct test2:
CORBA.Any(CORBA.TypeCode("omni:3cc98447:00000002"),
UnknownStruct<omni:3cc98447:00000002>(a=None))
Direct None Test1:
CORBA.Any(CORBA.TC_null, None)
Direct None Test2:
CORBA.Any(CORBA.TC_null, None)
IMHO the only valid tests are Direct Test 1+2 and Sequence test 1. I
digged through any.py and came up with the following (maybe not very
elegant) patch - I also attached it as any.py.patch:
--- any.py.orig Tue Aug 19 16:26:45 2008
+++ any.py Tue Aug 19 17:24:59 2008
@@ -210,7 +210,7 @@
atc = any_list[0]._t
for a in any_list:
- if not a._t.equivalent(atc):
+ if not a._t.equivalent(atc) or a._t.kind() == CORBA.tk_null:
break
else:
tc = tcInternal.createTypeCode((tcInternal.tv_sequence,
atc._d, 0))
@@ -238,8 +238,12 @@
t, v = _to_tc_value(v)
ms.append(k)
dl.append(k)
- dl.append(t._d)
- svals.append(v)
+ if t.kind() == CORBA.tk_null:
+ dl.append(CORBA.TC_any._d)
+ svals.append(CORBA.Any(CORBA.TC_null, None))
+ else:
+ dl.append(t._d)
+ svals.append(v)
cls = omniORB.createUnknownStruct(id, ms)
dl[1] = cls
tc = tcInternal.createTypeCode(tuple(dl))
The output of test script after applying the patch is:
Sequence test 1 (any.to_any([None, "123"]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_any),
[CORBA.Any(CORBA.TC_null, None), CORBA.Any(CORBA.TC_string, '123')])
Sequence test 2 (any.to_any([None]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_any),
[CORBA.Any(CORBA.TC_null, None)])
Sequence test 3 (any.to_any([None,None]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_any),
[CORBA.Any(CORBA.TC_null, None), CORBA.Any(CORBA.TC_null, None)])
Struct test1:
CORBA.Any(CORBA.TypeCode("omni:2c074c84:00000001"),
UnknownStruct<omni:2c074c84:00000001>(a=CORBA.Any(CORBA.TC_null, None)))
Struct test2:
CORBA.Any(CORBA.TypeCode("omni:2c074c84:00000002"),
UnknownStruct<omni:2c074c84:00000002>(a=CORBA.Any(CORBA.TC_null, None)))
Direct None Test1:
CORBA.Any(CORBA.TC_null, None)
Direct None Test2:
CORBA.Any(CORBA.TC_null, None)
Which IMHO is the way it should work.
I'm not sure if there are other data structures affected, but afaik
struct and sequence are the only types created dynamically by any.to_any.
Now for the second issue: Why does the server side crash? (It only
crashes for structs, so I will limit my analysis on those):
The order of events is (all happening in dynAny.cc):
1. call to factory->create_dyn_any which calls
2. factory_create_dyn_any which calls
3. internal_create_any which creates
4. DynStructImpl::DynStructImpl (ctor) which calls
setNumComponents(actualTc()->NP_member_count());
5. DynAnyConstrBase::setNumComponents will create a list of components
and pupulate them by calling internal_create_dyn_any (this happens at
line 2430)
6. internal_create_dyn_any does not handle tk_null but
throws DynamicAny::DynAny::TypeMismatch();
7. This exception is not caught in the calling place, which means
that pd_components will never be initialized correctly
8. Segmentation fault (couldn't track down the exact position, but since
pd_components is filled with null pointers there are many places
where this might happen). Finding the exact point was beyond my time
constraints.
I would suggest to add exception handling in
DynAnyConstrBase::setNumComponents or do more rigid testing when
receiving anys (contained structs or sequences should not be allowed to
have members of kind tk_null).
cheers
Michael
-------------- next part --------------
--- any.py.orig Tue Aug 19 16:26:45 2008
+++ any.py Tue Aug 19 17:24:59 2008
@@ -210,7 +210,7 @@
atc = any_list[0]._t
for a in any_list:
- if not a._t.equivalent(atc):
+ if not a._t.equivalent(atc) or a._t.kind() == CORBA.tk_null:
break
else:
tc = tcInternal.createTypeCode((tcInternal.tv_sequence, atc._d, 0))
@@ -238,8 +238,12 @@
t, v = _to_tc_value(v)
ms.append(k)
dl.append(k)
- dl.append(t._d)
- svals.append(v)
+ if t.kind() == CORBA.tk_null:
+ dl.append(CORBA.TC_any._d)
+ svals.append(CORBA.Any(CORBA.TC_null, None))
+ else:
+ dl.append(t._d)
+ svals.append(v)
cls = omniORB.createUnknownStruct(id, ms)
dl[1] = cls
tc = tcInternal.createTypeCode(tuple(dl))
this was a more complicated one, so I'm giving you some background:
We run a any serialization service with a signature like:
string anyToXml(in any a) raises (x,y,z);
We had issues when serializing certain dynamically created structures
from python, which resulted (based on the machine used) in Segfaults or
infinite hangs (but no CPU usage).
I could track down the problem to the following case in python:
serializer.anyToXml(any.to_any({'a':None}))
After inspecting what's going on, I figured that to_any does create
sequences and structures containing members of type TC_null (which IMHO
should not happen, instead they should put in an any "containing" TC_null).
I wrote a little test script for python:
from omniORB import any
import CORBA
print "Sequence test 1 (any.to_any([None, \"123\"]):"
print any.to_any([None, "123"])
print "\nSequence test 2 (any.to_any([None]):"
print any.to_any([None])
print "\nSequence test 3 (any.to_any([None,None]):"
print any.to_any([None,None])
print "\nStruct test1:"
print any.to_any({'a':None})
print "\nStruct test2:"
print any.to_any({'a':CORBA.Any(CORBA.TC_null, None)})
print "\nDirect None Test1:"
print any.to_any(CORBA.Any(CORBA.TC_null, None))
print "\nDirect None Test2:"
print any.to_any(None)
The output of this script is:
Sequence test 1 (any.to_any([None, "123"]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_any),
[CORBA.Any(CORBA.TC_null, None), CORBA.Any(CORBA.TC_string, '123')])
Sequence test 2 (any.to_any([None]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_null),
[None])
Sequence test 3 (any.to_any([None,None]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_null),
[None, None])
Struct test1:
CORBA.Any(CORBA.TypeCode("omni:3cc98447:00000001"),
UnknownStruct<omni:3cc98447:00000001>(a=None))
Struct test2:
CORBA.Any(CORBA.TypeCode("omni:3cc98447:00000002"),
UnknownStruct<omni:3cc98447:00000002>(a=None))
Direct None Test1:
CORBA.Any(CORBA.TC_null, None)
Direct None Test2:
CORBA.Any(CORBA.TC_null, None)
IMHO the only valid tests are Direct Test 1+2 and Sequence test 1. I
digged through any.py and came up with the following (maybe not very
elegant) patch - I also attached it as any.py.patch:
--- any.py.orig Tue Aug 19 16:26:45 2008
+++ any.py Tue Aug 19 17:24:59 2008
@@ -210,7 +210,7 @@
atc = any_list[0]._t
for a in any_list:
- if not a._t.equivalent(atc):
+ if not a._t.equivalent(atc) or a._t.kind() == CORBA.tk_null:
break
else:
tc = tcInternal.createTypeCode((tcInternal.tv_sequence,
atc._d, 0))
@@ -238,8 +238,12 @@
t, v = _to_tc_value(v)
ms.append(k)
dl.append(k)
- dl.append(t._d)
- svals.append(v)
+ if t.kind() == CORBA.tk_null:
+ dl.append(CORBA.TC_any._d)
+ svals.append(CORBA.Any(CORBA.TC_null, None))
+ else:
+ dl.append(t._d)
+ svals.append(v)
cls = omniORB.createUnknownStruct(id, ms)
dl[1] = cls
tc = tcInternal.createTypeCode(tuple(dl))
The output of test script after applying the patch is:
Sequence test 1 (any.to_any([None, "123"]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_any),
[CORBA.Any(CORBA.TC_null, None), CORBA.Any(CORBA.TC_string, '123')])
Sequence test 2 (any.to_any([None]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_any),
[CORBA.Any(CORBA.TC_null, None)])
Sequence test 3 (any.to_any([None,None]):
CORBA.Any(orb.create_sequence_tc(bound=0, element_type=CORBA.TC_any),
[CORBA.Any(CORBA.TC_null, None), CORBA.Any(CORBA.TC_null, None)])
Struct test1:
CORBA.Any(CORBA.TypeCode("omni:2c074c84:00000001"),
UnknownStruct<omni:2c074c84:00000001>(a=CORBA.Any(CORBA.TC_null, None)))
Struct test2:
CORBA.Any(CORBA.TypeCode("omni:2c074c84:00000002"),
UnknownStruct<omni:2c074c84:00000002>(a=CORBA.Any(CORBA.TC_null, None)))
Direct None Test1:
CORBA.Any(CORBA.TC_null, None)
Direct None Test2:
CORBA.Any(CORBA.TC_null, None)
Which IMHO is the way it should work.
I'm not sure if there are other data structures affected, but afaik
struct and sequence are the only types created dynamically by any.to_any.
Now for the second issue: Why does the server side crash? (It only
crashes for structs, so I will limit my analysis on those):
The order of events is (all happening in dynAny.cc):
1. call to factory->create_dyn_any which calls
2. factory_create_dyn_any which calls
3. internal_create_any which creates
4. DynStructImpl::DynStructImpl (ctor) which calls
setNumComponents(actualTc()->NP_member_count());
5. DynAnyConstrBase::setNumComponents will create a list of components
and pupulate them by calling internal_create_dyn_any (this happens at
line 2430)
6. internal_create_dyn_any does not handle tk_null but
throws DynamicAny::DynAny::TypeMismatch();
7. This exception is not caught in the calling place, which means
that pd_components will never be initialized correctly
8. Segmentation fault (couldn't track down the exact position, but since
pd_components is filled with null pointers there are many places
where this might happen). Finding the exact point was beyond my time
constraints.
I would suggest to add exception handling in
DynAnyConstrBase::setNumComponents or do more rigid testing when
receiving anys (contained structs or sequences should not be allowed to
have members of kind tk_null).
cheers
Michael
-------------- next part --------------
--- any.py.orig Tue Aug 19 16:26:45 2008
+++ any.py Tue Aug 19 17:24:59 2008
@@ -210,7 +210,7 @@
atc = any_list[0]._t
for a in any_list:
- if not a._t.equivalent(atc):
+ if not a._t.equivalent(atc) or a._t.kind() == CORBA.tk_null:
break
else:
tc = tcInternal.createTypeCode((tcInternal.tv_sequence, atc._d, 0))
@@ -238,8 +238,12 @@
t, v = _to_tc_value(v)
ms.append(k)
dl.append(k)
- dl.append(t._d)
- svals.append(v)
+ if t.kind() == CORBA.tk_null:
+ dl.append(CORBA.TC_any._d)
+ svals.append(CORBA.Any(CORBA.TC_null, None))
+ else:
+ dl.append(t._d)
+ svals.append(v)
cls = omniORB.createUnknownStruct(id, ms)
dl[1] = cls
tc = tcInternal.createTypeCode(tuple(dl))