Global variable in static library - double free or corruption error

classic Classic list List threaded Threaded
24 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Global variable in static library - double free or corruption error

Alexey Skidanov-2
Hello,
We use the gcc 4.1.1 in our project. After some code refactoring
(creating new shared library) the application crashes at exit with
following error:

*** glibc detected *** : double free or corruption (fasttop) ***

In order to simulate our application, I created the test one, with two
shared libraries and one static library. The code is below:

static.h

#ifndef STATIC
#define STATIC

using namespace std;

void set(int index, int value);

#endif /* STATIC */

static.cpp:

#include "static.h"
#include <stdio.h>

class TestClass {
public:
    TestClass() {
            printf("TestClass ctor %p %p\n", this, m_p);
            m_p = new int[10];
            printf("TestClass ctor %p\n", m_p);
    }
    ~TestClass() {
            printf("TestClass dtor %p %p\n", this, m_p);
            delete [] m_p;
            // m_p = NULL;

    }

    void set(int index, int value) {
            m_p[index] = value;
    }
   

private:
    int* m_p;

};



TestClass test_var;


void set(int index, int value) {
    test_var.set(index, value);
}

dynamic1.h

#ifndef DYNAMIC_1
#define DYNAMIC_1

void set1(int index, int value);

#endif /* DYNAMIC_1 */

dynamic1.cpp

#include "static.h"
#include "dynamic1.h"

void set1(int index, int value) {
    set(index, value);
}

dynamic2.h

#ifndef DYNAMIC_2
#define DYNAMIC_2

void set2(int index, int value);

#endif /* DYNAMIC_2 */

dynamic.cpp
#include "static.h"
#include "dynamic2.h"

void set2(int index, int value) {
    set(index, value);
}

main.cpp
#include "dynamic1.h"
#include "dynamic2.h"


int main() {

    set1(0, 0);
    set2(1, 1);

}

test application have been compiled:

g++  -g -c static.cpp -o static.o
ar rcs  libstatic.a static.o
g++ -g -shared -fPIC dynamic1.cpp -L. -lstatic -o libdynamic1.so
g++ -g -shared -fPIC dynamic2.cpp -L. -lstatic -o libdynamic2.so
g++ -g main.cpp -L. -ldynamic1 -ldynamic2  -o test

Running the test application I get the following:

TestClass ctor 0x60ca9c (nil)
TestClass ctor 0x936f008
TestClass ctor 0x60ca9c 0x936f008
TestClass ctor 0x936f038
TestClass dtor 0x60ca9c 0x936f038
TestClass dtor 0x60ca9c 0x936f038
*** glibc detected *** ./test: double free or corruption (fasttop):
0x0936f038 ***
======= Backtrace: =========
/lib/libc.so.6[0x178aa6]
/lib/libc.so.6(cfree+0x90)[0x17bfc0]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x953ef1]
/usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0x953f4d]
./libdynamic1.so(_ZN9TestClassD1Ev+0x38)[0x60b7b8]
./libdynamic2.so[0x11071a]
/lib/libc.so.6(__cxa_finalize+0xa9)[0x13db09]
./libdynamic2.so[0x1105f3]
./libdynamic2.so[0x11080c]
/lib/ld-linux.so.2[0x48e6de]
/lib/libc.so.6(exit+0xe9)[0x13d859]
/lib/libc.so.6(__libc_start_main+0xe4)[0x127df4]
./test(__gxx_personality_v0+0x31)[0x8048491]
======= Memory map: ========
00110000-00111000 r-xp 00000000 00:12 4091188
/home/alexey-s/Samples/SingletonInStatic/libdynamic2.so
00111000-00112000 rwxp 00000000 00:12 4091188
/home/alexey-s/Samples/SingletonInStatic/libdynamic2.so
00112000-0024c000 r-xp 00000000 08:02 265363     /lib/libc-2.5.so
0024c000-0024e000 r-xp 0013a000 08:02 265363     /lib/libc-2.5.so
0024e000-0024f000 rwxp 0013c000 08:02 265363     /lib/libc-2.5.so
0024f000-00252000 rwxp 0024f000 00:00 0
00480000-00499000 r-xp 00000000 08:02 265342     /lib/ld-2.5.so
00499000-0049a000 r-xp 00019000 08:02 265342     /lib/ld-2.5.so
0049a000-0049b000 rwxp 0001a000 08:02 265342     /lib/ld-2.5.so
00538000-00539000 r-xp 00538000 00:00 0          [vdso]
005e4000-00609000 r-xp 00000000 08:02 265370     /lib/libm-2.5.so
00609000-0060a000 r-xp 00024000 08:02 265370     /lib/libm-2.5.so
0060a000-0060b000 rwxp 00025000 08:02 265370     /lib/libm-2.5.so
0060b000-0060c000 r-xp 00000000 00:12 4091181
/home/alexey-s/Samples/SingletonInStatic/libdynamic1.so
0060c000-0060d000 rwxp 00000000 00:12 4091181
/home/alexey-s/Samples/SingletonInStatic/libdynamic1.so
00887000-00892000 r-xp 00000000 08:02 265372
/lib/libgcc_s-4.1.2-20070626.so.1
00892000-00893000 rwxp 0000a000 08:02 265372
/lib/libgcc_s-4.1.2-20070626.so.1
008a0000-00980000 r-xp 00000000 08:02 3115867
/usr/lib/libstdc++.so.6.0.8
00980000-00983000 r-xp 000e0000 08:02 3115867
/usr/lib/libstdc++.so.6.0.8
00983000-00985000 rwxp 000e3000 08:02 3115867
/usr/lib/libstdc++.so.6.0.8
00985000-0098b000 rwxp 00985000 00:00 0
08048000-08049000 r-xp 00000000 00:12 4091189
/home/alexey-s/Samples/SingletonInStatic/test
08049000-0804a000 rw-p 00000000 00:12 4091189
/home/alexey-s/Samples/SingletonInStatic/test
0936f000-09390000 rw-p 0936f000 00:00 0
b7e00000-b7e21000 rw-p b7e00000 00:00 0
b7e21000-b7f00000 ---p b7e21000 00:00 0
b7fba000-b7fbc000 rw-p b7fba000 00:00 0
b7fda000-b7fdc000 rw-p b7fda000 00:00 0
bf844000-bf859000 rw-p bf844000 00:00 0          [stack]
Abort

Static library defines some global variable (test_var), that during
library linking "injected" into the dynamic library bss segment.
Actually, static.o object file is linked with dynamic1.o and with
dynamic2.o files.
Please, pay attention that constructor and destructor of the SAME
INSTANCE (at address 0x60ca9c) of global variable were called twice - at
each dynamic library start up. Generally, it seems that this is partial
solution of double definition problem during main application linking:  
Dynamic linker somehow merges two definition of the same global variable
- but each shared library start up code contains calls of this variable
constructor and destructor.

I would expect that TWO different instances of the global variable would
be created in TWO different shared libraries - maybe with name mangling.


Is this a linker/loader bug? Can we cause (by linker/loader options)
linker/loader more consistent behavior?

Thanks,
Alexey

Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Jeffrey Walton-3
Hi Alexey,

I saw the same thing in Crypto++ when distributions began
porting/packaging as shared object [1, 2]. The mailing list was
getting 'double free' reports under obscure circumstances [3]. [2] was
a test case to reproduce and looks exactly like your analysis :).

Anyway, the fix is to hide the the global TestClass:

OLD:
TestClass test_var;

NEW:
TestClass& GetTestClass()
{
    static TestClass test_var;
    return test_var;
}

I just opened a feature request for a -Wglobal-variable  for this sort
of thing: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46097.

You might chime in on the issue since the GCC team is contemplating
whether the feature is even worth while. I claim it is because this
behavior has jumped up a bit a few people in the ass. I was thinking
that -Wglobal-variable should be a part of -Wextra, and possibly
-Wall.

Jeff

[1] http://www.cryptopp.com/wiki/Linux#Shared_Objects_and_Globals
[2] RTLD_GLOBAL and libcryptopp.so crash,
http://groups.google.com/group/cryptopp-users/browse_thread/thread/7eae009a4e02e726
[3] Errors with multiple loading cryptopp as shared lib on Linux,
http://groups.google.com/group/cryptopp-users/browse_thread/thread/68fbc22e8c6e2f48

On Thu, Oct 21, 2010 at 7:53 AM, Alexey Skidanov
<[hidden email]> wrote:

> Hello,
> We use the gcc 4.1.1 in our project. After some code refactoring
> (creating new shared library) the application crashes at exit with
> following error:
>
> *** glibc detected *** : double free or corruption (fasttop) ***
>
> In order to simulate our application, I created the test one, with two
> shared libraries and one static library. The code is below:
>
> [SNIP]
>
> Static library defines some global variable (test_var), that during
> library linking "injected" into the dynamic library bss segment.
> Actually, static.o object file is linked with dynamic1.o and with
> dynamic2.o files.
> Please, pay attention that constructor and destructor of the SAME
> INSTANCE (at address 0x60ca9c) of global variable were called twice - at
> each dynamic library start up. Generally, it seems that this is partial
> solution of double definition problem during main application linking:
> Dynamic linker somehow merges two definition of the same global variable
> - but each shared library start up code contains calls of this variable
> constructor and destructor.
>
> I would expect that TWO different instances of the global variable would
> be created in TWO different shared libraries - maybe with name mangling.
>
>
> Is this a linker/loader bug? Can we cause (by linker/loader options)
> linker/loader more consistent behavior?
>
> Thanks,
> Alexey
>
>
Reply | Threaded
Open this post in threaded view
|

RE: Global variable in static library - double free or corruption error

Alexey Skidanov-2
Hi Jeffrey,

Thanks for your response. You are absolutely right regarding to
-Wglobal-variable. I would prefer to get some kind of error (linking
error?) about two global variables with the same name instead of dynamic
loader/linker decision to "merge" them.

Thanks,
Alexey

-----Original Message-----
From: Jeffrey Walton [mailto:[hidden email]]
Sent: Thursday, October 21, 2010 5:00 PM
To: Alexey Skidanov
Cc: [hidden email]; [hidden email]
Subject: Re: Global variable in static library - double free or
corruption error

Hi Alexey,

I saw the same thing in Crypto++ when distributions began
porting/packaging as shared object [1, 2]. The mailing list was
getting 'double free' reports under obscure circumstances [3]. [2] was
a test case to reproduce and looks exactly like your analysis :).

Anyway, the fix is to hide the the global TestClass:

OLD:
TestClass test_var;

NEW:
TestClass& GetTestClass()
{
    static TestClass test_var;
    return test_var;
}

I just opened a feature request for a -Wglobal-variable  for this sort
of thing: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46097.

You might chime in on the issue since the GCC team is contemplating
whether the feature is even worth while. I claim it is because this
behavior has jumped up a bit a few people in the ass. I was thinking
that -Wglobal-variable should be a part of -Wextra, and possibly
-Wall.

Jeff

[1] http://www.cryptopp.com/wiki/Linux#Shared_Objects_and_Globals
[2] RTLD_GLOBAL and libcryptopp.so crash,
http://groups.google.com/group/cryptopp-users/browse_thread/thread/7eae0
09a4e02e726
[3] Errors with multiple loading cryptopp as shared lib on Linux,
http://groups.google.com/group/cryptopp-users/browse_thread/thread/68fbc
22e8c6e2f48

On Thu, Oct 21, 2010 at 7:53 AM, Alexey Skidanov
<[hidden email]> wrote:

