Topic: static objects in plugins


Author: personne70@hotmail.com (Dimitri Papadopoulos)
Date: Sun, 17 Jun 2001 15:31:07 GMT
Raw View
"Igor A. Goussarov" <igusarov@akella.com> wrote:
>
> > Of course this would mean
> > defining "freestanding environments", "plugins", "modules" and
> > their "termination" but not necessarily. I'm not sure "program"
> > is defined by the standard.
>
>    However if you want to describe what has to happen at the plugin
> startup or exit, you have to describe what a plugin is. This could
> require much more efforts...

Whenever a binary object with code that contains static objects is
"loaded", the constructors of static object should be executed and
when the binary object is "unloaded" destructors should be executed
in the reverese order.

Does the notion of "binary object" need a very precise definition?
Also "unloading" could mean that the code of the binary object is no
longer available for execution for example. Unfortunately I have no
experience of writing international standards so I'm not sure how to
write an acceptable definition for such things.

Dimitri

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Igor A. Goussarov" <igusarov@akella.com>
Date: Thu, 14 Jun 2001 20:33:45 GMT
Raw View
Dimitri Papadopoulos wrote:

> Whenever you see "freestanding environment" read "plugin" - I've
> borrowed the expression from 3.6.1:1.

   Freestanding environment is something different. See 1.4:7 and
17.4.1.3. I believe 'freestanding' means that the program is running
without an OS. (Like BIOS on PCs or some programs for a single-chip
embedded computers)

> Of course this would mean
> defining "freestanding environments", "plugins", "modules" and
> their "termination" but not necessarily. I'm not sure "program"
> is defined by the standard.

   However if you want to describe what has to happen at the plugin
startup or exit, you have to describe what a plugin is. This could
require much more efforts...

Igor

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Igor A. Goussarov" <igusarov@akella.com>
Date: Mon, 11 Jun 2001 20:52:34 GMT
Raw View
Dimitri Papadopoulos wrote:
> I'm using a static object in a plugin and this causes crashes
> with the KAI C++ compiler. All other compilers seem to handle
> this properly. Yet it seems that KAI C++ is conformant and that
> this conformance to the standards is the cause of the crash.
> Let me explain.
>
> Shouldn't paragraph 3.6.3 refrain from referring to main() or exit()
> and paragraph 3.7.1 clarify what is meant by "program" and "duration
> of program"?

   Briefly: destruction of global objects when the plugin module is
unloaded will break the order of destruction, thus breaking other parts
of the Standard.

   Now a little more detailed explanation of this point. Your problem is
not limited to your example. There might be static objects within the
functions like

SomeClass& Foo()
{
 static   SomeClass     A;
 return A;
};

   Here the things are even worse: the objects should be destructed in
the reverse order of their construction and some compilers are using
atexit() for their destruction (with the same result and for the same
reasons as in your example). There are some tricks about avoiding those
bugs, but they have nothing to do with the Standard: it simply doesn't
cover dynamic linking, loadable modules, runtime-modified code, etc.
Mostly because those things (and capabilities) depend on the OS and
therefore are out of compiler's (and language's) control.

   Technically all the dlopen/dlclode business can lead to the violation
of the Standard in one or another way. Imagine this scenario:

1. Main module is loaded
2. Global objects in the main module are initialized
3. main() is entered
4. dlopen() is performed
5. Global objects from that module (Plug_Objs) are initialized
6. Some object A_Obj with static storage duration from the main
   module is initialized
7. dlclose() is performed

   So what is to be done now? The objects should be destroyed in the
reverse order of their construction. Thus Plug_Objs should be destroyed
only after A_Obj is. Should A_Obj be destroyed immediately? If so then
what if the main module still need it? Should the destruction of A_Obj
and Plug_Objs be delayed until A_Obj can be destroyed safely? If so then
what if the destruction code is unavailable at that moment? Should the
RTL detect this situation and refuse to unload the module? But this may
break the logic of the program (e.g. some resources are left unfreed).

   So you see that your problem is not caused by a compiler conformance
or by a clarity of the Standard. It is a conflict between a concept of
dynamically loadable module and static storage duration.

