From: Thomas J. <tho...@in...> - 2005-06-05 18:30:18
|
Hi, libxml++ uses global initialization code like this: Document::Init::Init() { xmlInitParser(); //Not always necessary, but necessary for thread safety. xmlRegisterNodeDefault(on_libxml_construct); xmlDeregisterNodeDefault(on_libxml_destruct); xmlThrDefRegisterNodeDefault(on_libxml_construct); xmlThrDefDeregisterNodeDefault(on_libxml_destruct); } Document::Init Document::init_; We use PHP as apache module and have another module linking libxml++. The above piece of code totally breaks PHP's XML parser just by loading the second module. Changing the code is not easy as it would break existing applications. One possible solution would be to add a check to every constructor if the library was already initialized. On the destruction of the last libxml++ class if would have to be uninitialized. A more clean way would be to have an init()/deinit() function. Perhaps the use of this mode could be a compile time option? Please let me know what you think about this. Cheers, Thomas |
From: Christophe de V. <cde...@al...> - 2005-06-13 08:26:01
|
Le Dimanche 5 Juin 2005 20:29, Thomas Jarosch a =E9crit=A0: > Hi, > Hi Thomas, Sorry about the delay... > libxml++ uses global initialization code like this: > > Document::Init::Init() > { > xmlInitParser(); //Not always necessary, but necessary for thread > safety. xmlRegisterNodeDefault(on_libxml_construct); > xmlDeregisterNodeDefault(on_libxml_destruct); > xmlThrDefRegisterNodeDefault(on_libxml_construct); > xmlThrDefDeregisterNodeDefault(on_libxml_destruct); > } > > Document::Init Document::init_; > > We use PHP as apache module and have another module linking libxml++. > The above piece of code totally breaks PHP's XML parser > just by loading the second module. Can you be more precise ? What is broken exactly ? It the php xml parser is base on libxml2 and use it's callback (as we do wi= th=20 libxml++), then I don't think a cohexistence is possible. > > Changing the code is not easy as it would break existing applications. > One possible solution would be to add a check to every constructor if the > library was already initialized. On the destruction of the last libxml++ > class if would have to be uninitialized. It's unclear to me if the problem comes from a double-initialisation of=20 libxml++ or a conflit between php and libxml++ which are not able to 'share= '=20 their use of libxml2. Moreover such a test ( checking to every constructor if the library was=20 already initialized) is basically what's being done by the static Init=20 instance. We could maybe add some checks in the Init constructor but I don'= t=20 see a case where it's needed : static should do it for us. > A more clean way would be to have an init()/deinit() function. > Perhaps the use of this mode could be a compile time option? > > Please let me know what you think about this. I'm unsure about this. I don't think having a different behavior (ie the us= er=20 being obliged to call the init/deinit functions) based on a compile-time=20 option is a good idea. Anyway if the problem really comes from here you can= =20 try and patch libxml++ to see if it's fixing you problems. Regards, Christophe |
From: Thomas J. <tho...@in...> - 2005-06-13 08:39:49
|
Christophe, On Monday 13 June 2005 10:25, Christophe de VIENNE wrote: > > Document::Init Document::init_; > > > > We use PHP as apache module and have another module linking libxml++. > > The above piece of code totally breaks PHP's XML parser > > just by loading the second module. > > Can you be more precise ? What is broken exactly ? > It the php xml parser is base on libxml2 and use it's callback (as we do > with libxml++), then I don't think a cohexistence is possible. PHP uses libxml2 without those callbacks. As soon as I create a node using PHP function calls, I end up in libxml++'s callback :o) > > Changing the code is not easy as it would break existing applications. > > One possible solution would be to add a check to every constructor if the > > library was already initialized. On the destruction of the last libxml++ > > class if would have to be uninitialized. > > It's unclear to me if the problem comes from a double-initialisation of > libxml++ or a conflit between php and libxml++ which are not able to > 'share' their use of libxml2. > Moreover such a test ( checking to every constructor if the library was > already initialized) is basically what's being done by the static Init > instance. We could maybe add some checks in the Init constructor but I > don't see a case where it's needed : static should do it for us. The problem with the "static" class is that it gets executed during library load time. This is why it breaks PHP. > > A more clean way would be to have an init()/deinit() function. > > Perhaps the use of this mode could be a compile time option? > > > > Please let me know what you think about this. > > I'm unsure about this. I don't think having a different behavior (ie the > user being obliged to call the init/deinit functions) based on a > compile-time option is a good idea. Anyway if the problem really comes from > here you can try and patch libxml++ to see if it's fixing you problems. I already did and it fixed the problem. Took me hours to debug it until I realized what's really happening (PHP just started to segfault). The question is now if there's a more elegant solution than having a compile-time option? Cheers, Thomas |
From: Christophe de V. <cde...@al...> - 2005-06-13 09:13:25
|
Le Lundi 13 Juin 2005 10:39, Thomas Jarosch a =E9crit=A0: > Christophe, > > I already did and it fixed the problem. Took me hours to debug it > until I realized what's really happening (PHP just started to segfault). So it's really the multiple loading of libxml++ then. > The question is now if there's a more elegant solution > than having a compile-time option? I wonder if the nifty-counter idiom can solve this without changing the=20 current behavior, nor breaking the ABI. The question is, in the case of multiple load of a library, are the interna= l=20 variable shared by the different instances, or duplicated ? Regards, Christophe |
From: Christophe de V. <cde...@al...> - 2005-06-13 09:16:58
|
Le Lundi 13 Juin 2005 10:39, Thomas Jarosch a =E9crit=A0: > > Can you be more precise ? What is broken exactly ? > > It the php xml parser is base on libxml2 and use it's callback (as we do > > with libxml++), then I don't think a cohexistence is possible. > > PHP uses libxml2 without those callbacks. As soon as I create a node using > PHP function calls, I end up in libxml++'s callback :o) Wait, is the problem the callbacks themselves ? Are they disturbing the php= =20 xml parser ? the thing is that libxml++ cannot work properly without them. > > The problem with the "static" class is that it gets executed > during library load time. This is why it breaks PHP. Do you need it not to be executed at all, or only once ? Regards Christophe |
From: Thomas J. <tho...@in...> - 2005-06-13 09:33:23
|
On Monday 13 June 2005 11:16, Christophe de VIENNE wrote: > Le Lundi 13 Juin 2005 10:39, Thomas Jarosch a =E9crit=A0: > > > Can you be more precise ? What is broken exactly ? > > > It the php xml parser is base on libxml2 and use it's callback (as we > > > do with libxml++), then I don't think a cohexistence is possible. > > > > PHP uses libxml2 without those callbacks. As soon as I create a node > > using PHP function calls, I end up in libxml++'s callback :o) > > Wait, is the problem the callbacks themselves ? Are they disturbing the p= hp > xml parser ? the thing is that libxml++ cannot work properly without them. Exactly! The root of the problems seems to be that libxml++ and PHP both manipulate the node->_private pointer for their own needs. > > The problem with the "static" class is that it gets executed > > during library load time. This is why it breaks PHP. > > Do you need it not to be executed at all, or only once ? Only init once and reset after libxm++ code usage. Something like: =2D libxml::init() =2D XML manipultions via libxml++ =2D libxml::deinit() Cheers, Thomas |
From: Christophe de V. <cde...@al...> - 2005-06-13 09:59:44
|
Le Lundi 13 Juin 2005 11:33, Thomas Jarosch a =E9crit=A0: > On Monday 13 June 2005 11:16, Christophe de VIENNE wrote: > > Le Lundi 13 Juin 2005 10:39, Thomas Jarosch a =E9crit=A0: > > > > Can you be more precise ? What is broken exactly ? > > > > It the php xml parser is base on libxml2 and use it's callback (as = we > > > > do with libxml++), then I don't think a cohexistence is possible. > > > > > > PHP uses libxml2 without those callbacks. As soon as I create a node > > > using PHP function calls, I end up in libxml++'s callback :o) > > > > Wait, is the problem the callbacks themselves ? Are they disturbing the > > php xml parser ? the thing is that libxml++ cannot work properly without > > them. > > Exactly! The root of the problems seems to be that libxml++ and PHP > both manipulate the node->_private pointer for their own needs. Now it's clearer :-) > > > The problem with the "static" class is that it gets executed > > > during library load time. This is why it breaks PHP. > > > > Do you need it not to be executed at all, or only once ? > > Only init once and reset after libxm++ code usage. > Something like: > > - libxml::init() > - XML manipultions via libxml++ > - libxml::deinit() Well, to do libxml::init() and libxml::deinit(), you can simply control a=20 Document::Init instance. The thing is that you need it not to be default initiated. Globally, this solution looks heavy to me, but I don't see a workaround. So it looks like a --disable-static-initialisation in the configure script= =20 would solve the issue. Any objection ? Christophe |
From: Thomas J. <tho...@in...> - 2005-06-13 11:08:19
|
> > > > The problem with the "static" class is that it gets executed > > > > during library load time. This is why it breaks PHP. > > > > > > Do you need it not to be executed at all, or only once ? > > > > Only init once and reset after libxm++ code usage. > > Something like: > > > > - libxml::init() > > - XML manipultions via libxml++ > > - libxml::deinit() > > Well, to do libxml::init() and libxml::deinit(), you can simply control a > Document::Init instance. > The thing is that you need it not to be default initiated. > Globally, this solution looks heavy to me, but I don't see a workaround. > > So it looks like a --disable-static-initialisation in the configure script > would solve the issue. > > Any objection ? Fine with me. Of course we have to add a destructor to the Document::Init class and reset the callbacks. The Document::Init constructor needs an additional parameter (default: true) if it should call xmlCleanupParser() during destruction. I had another idea: Would it be possible to create the global _init object via an include file? #define LIBXMLPP_DISABLE_STATIC_INIT 1 #include <libxml++.h> Multiple applications which use libxml++ could still share the same binary library file. Thomas |
From: Thomas J. <tho...@in...> - 2005-06-16 16:51:21
Attachments:
libxml++-no-static-init.patch
|
Christophe, On Monday 13 June 2005 13:08, Thomas Jarosch wrote: > > So it looks like a --disable-static-initialisation in the configure > > script would solve the issue. > > > > Any objection ? > > Fine with me. Of course we have to add a destructor to the Document::Init > class and reset the callbacks. The Document::Init constructor needs an > additional parameter (default: true) if it should call xmlCleanupParser() > during destruction. > > I had another idea: > Would it be possible to create the global _init object via an include file? > > #define LIBXMLPP_DISABLE_STATIC_INIT 1 > #include <libxml++.h> > > Multiple applications which use libxml++ could still > share the same binary library file. I implemented the code like I wrote above. And it works :-) It's not ABI compatible as the new library doesn't contain the static init object, but it's 100% API compatile. -> It's best to bumb the .so version for the next release. Please let me know what you think. Cheers, Thomas |
From: Thomas J. <tho...@in...> - 2005-06-17 07:39:18
|
Good morning, On Friday 17 June 2005 09:34, Christophe de VIENNE wrote: > > > > >>I implemented the code like I wrote above. And it works :-) > > > > >>It's not ABI compatible as the new library doesn't contain the > > > > >> static init object, but it's 100% API compatile. -> It's best to > > > > >> bumb the .so version for the next release. > > > > > > > > > > That would be highly undesirable. ABI compatibility must be > > > > > maintained until we have a really good reason to break it. > > > > > > > > What is holding you back from making the global init object do > > > > strictly nothing, so its only purpose is to keep ABI compatibility > > > > and users may or may not use it in their application ? > > > > > > > > Then, you are ready to remove it when you have other reasons to break > > > > ABI compatibility. > > > > > > This is a great idea. I'll cook up a new version of the patch the next > > > days. > > > > I was typing faster than thinking... doing nothing is not possible > > as libxml2 needs to be initialized. IMHO there is no ABI compatible > > way of replacing the global initialization code, is there? > > I think so, with the global init doing nothing IF an environnement variable > "LIBXMLPP_NO_STATIC_INIT" has been defined. This still requires recompilation and is therefore not ABI compatible, IMHO. Cheers, Thomas |
From: Christophe de V. <cde...@al...> - 2005-06-17 07:51:44
|
Good morning, Le Vendredi 17 Juin 2005 09:39, Thomas Jarosch a =E9crit=A0: > > > I was typing faster than thinking... doing nothing is not possible > > > as libxml2 needs to be initialized. IMHO there is no ABI compatible > > > way of replacing the global initialization code, is there? > > > > I think so, with the global init doing nothing IF an environnement > > variable "LIBXMLPP_NO_STATIC_INIT" has been defined. > > This still requires recompilation and is therefore not ABI compatible, > IMHO. I think I disagree : the current global initialisation is done by Init::Ini= t.=20 We can, without breaking the ABI, change its behavior so it does nothing wh= en=20 a particular environment variable is set. We can add another class, let's say InitNG, which does what you suggested f= or=20 Init. This way people who want to do manual initialisation can do it by setting t= his=20 variable. Another way I just thought about is not to change Init::Init behavior, but= =20 adding both another init class and a free function (probably a static=20 function of the new init class) which undo what Init have done and forces=20 it's destructor not to do anything. The advantage is that the proper behavior of the program does not depend on= a=20 user intervention. Christophe |
From: Thomas J. <tho...@in...> - 2005-06-17 08:04:13
|
> > > I think so, with the global init doing nothing IF an environnement > > > variable "LIBXMLPP_NO_STATIC_INIT" has been defined. > > > > This still requires recompilation and is therefore not ABI compatible, > > IMHO. > > I think I disagree : the current global initialisation is done by > Init::Init. We can, without breaking the ABI, change its behavior so it > does nothing when a particular environment variable is set. > We can add another class, let's say InitNG, which does what you suggested > for Init. > This way people who want to do manual initialisation can do it by setting > this variable. Sorry, missed the environment part while reading as you wrote the french version ;-) I would take the the environment variable as last option because that's not very intuitive for the end user. (f.e. program crashes because he/she forget to set it) > Another way I just thought about is not to change Init::Init behavior, but > adding both another init class and a free function (probably a static > function of the new init class) which undo what Init have done and forces > it's destructor not to do anything. > The advantage is that the proper behavior of the program does not depend on > a user intervention. That would be an option, though it's still messy. Is there a garantuee from the compiler in which order global objects are created? Thomas |
From: Christophe de V. <cde...@al...> - 2005-06-17 08:41:57
|
Le Vendredi 17 Juin 2005 10:04, Thomas Jarosch a =E9crit=A0: > > > > I think so, with the global init doing nothing IF an environnement > > > > variable "LIBXMLPP_NO_STATIC_INIT" has been defined. > > > > > > This still requires recompilation and is therefore not ABI compatible, > > > IMHO. > > > > I think I disagree : the current global initialisation is done by > > Init::Init. We can, without breaking the ABI, change its behavior so it > > does nothing when a particular environment variable is set. > > We can add another class, let's say InitNG, which does what you suggest= ed > > for Init. > > This way people who want to do manual initialisation can do it by setti= ng > > this variable. > > Sorry, missed the environment part while reading > as you wrote the french version ;-) Sorry :-) > I would take the the environment variable as last option > because that's not very intuitive for the end user. > (f.e. program crashes because he/she forget to set it) I don't think it's a good solution either. > > Another way I just thought about is not to change Init::Init behavior, > > but adding both another init class and a free function (probably a stat= ic > > function of the new init class) which undo what Init have done and forc= es > > it's destructor not to do anything. > > The advantage is that the proper behavior of the program does not depend > > on a user intervention. > > That would be an option, though it's still messy. A bit messy, but still better than the environment variable solution (it do= es=20 not rely on the user, so it's reliable), and not breaking the ABI. =46or now I don't see another way to achieve your goal not breaking the abi= and=20 being reliable. The only other way would need a specific compilation of libxml++ for your=20 project, which break the ABI. > Is there a garantuee=20 > from the compiler in which order global objects are created? Unfortunately no. That would be too easy :-) I know that with gcc we can be= =20 pretty sure the library global initialisation is done before the main progr= am=20 one. But we can't rely on it, as other compilers will cause problems. Regards, Christophe |