> Hello,
> We use the gcc 4.1.1 in our project. After some code refactoring
> (creating new shared library) the application crashes at exit with
> following error:
>
> *** glibc detected *** : double free or corruption (fasttop) ***
>
> In order to simulate our application, I created the test one, with two
> shared libraries and one static library. The code is below:
>
> [SNIP]
>
> Static library defines some global variable (test_var), that during
> library linking "injected" into the dynamic library bss segment.
> Actually, static.o object file is linked with dynamic1.o and with
> dynamic2.o files.
> Please, pay attention that constructor and destructor of the SAME
> INSTANCE (at address 0x60ca9c) of global variable were called twice -
at
> each dynamic library start up. Generally, it seems that this is
partial
> solution of double definition problem during main application linking:
> Dynamic linker somehow merges two definition of the same global
variable
> - but each shared library start up code contains calls of this
variable
> constructor and destructor.
>
> I would expect that TWO different instances of the global variable
would
> be created in TWO different shared libraries - maybe with name
mangling.
>
>
> Is this a linker/loader bug? Can we cause (by linker/loader options)
> linker/loader more consistent behavior?
>
> Thanks,
> Alexey
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Vladimir Simonov-2
Hi all,

Have you tried to add -fvisibility=hidden to
"g++  -g -c static.cpp -o static.o" ?

I guess it should fix the problem. Sorry, I have no gcc 4.1.1
to check. As I remember gcc 4.1.x had -fvisibility=default by
default.  Newer gcc has -fvisibility=hidden.

Really it is very good thing to have -fvisibility=hidden
as default (specified explicitly in command line),
especially for shared libraries.

Best regards
Vladimir Simonov


On 10/21/2010 07:34 PM, Alexey Skidanov wrote:

> Hi Jeffrey,
>
> Thanks for your response. You are absolutely right regarding to
> -Wglobal-variable. I would prefer to get some kind of error (linking
> error?) about two global variables with the same name instead of dynamic
> loader/linker decision to "merge" them.
>
> Thanks,
> Alexey
>
> -----Original Message-----
> From: Jeffrey Walton [mailto:[hidden email]]
> Sent: Thursday, October 21, 2010 5:00 PM
> To: Alexey Skidanov
> Cc: [hidden email]; [hidden email]
> Subject: Re: Global variable in static library - double free or
> corruption error
>
> Hi Alexey,
>
> I saw the same thing in Crypto++ when distributions began
> porting/packaging as shared object [1, 2]. The mailing list was
> getting 'double free' reports under obscure circumstances [3]. [2] was
> a test case to reproduce and looks exactly like your analysis :).
>
> Anyway, the fix is to hide the the global TestClass:
>
> OLD:
> TestClass test_var;
>
> NEW:
> TestClass&  GetTestClass()
> {
>      static TestClass test_var;
>      return test_var;
> }
>
> I just opened a feature request for a -Wglobal-variable  for this sort
> of thing: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46097.
>
> You might chime in on the issue since the GCC team is contemplating
> whether the feature is even worth while. I claim it is because this
> behavior has jumped up a bit a few people in the ass. I was thinking
> that -Wglobal-variable should be a part of -Wextra, and possibly
> -Wall.
>
> Jeff
>
> [1] http://www.cryptopp.com/wiki/Linux#Shared_Objects_and_Globals
> [2] RTLD_GLOBAL and libcryptopp.so crash,
> http://groups.google.com/group/cryptopp-users/browse_thread/thread/7eae0
> 09a4e02e726
> [3] Errors with multiple loading cryptopp as shared lib on Linux,
> http://groups.google.com/group/cryptopp-users/browse_thread/thread/68fbc
> 22e8c6e2f48
>
> On Thu, Oct 21, 2010 at 7:53 AM, Alexey Skidanov
> <[hidden email]>  wrote:
>> Hello,
>> We use the gcc 4.1.1 in our project. After some code refactoring
>> (creating new shared library) the application crashes at exit with
>> following error:
>>
>> *** glibc detected *** : double free or corruption (fasttop) ***
>>
>> In order to simulate our application, I created the test one, with two
>> shared libraries and one static library. The code is below:
>>
>> [SNIP]
>>
>> Static library defines some global variable (test_var), that during
>> library linking "injected" into the dynamic library bss segment.
>> Actually, static.o object file is linked with dynamic1.o and with
>> dynamic2.o files.
>> Please, pay attention that constructor and destructor of the SAME
>> INSTANCE (at address 0x60ca9c) of global variable were called twice -
> at
>> each dynamic library start up. Generally, it seems that this is
> partial
>> solution of double definition problem during main application linking:
>> Dynamic linker somehow merges two definition of the same global
> variable
>> - but each shared library start up code contains calls of this
> variable
>> constructor and destructor.
>>
>> I would expect that TWO different instances of the global variable
> would
>> be created in TWO different shared libraries - maybe with name
> mangling.
>>
>>
>> Is this a linker/loader bug? Can we cause (by linker/loader options)
>> linker/loader more consistent behavior?
>>
>> Thanks,
>> Alexey
>>
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Andrew Haley
In reply to this post by Alexey Skidanov-2
On 10/21/2010 04:34 PM, Alexey Skidanov wrote:

> Thanks for your response. You are absolutely right regarding to
> -Wglobal-variable. I would prefer to get some kind of error (linking
> error?) about two global variables with the same name instead of dynamic
> loader/linker decision to "merge" them.

This is standard, and correct behaviour.  The One Definition Rule says
that there can only ever be one definition of a symbol in a program, and
UNIX has always merged multiple definitions to achieve this.  Also, plenty
of programs depend on this behaviour: it's just something to get used to.

Andrew.
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Jeffrey Walton-3
> that there can only ever be one definition of a symbol in a program, and
> UNIX has always merged multiple definitions to achieve this
Does the rule include that gloabl object destructors are to run on
every unload, or the last/final unload or last call to dlclose (when
the shared object gets unmapped)? Many folks don't expect their
objects will be pulled out from under them until the last unload. It
seems like a reasonable expectation to me.