Igor

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Mon, 11 Jun 2001 20:54:14 GMT
Raw View
In article <3B24B355.D48BAE17@BIDON.shfj.cea.fr>, Dimitri Papadopoulos
<papadopo.BIDON@BIDON.shfj.cea.fr> wrote:
>I'm using a static object in a plugin and this causes crashes
>with the KAI C++ compiler. All other compilers seem to handle
>this properly. Yet it seems that KAI C++ is conformant and that
>this conformance to the standards is the cause of the crash.
>Let me explain.
...
>The constructor of this object is called when the library is
>loaded. So far so good.
>
>But when should the destructor of this same object be called?
>
>The standard reads:
...
>I understand that the destructor of 'foo' should be called after
>returning from main(). This is exactly what KAI C++ does and this
>causes a crash because the code of the destructor has been already
>unloaded together with "libplugin.so". All other UNIX compilers
>execute the destructor upon unloading the plugin _before_ returning
>from main().

There is also this quote 3.6.1:1:
  A program shall contain a global function called main, which is the
designated
  start of the program. It is implementation-defined whether a program in a
  freestanding environment is required to define a main function. [Note: in a
  freestanding environment, start-up and termination is implementation-defined;
  start-up contains the execution of constructors for objects of namespace
scope
  with static storage duration; termination contains the execution of
  destructors for objects with static storage duration. ]

So if a DLL can be viewed a "freestanding environment", then it is
implementation defined, it seems.

On my compiler, I have to set special start-up and termination functions
for C++ plugins. If I do not do this, exceptions and standard streams will
not work, etc.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: personne70@hotmail.com (Dimitri Papadopoulos)
Date: Tue, 12 Jun 2001 21:13:54 GMT
Raw View
"Igor A. Goussarov" <igusarov@akella.com> wrote:
> Dimitri Papadopoulos wrote:
> > I'm using a static object in a plugin and this causes crashes
> > with the KAI C++ compiler. All other compilers seem to handle
> > this properly. Yet it seems that KAI C++ is conformant and that
> > this conformance to the standards is the cause of the crash.
> > Let me explain.
> >
> > Shouldn't paragraph 3.6.3 refrain from referring to main() or exit()
> > and paragraph 3.7.1 clarify what is meant by "program" and "duration
> > of program"?
>
>    Briefly: destruction of global objects when the plugin module is
> unloaded will break the order of destruction, thus breaking other parts
> of the Standard.
>
>    Now a little more detailed explanation of this point. Your problem is
> not limited to your example. There might be static objects within the
> functions like
>
> SomeClass& Foo()
> {
>  static   SomeClass     A;
>  return A;
> };
>
>    Here the things are even worse: the objects should be destructed in
> the reverse order of their construction and some compilers are using

Sure but this "objects should be destructed in the reverse order of
their construction" is also part of the problem. I believe it could
be changed to accomodate plugins with no side-effects.

Paragraph 3.6.3:1 could be changed to:

 Destructors (12.4) for initialized objects of static storage
 duration (declared at block scope or at namespace scope) are
 called as a result of returning from main and as a result of
 calling exit (18.3). These objects are destroyed when the
 freestanding environment in which their constructor was
 completed or in which they were dynamically initialized is
 terminated,. Within a single freestanding environment these
 objects are destroyed in the reverse order of the completion
 of their constructor or of the completion of their dynamic
 initialization.

Whenever you see "freestanding environment" read "plugin" - I've
borrowed the expression from 3.6.1:1. Of course this would mean
defining "freestanding environments", "plugins", "modules" and
their "termination" but not necessarily. I'm not sure "program"
is defined by the standard.


> atexit() for their destruction (with the same result and for the same
> reasons as in your example). There are some tricks about avoiding those
> bugs, but they have nothing to do with the Standard: it simply doesn't
> cover dynamic linking, loadable modules, runtime-modified code, etc.
> Mostly because those things (and capabilities) depend on the OS and
> therefore are out of compiler's (and language's) control.

I'm not saying the standard should control those things. I'm saying
it could accomodate those things without actually controlling them.


