Wednesday, April 22, 2009

GCC 4.01 MacOSX & Weak Symbols

During the QA process for Firebird V2.1.2 we found that there was a problem with creating a database remotely. In effect the inet server would crash.

On further analysis we found that we have a problem where the function free()(standard C dynamic memory deallocator) was being invoked with the incorrect parameter, an address which had not been allocated using malloc().

After setting up the code to make the inet server call abort we got the following stack trace

(fragment)

#0 0x90005efc in free ()
#1 0x010440b8 in Firebird::AbstractString::~AbstractString (this=0xbfffcb04)
at ../src/include/../common/classes/fb_string.h:375
#2 0x010440f8 Firebird::StringBase::~StringBase
(this=0xbfffcb04) at ../src/include/../common/classes/fb_string.h:391
#3 0x0101593c in LD_setup_attributes (textTypeName=0xbfffcd60 "ES_ES",
charSetName=0xbfffccdc "ISO8859_1",
configInfo=0x6a1204 "filename=$(this)/fbintl;icu_versions=default",
srcLen=39, src=0x69a898 "DISABLE-COMPRESSIONS=1;SPECIALS-FIRST=1",
dstLen=512, dst=0xbfffcdb8 "DISABLE-COMPRESSIONS=1;SPECIALS-FIRST=1,")
at ../src/intl/ld.cpp:457
#4 0x3011b1b4 in Jrd::IntlManager::setupCollationAttributes
(collationName=@0xbfffd0e4, charSetName=@0xbfffd0b8,
specificAttributes=@0xbfffd14c, newSpecificAttributes=@0xbfffd178)
at ../src/jrd/IntlManager.cpp:317

From this back trace you can see that free() is called from the operator delete[], where we would have expected MemoryPool::deallocate() to be used. For some
reason the default operator delete[] is used.

Strange, how did this code arrive at address 0x010440b8?

After an analysis of nm output for fbintl and the linker's map of symbols Alex found that at this address is in fact located the redefined operator delete[], which was compiled in via ld.cpp. However in the assembly version of the file (ld.cpp), it was correctly redefined (i.e. it was calling MemoryPool::deallocate()) operator delete[].

Houston it looks as if we have a buggy toolchain.

But we also need to take into account that AbstractString dtor() and operator delete[] are also WEAK symbols. Weak meaning that such symbols may be present in many object files, and the linker at link-time will take it from the relevant one. But in this case it looks as if it was taken from another file...

But after we compiled into assembler all of the files that are used in the fbintl
library we found that they all contained the correctly redefined operator
delete[]. As such there is no use of operator delete[], calling std free() function in our code, but anyway we get such use in the resulting binary.

In effect it looks like weak symbols are broken on MacOSX GCC 4.01 (Apple build 5747). And the only way to fix a problem is to avoid them.

We are currently compiling Firebird on PPC 10.4 (Tiger) using a new switch -fno-weak

fno-weak:
"Do not use weak symbol support, even if it is provided by the linker. By default, G++ will use weak symbols if they are available. This option exists only for testing, and should not be used by end-users; it will result in inferior code and has no benefits."

Thursday, April 16, 2009

MallocLogFile, MacOSX & LaunchDaemons

I have been debugging the fb_inet_server trying to find a problem in Firebird 2.1.2 Classic for PowerPC. That takes a little bit of setting up, but I will try and explain that in another blog post. Part of one of the things that I wanted to check was what malloc was doing. However by default any "error" messages get sent to standard out, however you can set the environment variable MallocLogFile to capture messages to a specified file. But setting that in my normal environment is going to work because the fb_inet_server is actually launched by the LaunchDaemon and is then also forked. So we need to set the environment variable in the LaunchDaemon script directly.

The solution:

You need to edit the xml script that "launches" the fb_inet_server. This file can be found in /Library/LaunchDaemons and is called org.firebird.gds.plist

First of all unload the current launch definition

launchctl unload /Library/LaunchDaemons/org.firebird.gds.plist

Then edit the file as follows
After

<string>org.firebird.gds</string>

Add

<Key>EnvironmentVariables</Key>
<dict>
<Key>MallocLogFile</Key>
<String>/Library/Frameworks/Firebird.framework/Malloc.log</String>
</dict>

Save and

launchctl load /Library/LaunchDaemons/org.firebird.gds.plist