>  it's just something to get used to
Agreed.

On Thu, Oct 21, 2010 at 12:10 PM, Andrew Haley <[hidden email]> wrote:

> On 10/21/2010 04:34 PM, Alexey Skidanov wrote:
>
>> Thanks for your response. You are absolutely right regarding to
>> -Wglobal-variable. I would prefer to get some kind of error (linking
>> error?) about two global variables with the same name instead of dynamic
>> loader/linker decision to "merge" them.
>
> This is standard, and correct behaviour.  The One Definition Rule says
> that there can only ever be one definition of a symbol in a program, and
> UNIX has always merged multiple definitions to achieve this.  Also, plenty
> of programs depend on this behaviour: it's just something to get used to.
>
> Andrew.
>
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Andrew Haley
On 10/21/2010 05:23 PM, Jeffrey Walton wrote:
>> that there can only ever be one definition of a symbol in a program, and
>> UNIX has always merged multiple definitions to achieve this
> Does the rule include that gloabl object destructors are to run on
> every unload, or the last/final unload or last call to dlclose (when
> the shared object gets unmapped)?

I suspect that Bad Things would happen.  :-)

As far as I know, they are run, and if you have two definitions
of some object with a destructor, then you violate the ODR rule,
and it's all your fault!

> Many folks don't expect their
> objects will be pulled out from under them until the last unload. It
> seems like a reasonable expectation to me.

Sure, but you break the rules, you get to keep all the pieces.

Andrew.
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Alexey Skidanov-3
Actually, you claim that if some static library defines some global variable,
then it should NOT be linked with more then one shared library. That is, if you
have the dependencies tree like in my example then you have a problem. Think
about such static library is third party library where I can't change the code.

Regarding the ODR. You are absolutly right. But what about a MULTIPLE variable
initialization. Is it correct behaviour according to standard? 

Alexey
________________________________
From: Andrew Haley <[hidden email]>
To: [hidden email]
Cc: Alexey Skidanov <[hidden email]>; [hidden email];
[hidden email]
Sent: Thu, October 21, 2010 7:37:25 PM
Subject: Re: Global variable in static library - double free or corruption error

On 10/21/2010 05:23 PM, Jeffrey Walton wrote:
>> that there can only ever be one definition of a symbol in a program, and
>> UNIX has always merged multiple definitions to achieve this
> Does the rule include that gloabl object destructors are to run on
> every unload, or the last/final unload or last call to dlclose (when
> the shared object gets unmapped)?

I suspect that Bad Things would happen.  :-)

As far as I know, they are run, and if you have two definitions
of some object with a destructor, then you violate the ODR rule,
and it's all your fault!

> Many folks don't expect their
> objects will be pulled out from under them until the last unload. It
> seems like a reasonable expectation to me.

Sure, but you break the rules, you get to keep all the pieces.

Andrew.




Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Jeffrey Walton-3
In reply to this post by Andrew Haley
On Thu, Oct 21, 2010 at 1:37 PM, Andrew Haley <[hidden email]> wrote:

> On 10/21/2010 05:23 PM, Jeffrey Walton wrote:
>>> that there can only ever be one definition of a symbol in a program,
>>> and UNIX has always merged multiple definitions to achieve this
>> Does the rule include that gloabl object destructors are to run on
>> every unload, or the last/final unload or last call to dlclose (when
>> the shared object gets unmapped)?
>
> I suspect that Bad Things would happen.  :-)
>
> As far as I know, they are run, and if you have two definitions
> of some object with a destructor, then you violate the ODR rule,
> and it's all your fault!
When I look at the original source files, it is clear that there is
one definition. I'm not sure what is getting lost in the translation,
but the runtime link-loader 'multiplying definitions' which lead to a
crash is not desired behavior. I would claim it is a bug.

Since what happens in one module crashes another module, I would go
out on a limb and claim this bug might have security implications.

>> Many folks don't expect their objects will be pulled out from
>> under them until the last unload. It seems like a reasonable
>> expectation to me.
> Sure, but you break the rules, you get to keep all the pieces.
I think the problem here is that the rule is f**k'd up. I would argue
that many folks probably know about the rule. But how many know about
it because they got bit in the ass by it versus RTFM'ing the manual in
their spare time?

In essence, the rule creates "Shared (Global) Data Segments" in the
Microsoft world. Those things are quite dangerous (because one process
can cause another to crash) and code cannot pass a security related
quality gates if present [1]. In the Microsoft world, if you want to
take the bull by the horns, you have to go out of your way to get it -
it is not default behavior [2].

(And I know M$ is not a stellar example of security).

Making a bad choice (ie, 'the rule') and documenting it does not make
it all OK. Its not reasonably expected behavior, and it might have
security implications.

Jeffrey Walton

[1] Howard and LeBlac, Writing Secure Code, ISBN 0-7356-1722-8, p. 677-78
[2] How do I share data in my DLL with an application or with other
DLLs?, http://msdn.microsoft.com/en-us/library/h90dkhs0%28VS.80%29.aspx
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Marc Glisse-6
On Thu, 21 Oct 2010, Alexey Skidanov wrote:

> Actually, you claim that if some static library defines some global variable,
> then it should NOT be linked with more then one shared library.

Static libraries should only be linked with the executable. Shared objects
are perfectly fine with undefined symbols. (Of course this is only a
general rule, there can be good reasons to ignore it)



On Thu, 21 Oct 2010, Jeffrey Walton wrote:

> In essence, the rule creates "Shared (Global) Data Segments" in the
> Microsoft world. Those things are quite dangerous (because one process
> can cause another to crash)

Er, I don't know about shared global data segments, but in this thread
there is no mention of crossing the process boundary, only merging 2
variables in a given process.

