[SOLVED] 64 bit data alignment issue on CentOS 5.7 gcc 4.1.2
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
64 bit data alignment issue on CentOS 5.7 gcc 4.1.2
While porting an application to 64 bit environment facing data alignment issues. While creating objects using new, less memory is allocated then expected. This is causing memory corruption. valgrind is also reporting invalid reads/writes.
Problem:
If I check the size of the object "sizeof(*this)" within the constructor then the size is showing as 244 bytes. But if I check the size of the object where it is created "sizeof(*ci)" then it is showing as 236 bytes.
Code:
Creating an object of class ConfigInfo as below:
ConfigInfo *ci = new ConfigInfo();
if (ci->init() != CI_SUCCESS)
{
cout << "Unable to initialize ConfigInfo instance." << endl;
}
class ConfigInfo
{
// variables
LVPairList _parameterList;
LVPairList _pdbaIpList;
// size 56 bytes
SQL *_dbConnection;
Mutex _connMutex;
//size (8+104) = 112 bytes
char *_localHostname;
char *_localIpAddr;
char *_remoteIpAddr;
char *_mySide;
char *_dbPref;
char *_dbUnpref;
char *_hostPref;
char *_hostUnpref;
ConnectionType _myConnectionType; //This is enum
// size 68 bytes
//Total = 56 + 112 + 68 = 236 bytes
};
class LVPairList
{
public:
...
protected:
LVPair *_list;
LVPair *_last;
LVPair *_cursor;
int _count;
// size = 28 bytes
};
GCC version is:
$ g++ -v
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --disable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=x86_64-redhat-linux
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-51)
If I create a separate sample program then the allocated memory using new is same as expected, the padding/alignment is done automatically.
I could not figure out why there is a difference in the alignment in the application and in the separate sample program. I am using the same compiler flags and linking options in both the cases. $ g++ -Wall -g -I. -I../../include -I/usr/include/mysql -c filename.cxx
$ g++ -Wall -L/usr/lib64/mysql -o <EXE> <OBJFILES> -dy -L../../lib -lconf -lmysqlclient_r -lz -lssl -lpthread
Yes, the sizeof(LVPairList) should be 32 bytes. That is the problem I am facing. While allocating memory, its considering the size as given in my post(i.e., 28 bytes for LVPairList). But while initializing the variables its assuming the size to be 32 bytes, which is causing memory corruption.
> I am using "#pragma pack(1)" in some other module to make the structures single byte aligned and at the end changing it back to normal byte alignment.
Yes, the sizeof(LVPairList) should be 32 bytes. That is the problem I am facing. While allocating memory, its considering the size as given in my post(i.e., 28 bytes for LVPairList). But while initializing the variables its assuming the size to be 32 bytes, which is causing memory corruption.
The funny thing about software is that it does not "assume" anything. It performs the actions that it was instructed to do by the programmer. So, depending on how you compiled the code or what is specified in the header file that defines LVPairList (see NevemTeve's previous posts), I find it highly dubious that LVPairList is 28 bytes in size in one area of the code, yet seen as 32 bytes in another, unless of course you are playing "tricks" with the compiler.
Back to your statement that the program (application) is assuming that LVPairList has a size of 32 bytes, how is it making this assumption? Did you hard-code the number 32 as the size, or did you rely on sizeof()?
Without knowing a few details of your application, I took the liberty to throw together the following app based on your comments that were posted previously in your code. ConfigInfo will have a size of 248 bytes, unless you pack LVPairList, which will then make the size 240. If you pack ConfigInfo, and not LVPairList, the size will be 244 bytes. If you pack both structures, then ConfigInfo will have a size of 236 bytes.
Code:
// typedefs used to fill in the "unknown"
//
typedef char Mutex[104]; // based on OP's comment
typedef char SQL;
typedef char LVPair;
enum ConnectionType {};
// Under 64-bit, all pointers, regardless of type, have a size of 8 bytes.
// LVPairList will have a size of 8+8+8+4 = 28 bytes, but when rounded
// to the next word boundary, it will have a size of 32 bytes. If the
// structure is packed, the size will remain at 28 bytes.
//
//#pragma pack(1)
class LVPairList
{
private:
LVPair *_list;
LVPair *_last;
LVPair *_cursor;
int _count;
};
//#pragma pack(0)
// ConfigInfo will have a size of 32+32+8+104+(8*8)+4 = 248 bytes, unless
// LVPairList is packed, in which case it will be 240 bytes. If LVPairList
// is not packed, yet ConfigInfo is, then the size will be 244 bytes. If both
// structures are packed, ConfigInfo will have a size of 236 bytes.
//
//#pragma pack(1)
class ConfigInfo
{
private:
LVPairList _parameterList;
LVPairList _pdbaIpList;
SQL *_dbConnection;
Mutex _connMutex;
char *_localHostname;
char *_localIpAddr;
char *_remoteIpAddr;
char *_mySide;
char *_dbPref;
char *_dbUnpref;
char *_hostPref;
char *_hostUnpref;
ConnectionType _myConnectionType;
};
//#pragma pack(0)
#include <iostream>
int main()
{
std::cout << "LVPairList : " << sizeof(LVPairList) << '\n'
<< "SQL pointer : " << sizeof(SQL*) << '\n'
<< "Mutex : " << sizeof(Mutex) << '\n'
<< "ConnectionType: " << sizeof(ConnectionType) << '\n'
<< "ConfigInfo : " << sizeof(ConfigInfo)
<< std::endl;
}
Last edited by dwhitney67; 01-23-2012 at 04:21 AM.
I am using "#pragma pack(1)" in some other module to make the structures single byte aligned and at the end changing it back to normal byte alignment.
If those are the only occurrences of #pragma pack in your project, then it is likely that those are somehow causing the problem.
Without seeing everything (code and build rules) it would be very hard to diagnose the exact sequence as understood by the compiler. But everything you have said indicates the header of the problem class (or a member of it) is read by the compiler in different parts of your project with different settings for pack
Thanks Guys for your valuable response. One of the #pragma pack statement was set to "#pragma pack(4)" at the end of a structure to change the alignment back to normal. On the 32 bit environment it was working fine. but causing problem on 64 bit environment.
Changing the end pragma statement to “#pragma pack(8)” fixed the problem.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.