>    Technically all the dlopen/dlclode business can lead to the violation
> of the Standard in one or another way. Imagine this scenario:
>
> 1. Main module is loaded
> 2. Global objects in the main module are initialized
> 3. main() is entered
> 4. dlopen() is performed
> 5. Global objects from that module (Plug_Objs) are initialized
> 6. Some object A_Obj with static storage duration from the main
>    module is initialized
> 7. dlclose() is performed
>
>    So what is to be done now? The objects should be destroyed in the
> reverse order of their construction. Thus Plug_Objs should be destroyed

Precisely. This "objects should be destroyed in the reverse order
of their construction" thing can be modified to accomodate plugins
without side-effects.


> only after A_Obj is. Should A_Obj be destroyed immediately? If so then
> what if the main module still need it? Should the destruction of A_Obj
> and Plug_Objs be delayed until A_Obj can be destroyed safely? If so then
> what if the destruction code is unavailable at that moment? Should the
> RTL detect this situation and refuse to unload the module? But this may
> break the logic of the program (e.g. some resources are left unfreed).

The "objects should be destroyed in the reverse order of their
construction" rule doesn't solve all problems either. A rule that
would say that objects are destructed with their "freestanding
environment" and then "within this environment in the reverse order
of their construction" certainly does not solve all the above problems
but at least it permits the use of static objects in plugins in simple
cases. This is the only portable way to allocate/release resources
in a "plugin". I believe this is a useful addition to the language.


>    So you see that your problem is not caused by a compiler conformance
> or by a clarity of the Standard. It is a conflict between a concept of
> dynamically loadable module and static storage duration.

Yes, the current static storage duration rules conflict with the
concept of dynamically loadable module. But the whole point of my
post was that static storage duration rules could probably be
modified to accomodate the concept of dynamically loadable module
- without much incidence.

Dimitri

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Dimitri Papadopoulos <papadopo.BIDON@BIDON.shfj.cea.fr>
Date: Mon, 11 Jun 2001 16:25:09 GMT
Raw View
Hi,

I'm using a static object in a plugin and this causes crashes
with the KAI C++ compiler. All other compilers seem to handle
this properly. Yet it seems that KAI C++ is conformant and that
this conformance to the standards is the cause of the crash.
Let me explain.

First and to make things clear, by "plugin" I mean a dynamic
library that is loaded/unloaded at will and explicitely by the
program. As an example, on UNIX loading/unloading the plugin
"libplugin.so" would be coded like this:

 #include <dlfcn.h>
 #include <iostream.h>
 int main() {
      cerr << "Loading library..." << endl;
      void *handle = dlopen("libplugin.so", RTLD_LAZY);
      cerr << "Unloading library..." << endl;
      dlclose(handle);
 }

Now let's suppose that "libplugin.so" contains a static object
such as 'foo' in this example:

 class Foo {
 public:
     Foo();
     ~Foo();
 };
 #include <iostream.h>
 Foo::Foo() {
     cerr << "Foo::Foo()" << endl;
 }
 Foo::~Foo() {
     cerr << "Foo::~Foo()" << endl;
 }
 static Foo foo;

The constructor of this object is called when the library is
loaded. So far so good.

But when should the destructor of this same object be called?

The standard reads:

 3.6.3 Termination

 Destructors (12.4) for initialized objects of static storage
 duration (declared at block scope or at namespace scope) are
 called as a result of returning from main and as a result of
 calling exit (18.3).

 3.7.1 Static storage duration

 All objects which neither have dynamic storage duration
 nor are local have static storage duration. The storage
 for these objects shall last for the duration of the
 program (3.6.2, 3.6.3).

 If an object of static storage duration has initialization
 or a destructor with side effects, it shall not be eliminated
 even if it appears to be unused, except that a class object
 or its copy may be eliminated as specified in 12.8.

I understand that the destructor of 'foo' should be called after
returning from main(). This is exactly what KAI C++ does and this
causes a crash because the code of the destructor has been already
unloaded together with "libplugin.so". All other UNIX compilers
execute the destructor upon unloading the plugin _before_ returning
from main().

Shouldn't paragraph 3.6.3 refrain from referring to main() or exit()
and paragraph 3.7.1 clarify what is meant by "program" and "duration
of program"?

Regards,
--
Dimitri Papadopoulos

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]