--
Marc Glisse
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Alexey Skidanov-3
In reply to this post by Jeffrey Walton-3
HI,
I'm absolutely agree with Jeffrey. In addition, if I violate the ODR rule,
linker shoud issue an error at link time and should not try to force it
partially.

Alexey

  



----- Original Message ----
From: Jeffrey Walton <[hidden email]>
To: Andrew Haley <[hidden email]>
Cc: Alexey Skidanov <[hidden email]>; [hidden email];
[hidden email]
Sent: Thu, October 21, 2010 10:21:47 PM
Subject: Re: Global variable in static library - double free or corruption error

On Thu, Oct 21, 2010 at 1:37 PM, Andrew Haley <[hidden email]> wrote:

> On 10/21/2010 05:23 PM, Jeffrey Walton wrote:
>>> that there can only ever be one definition of a symbol in a program,
>>> and UNIX has always merged multiple definitions to achieve this
>> Does the rule include that gloabl object destructors are to run on
>> every unload, or the last/final unload or last call to dlclose (when
>> the shared object gets unmapped)?
>
> I suspect that Bad Things would happen.  :-)
>
> As far as I know, they are run, and if you have two definitions
> of some object with a destructor, then you violate the ODR rule,
> and it's all your fault!
When I look at the original source files, it is clear that there is
one definition. I'm not sure what is getting lost in the translation,
but the runtime link-loader 'multiplying definitions' which lead to a
crash is not desired behavior. I would claim it is a bug.

Since what happens in one module crashes another module, I would go
out on a limb and claim this bug might have security implications.

>> Many folks don't expect their objects will be pulled out from
>> under them until the last unload. It seems like a reasonable
>> expectation to me.
> Sure, but you break the rules, you get to keep all the pieces.
I think the problem here is that the rule is f**k'd up. I would argue
that many folks probably know about the rule. But how many know about
it because they got bit in the ass by it versus RTFM'ing the manual in
their spare time?

In essence, the rule creates "Shared (Global) Data Segments" in the
Microsoft world. Those things are quite dangerous (because one process
can cause another to crash) and code cannot pass a security related
quality gates if present [1]. In the Microsoft world, if you want to
take the bull by the horns, you have to go out of your way to get it -
it is not default behavior [2].

(And I know M$ is not a stellar example of security).

Making a bad choice (ie, 'the rule') and documenting it does not make
it all OK. Its not reasonably expected behavior, and it might have
security implications.

Jeffrey Walton

[1] Howard and LeBlac, Writing Secure Code, ISBN 0-7356-1722-8, p. 677-78
[2] How do I share data in my DLL with an application or with other
DLLs?, http://msdn.microsoft.com/en-us/library/h90dkhs0%28VS.80%29.aspx




Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Alexey Skidanov-3
In reply to this post by Marc Glisse-6
Your suggestion  is a workarround. The other one is to turn the static library
to dynamic one.




----- Original Message ----
From: Marc Glisse <[hidden email]>
To: Alexey Skidanov <[hidden email]>; Jeffrey Walton
<[hidden email]>
Cc: [hidden email]
Sent: Thu, October 21, 2010 11:14:15 PM
Subject: Re: Global variable in static library - double free or corruption error

On Thu, 21 Oct 2010, Alexey Skidanov wrote:

> Actually, you claim that if some static library defines some global variable,
> then it should NOT be linked with more then one shared library.

Static libraries should only be linked with the executable. Shared objects are
perfectly fine with undefined symbols. (Of course this is only a general rule,
there can be good reasons to ignore it)



On Thu, 21 Oct 2010, Jeffrey Walton wrote:

> In essence, the rule creates "Shared (Global) Data Segments" in the
> Microsoft world. Those things are quite dangerous (because one process
> can cause another to crash)

Er, I don't know about shared global data segments, but in this thread there is
no mention of crossing the process boundary, only merging 2 variables in a given
process.

-- Marc Glisse




Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Jeffrey Walton-3
In reply to this post by Alexey Skidanov-2
Alexey -

Sorry to go to the top of the thread but this does not apply to any one comment.

Try running the attached program on the SOs in /usr/lib (or any
directory with a shared object). All it does is a load and unload. It
appears there are many victims of C++ shared objects and not knowing
all the rules of RTLD_GLOBAL, ABI and ODR. I have not been able to
make it through the list of libraries yet due to a crash from one
shared object or another.

Some of the libraries cannot even get through their constructors -
/usr/lib/codeblocks/plugins/libAutoVersioning.so comes to mid.

I'm actually quite surprised that a GTK module  -
libwx_gtk2u_core-2.8.so.0 - made an appearance. It seems the module
crashed in its destructor. Need I say more?

And I have not even begun to play dirty: if I fork/exec so that two
processes have a shared object open, I can guarantee a crash of the
second processunder the right circumstances (RTLD_GLOBAL and global
C++ objects) when the first process exits. What if the 'second
process' were a SELinux binary?

And one final note (keep in mind we *MUST* RTLD_GLOBAL to catch C++
exceptions across module boundaries (see the GCC FAQ)):

    ... usually there is no reason to use RTLD GLOBAL. For reasons
    explained later it is always highly advised ..." [1]

Jeff

[1] U. Dreeper, How To Write Shared Libraries,
http://people.redhat.com/drepper/dsohowto.pdf, p.10.

============================

jeffrey@bruno:~/dlopen-dlclose$ uname -a
Linux bruno 2.6.32-25-generic #45-Ubuntu SMP Sat Oct 16 19:52:42 UTC
2010 x86_64 GNU/Linux

============================

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff1f3ee80 in wxWindowBase::PushEventHandler(wxEvtHandler*) ()
   from /usr/lib/libwx_gtk2u_core-2.8.so.0
(gdb) where
#0  0x00007ffff1f3ee80 in wxWindowBase::PushEventHandler(wxEvtHandler*) ()
   from /usr/lib/libwx_gtk2u_core-2.8.so.0
