run-time problems due to migration from x86 to x86_64
Hi All,
I recently upgraded OS to its 64-bit version, namely, Ubuntu 9.10 64-bit. After that, I began to experience anomalies (missing output data, infinite loops, etc) when executing my C++ application, which was previously running without any problems on x86. Even though there is no application crash, I suspect that some third-party libraries along with even my own sources have problems due to the incompatibilities in data type lengths between x86 and x86_64. I am in a situation where debugging the sources to find out about the real cause of the problem is difficult... I want to hear about your suggestions. Can I build my application using GCC compiler options with x86 settings on a x86_64 platform ? Even if I am allowed to do that, is it really the right thing to do ? What might be the negative side-effects ? Thanks. |
Quote:
Quote:
Quote:
Quote:
This is an academic point of view. As I never play this kind of game, I'm not aware of "real" and immediate side-effects that could rise... |
Quote:
"unsigned int" is defined in stdint.h, however, it still caused me problem. Hence, I replaced that "unsigned int" variable with size_t, and it resolved my problem. So, in this case, based on what you say, using size_t in sources is not always a good idea ? ... |
Quote:
Quote:
When you're using "size_t", you don't care of the _REAL_ size of the type behind, but you care about the fact that the type is usable for an offset / dimension on the platform you're using. To resume: you must use stdint.h types family when you need an absolute sized type (for exchanging over the network or with hardware) you must use size_t, ptrdiff_t... when you need a platform size dependent type. |
Quote:
Quote:
Quote:
Most of the 32 bit libraries you are likely to need are available in one of the packages designed as 32 bit library packages for 64 bit Debian systems. More obscure libraries you might need are only available as 32 bit packages. I don't know the best way to install a 32 bit Debian package on 64 bit Ubuntu (assuming name conflicts with some 64 bit package you also have), but it can be done. Quote:
In a perfect world, finding and fixing the bad code that makes your application non portable is a more important task. In the real world, you need to budget your time. Quote:
I've found and fixed many bugs where someone stuffed a negative special value (error code etc.) into both an unsigned int and a size_t and then compared. The result is unequal because negative values don't really "fit" in unsigned int. I've even seen a few that stuffed a negative offset into an unsigned int and then added it to a size_t that always had a positive value big enough for the algebraic result to be positive. Try that and you'll see the result is correct on x86 but 2**32 too high on x86_64. "unsigned int" is defined in stdint.h, however, it still caused me problem. Hence, I replaced that "unsigned int" variable with size_t, and it resolved my problem. Quote:
As I described above, it is generally safe to mix uses of unsigned int with size_t for true positive numbers that fit in unsigned int. It is not safe to mix them for error codes (std::string::npos etc.) or other tricks that stuff negative values into unsigned variables. In each place you should not mix them, that means picking one or the other. I don't think size_t is either uniformly better or uniformly worse for all possible places that there is a reason not to mix them. I think most language purists would lean toward using more std::size_t and less unsigned int because of these issues. For example, the std::string functions that might return npos are documented as returning size_t. If you put the function return in an unsigned int and then compare it to npos, it will never be equal to npos. That is just a bug of not storing the return value in the correct type. In the inner loops where you really care about every little spec of performance, unsigned int is the best data type for x86_64, especially for use as an index into anything like an array or vector. Either int or std::size_t tends to generate slightly larger code that likely runs a little slower in key inner loops. I even use uint to get the return value from all those std::string functions (because I'm in the habit of always coding for efficiency). The compiler and options I use will warn about (x==npos) when x was declared uint, and I change that to (x==(uint)npos). I can't say I really recommend copying that style. The efficiency gains are modest. I have some other reasons for coding that way that likely would not apply to you. |
Quote:
Quote:
Code:
/usr/bin/ld: skipping incompatible libclassreg.a when searching for -lclassreg Should I also add -m32 option to linker to link against libclassreg.a ? Quote:
|
Quote:
I always use a gcc command to link, rather than a ld command, because it tends to be easier to get the options right and get it to find all the right libraries. I do always use -m32 in the gcc command for linking 32 bit images on a 64 bit platform. I'm not sure whether it is always necessary or whether gcc and/or the linker can figure that out from the type of the first .o file. Quote:
I assume libclassreg.a exists somewhere on your system as a 64 bit library. Are you sure it isn't finding that one and failing to find the 32 bit one you say you built? Quote:
Quote:
If you found one bug comparing a uint to npos, did you then grep the entire source code for all occurrences of npos and glance at each to see if they were portable? That is the right way to attack these problems. Don't try nor expect to find every portability bug by debugging. When you find a portability bug by debugging do a text search of the source code for that same bug anywhere else it might appear. |
Quote:
Quote:
After doing this, the first shared object which tries to link against libclassreg.a, using linker options -shared -Wl,-soname, generates that "skipping incompatible..." error. I double-checked the path specified for libclassreg.a in that error message, and it is the path for 32-bit libclassreg.a library...(Before checking the path, I cleaned all object files along with static and dynamic libraries (.so files) from the source tree and rebuilt the application) Quote:
|
All times are GMT -5. The time now is 11:56 AM. |