This is the mail archive of the
mailing list for the Cygwin project.
Re: Porting to 64 bit Cygwin (was Re: Difference in 32/64-bit curl.)
- From: Erwin Waterlander <waterlan at xs4all dot nl>
- To: cygwin at cygwin dot com
- Date: Wed, 24 Apr 2013 20:25:40 +0200
- Subject: Re: Porting to 64 bit Cygwin (was Re: Difference in 32/64-bit curl.)
- References: <51766C22 dot 10702 at bahnhof dot se> <51770372 dot 4070408 at t-online dot de> <20130424125930 dot GQ26397 at calimero dot vinschen dot de> <20130424134749 dot GR26397 at calimero dot vinschen dot de>
Op 24-4-2013 15:47, Corinna Vinschen schreef:
On Apr 24 14:59, Corinna Vinschen wrote:
On Apr 23 23:56, Christian Franke wrote:
Possibly a __builtin_va_list related gcc bug.
This is rather unlikely. That code is shared between Cygwin and
Mingw, and chances are that the bug would have been found already.
What about a type issue? int vs. long?
For clearness I decided to add a quick lecture. Hope that's ok.
The Cygwin x86_64 toolchain is using the LP64(*) data model. That means,
in contrast to Windows, which uses an LLP64(*) data model, sizeof(long)
!= sizeof(int), just as on Linux.
Cygwin Windows Cygwin
Linux x86_64 Linux
sizeof(int) 4 4 4
sizeof(long) 4 4 8
sizeof(size_t) 4 8 8
sizeof(void*) 4 8 8
And these. Interesting for people handling Unicode (wide) text:
sizeof(wchar_t) 2 2 2
sizeof(wint_t) 2 2 4
This difference can result in interesting problems, especially when
using Win32 functions, especially when using pointers to Windows
datatypes like LONG, ULONG, DWORD. Given that Windows is LLP64, all of
these are 4 byte in size, while `long' on Cygwin is 8 bytes.
Take the example ReadFile:
ReadFile (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
In the 32 bit Cygwin and Mingw environments, as well as in the 64 bit
Mingw environment, it is no problem to substitute DWORD with unsigned
unsigned long number_of_bytes_read;
ReadFile (fhdl, buf, buflen, &number_of_bytes_read, NULL);
However, in 64 bit Cygwin, using LP64, number_of_bytes_read is 8 bytes
in size. But ReadFile expects a pointer to a 4 byte type. So the
function will only change the lower 4 bytes of number_of_bytes_read,
while the content of the upper 4 bytes is undefined.
Here are a few donts which may help porting applications from the
ILP32 to the new LP64 data model. Note that this is not a Cygwin-only
problem. Many Linux applications suffered the same somewhat liberal
handling of datatypes when x86_64 was new.
- DON'T mix up int and long in printf/scanf. This:
int i; long l;
printf ("%d %ld\n", l, i);
may not print what you think it should.
- DON'T mix int and long pointers.
int *ip = (int *) &my_long; /* Uh oh! */
- DON'T mix int and pointers at all! THis will NOT work as expected
printf ("Pointer value is %x\n", (int) ptr);
- DON'T use functions returning pointers without declaration. For instance
printf ("Error message is: %s\n", strerror (errno));
This code will CRASH, unless you included string.h. The implicit
rule in C is that an undeclared function is of type int. But int
is 4 byte and pointers are 8 byte, so the string pointer given to
printf is missing the upper 4 bytes. Hilarity ensues ;)
- DON'T use C base types together with Win32 functions. Keep in mind
that DWORD, LONG, ULONG are *not* the same as long and unsigned long.
Try to use only Win32 datatypes in conjunction with Win32 API function
calls to avoid type problems.
- DON'T mix Windows dataypes with POSIX type-specific MIN/MAX values.
unsigned long l_max = ULONG_MAX; /* That's right. */
ULONG w32_biggest = ULONG_MAX; /* Hey, wait! What? */
ULONG w32_biggest = UINT_MAX; /* Ok. */
Always keep in mind that ULONG (or DWORD) != unsigned long but
rather == unsigned int now.
Problem reports: http://cygwin.com/problems.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple