Abstract

While porting 32-bit software to 64-bit systems there may appear some errors in the code of applications which were written in C++ language. The cause for these hides in the alteration of the base data types (to be more exact, in the relations between them) with the new hardware platform.

This article contains various examples of 64-bit errors. However, we have learnt much more examples and types of errors since we started writing the article and they were not included into it. Please see the article "A Collection of Examples of 64-bit Errors in Real Programs" that covers defects in 64-bit programs we know of most thoroughly. We also recommend you to study the course "Lessons on development of 64-bit C/C++ applications" where we describe the methodology of creating correct 64-bit code and searching for all types of defects using the Viva64 code analyzer.

Introduction

While porting 32-bit software to 64-bit systems there may appear some errors in the code of applications which were written in C++ language. The cause for these hides in the alteration of the base data types (to be more exact, in the relations between them) with the new hardware platform. "But isn't C++ a high-level language!" you may ask, and you will be right. But still all the high-level abstractions are realized through the low-level data types.

Help documentation for developers is sure to contain the description of such errors. However, even such authoritative sources as, for example MSDN, often give only platitudes, for instance:

int and long remained 32-bit ones with 64-bit versions of Widows;

size_t, time_t, and ptrdiff_t became 64-bit ones with 64-bit versions of Windows.

But what does it mean for a developer and what problems may it potentially cause - all this is not reported in the help.

Meanwhile, there are very few articles which contain certain examples of application code errors in 64-bit Windows versions. This article is to fill the vacuum.

First of all some terminology. Memsize type is any data type which changes its size when the digit capacity of architecture is changed from 32 bits to 64 bits. The examples are size_t, ptrdiff_t, DWORD_PTR, LONG_PTR and others.

Take a note that only short examples of errors are given in the article. The explanation of their causes are given in the article "20 issues of porting C++ of porting C++ code on the 64-bit platform"http://www.viva64.com/en/a/0004/ .

An error source code example

Let us not harass the developers who wish to get down to studying the error examples, so let's show the whole source code of such a program. After the source code each error will be considered separately.

To demonstrate the errors it is necessary to compile and run this code in the 64-bit mode.

You can find the source code of an application which contains this code in a Viva64 distributive named PortSample. For this purpose download and install Viva64 and then install PortSamle from program folder Viva64.

Now, when we see the whole code, let's consider the functions which contain errors. When we say that a function contains an error we mean the following: the given code is able to compile and function in the 32-bit regime, but after compiling for the64-bit regime its functioning becomes incorrect up to fall.

All the varibles in the multiplation are of unsigned type, which in both 32-bit and 64-bit regimes pssesses the sie of 32 bits. But the result of multiplation is written with a variable of size_t type which in the 32-bit mode possesses the size coinciding with the size of unsigned type and they don't coincide in the 64-bit mode. But the compiler fulfills the extention of the result type up to unsigned one.It seems that there is no problem at all. But the problem exists! If the result of multplication exceeds 4 gigabytes the overflow will occur and the result will be incorrect.

It's strange but operations of comparing two variables may be also the source of trouble. In the following line

for (i = 0; i != n; ++i)

the problem is that the variable i of unsigned type is compared to the variable n of size_t type, and after that this variable extends. But as unsigned never exceeds 4 gigabytes , than i will never be larger than this value. What do we have as a result? We have an infinite loop! as the conditions of i != n will always be fulfilled.

the developer hoped to get a 5-gigabyte buffer with a 64-bit system. But an error will occur here. You ask why? Just because the malloc() function possesses an argument of memsize type and 5 is quite an appropriate value. But when (5 * unit) is multiplied an overflow will occur because the unit variable is of unsigned type. The result will for sure be not 5 gigabytes.

Implicit conversion of a function argument of memsize type to the 32-bit type

The value result is of int type which will be implicitly expanded to ptrdiff_t. But the function UnsafeCalcIndex() will never be able to return the index of the element following 2 gigabytes. It would be more correct to say that the error is the wrongly chosen type of the variable result. In this case this variable must be of UnsafeCalcIndex() type.

C++ being a low-level language allows working with memory at the pointer level. Explicit type conversion using pointers is anyway dangerous, but conversion of memsize types , as shown in the example, is twice dangerous.

One of the funniest errors of C++ applications which can appear with 64-bit systems is related to virtual functions. Pay your attention to the parameters of virtual functions in the example above. With a 32-bit system DWORD_PTR and DWORD coincide and there appears an overridden virtual function, and with a 64-bit platform there are two different functions! As a result the call of WinHelp() function from the example will cause the appearance of "Cannot activate WinHelp" message.

Pro conclusion

Thus, we have listed all the main code errors which appear when a code is ported to 64-bit systems. You might think many of them are sophisticated. For example, who, for God's sake, may need a 5 gigabyte buffer at Windows system? Maybe this problem is not very acute in 2007, though many resource-intensive applications are already able to use such amount of memory. We'll see if this article will be actual in a couple of years. Maybe just you will debug an error which appears when several gigabytes of memory are allocated.

Some information about the author

Evgeniy Ryzhkov is one of the developers of the static code analyzer Viva64 which is meant for simplifying the migration of applications to 64-bit platforms. He studies the migration of 32-bit program systems to 64-bit platforms.

Use PVS-Studio to search for bugs in C, C++, C# and Java code

We offer you to check your project code with PVS-Studio. Just one bug found in the project will show you the benefits of the static code analysis methodology better than a dozen of the articles.