#1  0x00007ffff33eecc7 in PluginManager (this=0x6c1a30) at pluginmanager.cpp:170
#2  0x00007ffff33e1e34 in Mgr<PluginManager>::Get (this=<value
optimized out>) at ./manager.h:183
#3  Manager::GetPluginManager (this=<value optimized out>) at manager.cpp:326
#4  0x00007ffff68190dd in PluginRegistrant (__priority=<value optimized out>,
    __initialize_p=<value optimized out>) at
../../../../src/include/cbplugin.h:593
#5  __static_initialization_and_destruction_0 (__priority=<value
optimized out>,
    __initialize_p=<value optimized out>) at AutoVersioning.cpp:58
#6  0x00007ffff6836c16 in __do_global_ctors_aux ()
   from /usr/lib/codeblocks/plugins/libAutoVersioning.so
#7  0x00007ffff6817f53 in _init () from
/usr/lib/codeblocks/plugins/libAutoVersioning.so
#8  0x00007fff00000000 in ?? ()
#9  0x00007ffff7dead65 in ?? () from /lib64/ld-linux-x86-64.so.2
#10 0x00007ffff7def841 in ?? () from /lib64/ld-linux-x86-64.so.2
#11 0x00007ffff7dea9c6 in ?? () from /lib64/ld-linux-x86-64.so.2
#12 0x00007ffff7deeffa in ?? () from /lib64/ld-linux-x86-64.so.2
#13 0x00007ffff7bd8f66 in ?? () from /lib/libdl.so.2
#14 0x00007ffff7dea9c6 in ?? () from /lib64/ld-linux-x86-64.so.2
#15 0x00007ffff7bd92ac in ?? () from /lib/libdl.so.2
#16 0x00007ffff7bd8ee1 in dlopen () from /lib/libdl.so.2
#17 0x000000000040229f in DoLoadUnload (files=..., errata=...) at
load-unload.cpp:204
#18 0x0000000000401fba in main (argc=1, argv=0x7fffffffe368) at
load-unload.cpp:163
(gdb)

============================

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff0311e8c in wxBaseArrayInt::Add(int, unsigned long) () from
/usr/lib/libwx_baseu-2.8.so.0
(gdb) where
#0  0x00007ffff0311e8c in wxBaseArrayInt::Add(int, unsigned long) ()
   from /usr/lib/libwx_baseu-2.8.so.0
#1  0x00007ffff282f593 in ~wxsRegisterItem (this=0x7ffff2b5a160,
__in_chrg=<value optimized out>)
    at ./../wxsitemfactory.h:108
#2  0x00007ffff6ec3630 in __cxa_finalize () from /lib/libc.so.6
#3  0x00007ffff2737c06 in __do_global_dtors_aux () from
/usr/lib/libwxsmithlib.so.0.0.1
#4  0x0000000000000009 in ?? ()
#5  0x00007fffffffdfb0 in ?? ()
#6  0x00007ffff28ae121 in _fini () from /usr/lib/libwxsmithlib.so.0.0.1
#7  0x00000000006898b0 in ?? ()
#8  0x00007ffff7df0972 in ?? () from /lib64/ld-linux-x86-64.so.2
#9  0x000000000064b7f0 in ?? ()
#10 0x00000000006720b0 in ?? ()
#11 0x00000000006648a0 in ?? ()
#12 0x00000000006787d0 in ?? ()
#13 0x0000000000658a80 in ?? ()
#14 0x00000000006643a0 in ?? ()
#15 0x0000000000641910 in ?? ()
#16 0x000000000066bb90 in ?? ()
#17 0x000000000066c3a0 in ?? ()
#18 0x0000000000663ef0 in ?? ()
#19 0x0000000000672560 in ?? ()
#20 0x000000000066dbf0 in ?? ()
#21 0x000000000066e0a0 in ?? ()
#22 0x000000000066b590 in ?? ()
#23 0x00000000006549e0 in ?? ()
#24 0x0000000000645c70 in ?? ()
#25 0x0000000000679140 in ?? ()
#26 0x0000000000646110 in ?? ()
#27 0x0000000000654e90 in ?? ()
#28 0x0000000000683f60 in ?? ()
#29 0x00000000006500b0 in ?? ()
#30 0x000000000064fc00 in ?? ()
#31 0x0000000000681a40 in ?? ()
#32 0x0000000000681ef0 in ?? ()
#33 0x000000000066cc90 in ?? ()
#34 0x000000000066d140 in ?? ()
#35 0x000000000065a820 in ?? ()
#36 0x0000000000678080 in ?? ()
#37 0x000000000065acc0 in ?? ()
#38 0x0000000000677be0 in ?? ()
#39 0x0000000000647930 in ?? ()
#40 0x000000000065cf40 in ?? ()
#41 0x000000000065d3e0 in ?? ()
#42 0x0000000000647dd0 in ?? ()
#43 0x00000000006795f0 in ?? ()
#44 0x0000000000650ae0 in ?? ()
#45 0x0000000000650f80 in ?? ()
#46 0x0000000000684400 in ?? ()
#47 0x0000000000683280 in ?? ()
#48 0x0000000000683720 in ?? ()
#49 0x0000000000644b90 in ?? ()
#50 0x0000000000645040 in ?? ()
#51 0x000000000067e3a0 in ?? ()
#52 0x000000000067e850 in ?? ()
#53 0x000000000065db90 in ?? ()
#54 0xe0eda5b1f212b194 in ?? ()
#55 0xfffffffffffffffe in ?? ()
#56 0x0101010101010101 in ?? ()
#57 0x0101010101010101 in ?? ()
#58 0x0101010101010101 in ?? ()
#59 0x0101010101010101 in ?? ()
#60 0x0000010101010101 in ?? ()
#61 0x0000000000000000 in ?? ()
(gdb)


On Thu, Oct 21, 2010 at 7:53 AM, Alexey Skidanov
<[hidden email]> wrote:

