Typical errors of porting C++ code on the 64-bit platform

Pointer address arithmetic

The first example.

unsigned short a16, b16, c16;
char *pointer;
…
pointer += a16 * b16 * c16;

This example works correctly with pointers if the value of "a16 * b16 * c16" expression does not exceed UINT_MAX (4Gb). Such code could always work correctly on the 32-bit platform for the program has never allocated arrays of large sizes. On the 64-bit architecture the size of the array exceeded UINT_MAX items. Suppose we would like to shift the pointer value on 6.000.000.000 bytes and that’s why variables a16, b16 and c16 have values 3000, 2000 and 1000 correspondingly. While calculating "a16 * b16 * c16" expression all the variables according to C++ rules will be converted to int type and only then their multiplication will occur. During the process of multiplication an overflow will occur. The incorrect expression result will be extended to ptrdiff_t type and the calculation of the pointer will be incorrect.

One should take care to avoid possible overflows in pointer arithmetic. For this purpose it’s better to use memsize types or the explicit type conversion in expressions which carry pointers. Using the explicit type conversion we can rewrite the code in the following way.

short a16, b16, c16;
char *pointer;
…
pointer += static_cast<ptrdiff_t>(a16) *
           static_cast<ptrdiff_t>(b16) *
           static_cast<ptrdiff_t>(c16);

If you think that only those inaccurate programs which work on larger data sizes face troubles we have to disappoint you. Let’s look at an interesting code for working with an array containing only 5 items. The second example works in the 32-bit variant and does not work in the 64-bit one.

int A = -2;
unsigned B = 1;
int array[5] = { 1, 2, 3, 4, 5 };
int *ptr = array + 3;
ptr = ptr + (A + B); //Invalid pointer value on 64-bit platform
printf("%i\n", *ptr); //Access violation on 64-bit platform

Let’s follow how the calculation of "ptr + (a + b)" expression develops:

  • According to C++ rules variable A of int type is converted to unsigned type.
  • Addition of A and B occurs. The result we get is value 0xFFFFFFFF of unsigned type.

Then calculation of "ptr + 0xFFFFFFFFu" takes place but the result of it depends on the pointer size on the particular architecture. If addition will take place in a 32-bit program the given expression will be an equivalent of "ptr – 1" and we’ll successfully print number 3.

In a 64-bit program 0xFFFFFFFFu value will be added fairly to the pointer and the result will be that the pointer will be outbound of the array. And while getting access to the item of this pointer we’ll face troubles.

To avoid the shown situation, as well as in the first case, we advise you to use only memsize types in pointer arithmetic. Here are two variants of the code correction:

ptr = ptr + (ptrdiff_t(A) + ptrdiff_t(B));

 

ptrdiff_t A = -2;
size_t B = 1;
...
ptr = ptr + (A + B);

You may object and offer the following variant of the correction:

int A = -2;
int B = 1;
...
ptr = ptr + (A + B);

Yes, this code will work but it is bad due to some reasons:

  1. It will teach you inaccurate work with pointers. After a while you may forget nuances and made a mistake by making one of the variables of unsigned type.
  2. Using of non-memsize types together with pointers is potentially dangerous. Suppose variable Delta of int type participates in the expression with a pointer. This expression is absolutely correct. But the error may hide in the calculation of the variable Delta itself for 32-bit may be not enough to make the necessary calculations while working with large data arrays. The use of memsize type for variable Delta liquidates the danger automatically.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Better train people and risk they leave – than do nothing and risk they stay.” - Anonymous