Mail Archives: cygwin/2013/04/24/09:48:10
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.
For comparison:
Cygwin Windows Cygwin
Linux x86_64 Linux
Windows x86_64
i686
sizeof(int) 4 4 4
sizeof(long) 4 4 8
sizeof(size_t) 4 8 8
sizeof(void*) 4 8 8
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
long:
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
anymore:
void *ptr;
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.
HTH,
Corinna
(*) http://en.wikipedia.org/wiki/LLP64#64-bit_data_models
--
Corinna Vinschen Please, send mails regarding Cygwin to
Cygwin Maintainer cygwin AT cygwin DOT com
Red Hat
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
- Raw text -