> Hello,
> We use the gcc 4.1.1 in our project. After some code refactoring
> (creating new shared library) the application crashes at exit with
> following error:
>
> *** glibc detected *** : double free or corruption (fasttop) ***
>
> In order to simulate our application, I created the test one, with two
> shared libraries and one static library. The code is below:
>
> [SNIP]

load-unload.cpp (10K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Andrew Haley
In reply to this post by Alexey Skidanov-3
Please stop top-posting.  It makes it very hard to reply to you.

On 10/21/2010 09:01 PM, Alexey Skidanov wrote:
> Actually, you claim that if some static library defines some global variable,
> then it should NOT be linked with more then one shared library.

In the same process, yes.  That's absolutely true.

> That is, if you
> have the dependencies tree like in my example then you have a problem. Think
> about such static library is third party library where I can't change the code.
>
> Regarding the ODR. You are absolutly right. But what about a MULTIPLE variable
> initialization. Is it correct behaviour according to standard?

I don't know what you mean by a "MULTIPLE variable initialization".

Andrew.


> Alexey
> ________________________________
> From: Andrew Haley <[hidden email]>
> To: [hidden email]
> Cc: Alexey Skidanov <[hidden email]>; [hidden email];
> [hidden email]
> Sent: Thu, October 21, 2010 7:37:25 PM
> Subject: Re: Global variable in static library - double free or corruption error
>
> On 10/21/2010 05:23 PM, Jeffrey Walton wrote:
>>> that there can only ever be one definition of a symbol in a program, and
>>> UNIX has always merged multiple definitions to achieve this
>> Does the rule include that gloabl object destructors are to run on
>> every unload, or the last/final unload or last call to dlclose (when
>> the shared object gets unmapped)?
>
> I suspect that Bad Things would happen.  :-)
>
> As far as I know, they are run, and if you have two definitions
> of some object with a destructor, then you violate the ODR rule,
> and it's all your fault!
>
>> Many folks don't expect their
>> objects will be pulled out from under them until the last unload. It
>> seems like a reasonable expectation to me.
>
> Sure, but you break the rules, you get to keep all the pieces.
>
> Andrew.
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Andrew Haley
In reply to this post by Jeffrey Walton-3
On 10/21/2010 09:21 PM, Jeffrey Walton wrote:

> On Thu, Oct 21, 2010 at 1:37 PM, Andrew Haley <[hidden email]> wrote:
>> On 10/21/2010 05:23 PM, Jeffrey Walton wrote:
>>>> that there can only ever be one definition of a symbol in a program,
>>>> and UNIX has always merged multiple definitions to achieve this
>>> Does the rule include that gloabl object destructors are to run on
>>> every unload, or the last/final unload or last call to dlclose (when
>>> the shared object gets unmapped)?
>>
>> I suspect that Bad Things would happen.  :-)
>>
>> As far as I know, they are run, and if you have two definitions
>> of some object with a destructor, then you violate the ODR rule,
>> and it's all your fault!
>
> When I look at the original source files, it is clear that there is
> one definition. I'm not sure what is getting lost in the translation,
> but the runtime link-loader 'multiplying definitions' which lead to a
> crash is not desired behavior. I would claim it is a bug.

Possibly.  Can you make a small test case?

> Since what happens in one module crashes another module, I would go
> out on a limb and claim this bug might have security implications.
>
>>> Many folks don't expect their objects will be pulled out from
>>> under them until the last unload. It seems like a reasonable
>>> expectation to me.
>> Sure, but you break the rules, you get to keep all the pieces.
> I think the problem here is that the rule is f**k'd up.

Could well be, but it's rather late to change it now.

> I would argue that many folks probably know about the rule. But how
> many know about it because they got bit in the ass by it versus
> RTFM'ing the manual in their spare time?
>
> In essence, the rule creates "Shared (Global) Data Segments" in the
> Microsoft world. Those things are quite dangerous (because one
> process can cause another to crash) and code cannot pass a security
> related quality gates if present [1].

This is not true.  One process cannot cause another to crash: each has
its own memory space.

Andrew.
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Jeffrey Walton-3
In reply to this post by Andrew Haley
On Fri, Oct 22, 2010 at 4:32 AM, Andrew Haley <[hidden email]> wrote:

> Please stop top-posting.  It makes it very hard to reply to you.
>
> On 10/21/2010 09:01 PM, Alexey Skidanov wrote:
>> Actually, you claim that if some static library defines some global variable,
>> then it should NOT be linked with more then one shared library.
>
> In the same process, yes.  That's absolutely true.
>
>> That is, if you
>> have the dependencies tree like in my example then you have a problem. Think
>> about such static library is third party library where I can't change the code.
>>
>> Regarding the ODR. You are absolutly right. But what about a MULTIPLE variable
>> initialization. Is it correct behaviour according to standard?
>
> I don't know what you mean by a "MULTIPLE variable initialization".
I believe he means the constructor running multiple times (the
antithesis of the destructor running multiple times).

I had the same question, but constructors are not causing a crash, so
I have not pursued it :/



 ________________________________

>> From: Andrew Haley <[hidden email]>
>> To: [hidden email]
>> Cc: Alexey Skidanov <[hidden email]>; [hidden email];
>> [hidden email]
>> Sent: Thu, October 21, 2010 7:37:25 PM
>> Subject: Re: Global variable in static library - double free or corruption error
>>
>> On 10/21/2010 05:23 PM, Jeffrey Walton wrote:
>>>> that there can only ever be one definition of a symbol in a program, and
>>>> UNIX has always merged multiple definitions to achieve this
>>> Does the rule include that gloabl object destructors are to run on
>>> every unload, or the last/final unload or last call to dlclose (when
>>> the shared object gets unmapped)?
>>
>> I suspect that Bad Things would happen.  :-)
>>
>> As far as I know, they are run, and if you have two definitions
>> of some object with a destructor, then you violate the ODR rule,
>> and it's all your fault!
>>
>>> Many folks don't expect their
>>> objects will be pulled out from under them until the last unload. It
>>> seems like a reasonable expectation to me.
>>
>> Sure, but you break the rules, you get to keep all the pieces.
>>
>> Andrew.
>>
>>
>>
>>
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Andrew Haley
On 10/22/2010 01:22 PM, Jeffrey Walton wrote:

> On Fri, Oct 22, 2010 at 4:32 AM, Andrew Haley <[hidden email]> wrote:
>> Please stop top-posting.  It makes it very hard to reply to you.
>>
>> On 10/21/2010 09:01 PM, Alexey Skidanov wrote:
>>> Actually, you claim that if some static library defines some global variable,
>>> then it should NOT be linked with more then one shared library.
>>
>> In the same process, yes.  That's absolutely true.
>>
>>> That is, if you
>>> have the dependencies tree like in my example then you have a problem. Think
>>> about such static library is third party library where I can't change the code.
>>>
>>> Regarding the ODR. You are absolutly right. But what about a MULTIPLE variable
>>> initialization. Is it correct behaviour according to standard?
>>
>> I don't know what you mean by a "MULTIPLE variable initialization".
> I believe he means the constructor running multiple times (the
> antithesis of the destructor running multiple times).

I see, thanks.

Well, unless there's a bug you can't get that unless you break the
ODR.

Andrew.
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Jeffrey Walton-3
On Fri, Oct 22, 2010 at 9:02 AM, Andrew Haley <[hidden email]> wrote:

> On 10/22/2010 01:22 PM, Jeffrey Walton wrote:
>> On Fri, Oct 22, 2010 at 4:32 AM, Andrew Haley <[hidden email]> wrote:
>>> Please stop top-posting.  It makes it very hard to reply to you.
>>>
>>> On 10/21/2010 09:01 PM, Alexey Skidanov wrote:
>>>> [SNIP]
>>>> Regarding the ODR. You are absolutly right. But what about a MULTIPLE variable
>>>> initialization. Is it correct behaviour according to standard?
>>>
>>> I don't know what you mean by a "MULTIPLE variable initialization".
>> I believe he means the constructor running multiple times (the
>> antithesis of the destructor running multiple times).
>
> Well, unless there's a bug you can't get that unless you break the
> ODR.
Am I the only guy under the impression that a Microsoft platform can
suffer from Insecure Library Loading, while the Linux platform can
suffer from Insecure Library Unloading due to ABI, ODR, and
RTLD_GLOBAL?

RTFM and and ODR are great - until the attacker causes SELinux (or
other important sub system) to crash due to this 'documented feature'.
Shared data segments are evil and should not be the default :/

Jeff
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Andrew Haley
On 10/22/2010 02:18 PM, Jeffrey Walton wrote:

> On Fri, Oct 22, 2010 at 9:02 AM, Andrew Haley <[hidden email]> wrote:
>> On 10/22/2010 01:22 PM, Jeffrey Walton wrote:
>>> On Fri, Oct 22, 2010 at 4:32 AM, Andrew Haley <[hidden email]> wrote:
>>>> Please stop top-posting.  It makes it very hard to reply to you.
>>>>
>>>> On 10/21/2010 09:01 PM, Alexey Skidanov wrote:
>>>>> [SNIP]
>>>>> Regarding the ODR. You are absolutly right. But what about a MULTIPLE variable
>>>>> initialization. Is it correct behaviour according to standard?
>>>>
>>>> I don't know what you mean by a "MULTIPLE variable initialization".
>>> I believe he means the constructor running multiple times (the
>>> antithesis of the destructor running multiple times).
>>
>> Well, unless there's a bug you can't get that unless you break the
>> ODR.
>
> Am I the only guy under the impression that a Microsoft platform can
> suffer from Insecure Library Loading, while the Linux platform can
> suffer from Insecure Library Unloading due to ABI, ODR, and
> RTLD_GLOBAL?

I have no idea.

> RTFM and and ODR are great - until the attacker causes SELinux (or
> other important sub system) to crash due to this 'documented feature'.
> Shared data segments are evil and should not be the default :/

Probably, but it's too late for that.  And it's nothing to do with gcc.

Andrew.
Reply | Threaded
Open this post in threaded view
|

Re: Global variable in static library - double free or corruption error

Alexey Skidanov-3
In reply to this post by Andrew Haley
Could you explain the last phrase. Do you mean, once I break the ODR the
behaviour is unexpected?  



----- Original Message ----
From: Andrew Haley <[hidden email]>
To: [hidden email]
Cc: Alexey Skidanov <[hidden email]>; Alexey Skidanov
<[hidden email]>; [hidden email]
Sent: Fri, October 22, 2010 3:02:13 PM
Subject: Re: Global variable in static library - double free or corruption error

On 10/22/2010 01:22 PM, Jeffrey Walton wrote:
> On Fri, Oct 22, 2010 at 4:32 AM, Andrew Haley <[hidden email]> wrote:
>> Please stop top-posting.  It makes it very hard to reply to you.
>>
>> On 10/21/2010 09:01 PM, Alexey Skidanov wrote:
>>> Actually, you claim that if some static library defines some global
variable,

>>> then it should NOT be linked with more then one shared library.
>>
>> In the same process, yes.  That's absolutely true.
>>
>>> That is, if you
>>> have the dependencies tree like in my example then you have a problem. Think
>>> about such static library is third party library where I can't change the
>>code.
>>>
>>> Regarding the ODR. You are absolutly right. But what about a MULTIPLE
>variable
>>> initialization. Is it correct behaviour according to standard?
>>
>> I don't know what you mean by a "MULTIPLE variable initialization".
> I believe he means the constructor running multiple times (the
> antithesis of the destructor running multiple times).

I see, thanks.

Well, unless there's a bug you can't get that unless you break the
ODR.

Andrew.




12