public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* FW: Printing long int in C program under cygwin64
@ 2017-05-24 12:18 Carl Fredrik Forsberg
  2017-05-24 12:54 ` bug in lrint [was: FW: Printing long int in C program under cygwin64] Eric Blake
  0 siblings, 1 reply; 16+ messages in thread
From: Carl Fredrik Forsberg @ 2017-05-24 12:18 UTC (permalink / raw)
  To: cygwin

I am experiencing problems printing long int values under cygwin64 installed on a Windows 10 machine.

Below is a test program followed by its output to demonstrate the problem. The program was initially written to demonstrate the output from lrint(), and developed further to demonstrate to myself how negative integers are tackled by printf type specifiers (e.g. %li, %ld etc).

My understanding is that lrint() should return a long int. However I am unable to get printf to print the correct number. Instead its output is treated as an unsigned integer.
Any  help or hints would be much appreciated.

Regards
Carl Fredrik

#include <stdio.h>      /* printf */
#include <math.h>       /* lrint */

int main ()
{
  char text[64];
  printf ( "int -2 = %i\n", -2 );
  printf ( "int -1 = %i\n", -1 );
  printf ( "int 0 = %i\n", 0 );
  printf ( "int 1 = %i\n", 1 );
  printf ( "long int -2 = %li\n", -2 );
  printf ( "long int -1 = %li\n", -1 );
  printf ( "type cast -1 = %li\n", (long int)-1 );
  printf ( "type cast lrint(-1.0) = %li\n", (long int)lrint(-1.0) );
  printf ( "lrint(-1.0) = %li\n", lrint(-1.0) );
  printf ( "lrint(1.0) = %li\n", lrint(1.0) );
  printf ( "long int 0 = %li\n", 0 );
  printf ( "long int 1 = %li\n", 1 );
  sprintf( text,"long int -1 = %li", -1 );
  printf ( "Via sprintf: %s\n", text);
  printf ( "size of long int: %i\n", sizeof(long int));
  printf ( "size of int: %i\n", sizeof(int));
  return 0;
}


compiled by:
gcc lrint_test.c -o lrint_test.exe

Output:

int -2 = -2
int -1 = -1
int 0 = 0
int 1 = 1
long int -2 = 4294967294
long int -1 = 4294967295
type cast -1 = -1
type cast lrint(-1.0) = 4294967295
lrint(-1.0) = 4294967295
lrint(1.0) = 1
long int 0 = 0
long int 1 = 1
Via sprintf: long int -1 = 4294967295
size of long int: 8
size of int: 4



gcc version:
gcc (GCC) 5.4.0
Copyright (C) 2015 Free Software Foundation, Inc.









The confidentiality or integrity of this message can not be guaranteed following transmission on the Internet. The addressee should be aware of this before using the contents of this message.

--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-24 12:18 FW: Printing long int in C program under cygwin64 Carl Fredrik Forsberg
@ 2017-05-24 12:54 ` Eric Blake
  2017-05-24 16:53   ` Erik Bray
                     ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Eric Blake @ 2017-05-24 12:54 UTC (permalink / raw)
  To: cygwin


[-- Attachment #1.1: Type: text/plain, Size: 3718 bytes --]

On 05/24/2017 07:00 AM, Carl Fredrik Forsberg wrote:
> I am experiencing problems printing long int values under cygwin64 installed on a Windows 10 machine.
> 
> Below is a test program followed by its output to demonstrate the problem. The program was initially written to demonstrate the output from lrint(), and developed further to demonstrate to myself how negative integers are tackled by printf type specifiers (e.g. %li, %ld etc).

Are you compiling with -Wall, or even -Wformat?

> 
> My understanding is that lrint() should return a long int. However I am unable to get printf to print the correct number. Instead its output is treated as an unsigned integer.
> Any  help or hints would be much appreciated.
> 
> Regards
> Carl Fredrik
> 
> #include <stdio.h>      /* printf */
> #include <math.h>       /* lrint */
> 
> int main ()
> {
>   char text[64];
>   printf ( "int -2 = %i\n", -2 );
>   printf ( "int -1 = %i\n", -1 );
>   printf ( "int 0 = %i\n", 0 );
>   printf ( "int 1 = %i\n", 1 );

Okay so far.

>   printf ( "long int -2 = %li\n", -2 );
>   printf ( "long int -1 = %li\n", -1 );

Both buggy.  You are passing an int through varargs, but then telling
printf to grab a long int.  It may or may not work depending on ABI and
stack sizes and what not, but gcc will warn you that it is bogus.

>   printf ( "type cast -1 = %li\n", (long int)-1 );
>   printf ( "type cast lrint(-1.0) = %li\n", (long int)lrint(-1.0) );
>   printf ( "lrint(-1.0) = %li\n", lrint(-1.0) );
>   printf ( "lrint(1.0) = %li\n", lrint(1.0) );

Okay.

>   printf ( "long int 0 = %li\n", 0 );
>   printf ( "long int 1 = %li\n", 1 );
>   sprintf( text,"long int -1 = %li", -1 );

Buggy.

>   printf ( "Via sprintf: %s\n", text);

Okay (well, if you overlook the fact that text was populated in a buggy
manner)

>   printf ( "size of long int: %i\n", sizeof(long int));
>   printf ( "size of int: %i\n", sizeof(int));

Buggy.  size_t should be printed with %zi, not %i (since size_t and int
are not necessarily the same type).

>   return 0;
> }
> 
> 
> compiled by:
> gcc lrint_test.c -o lrint_test.exe

Missing -Wall.  Also, some platforms require the use of -lm to actually
link with lrint() (cygwin does not, though).

> 
> Output:
> 
> int -2 = -2
> int -1 = -1
> int 0 = 0
> int 1 = 1
> long int -2 = 4294967294
> long int -1 = 4294967295

Evidence of your bugs.

> type cast -1 = -1
> type cast lrint(-1.0) = 4294967295

Now that's an interesting one - it may be that cygwin1.dll actually has
buggy behavior in lrint().  In the source code, cygwin/math/lrint.c is
dropping down to assembly; it could very well be that the assembly code
is incorrectly truncating things at 32 bits (where it is just fine for
32-bit Cygwin, but wrong for 64-bit):

long lrint (double x)
{
  long retval = 0L;
#if defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) ||
defined(__i386__)
  __asm__ __volatile__ ("fistpl %0"  : "=m" (retval) : "t" (x) : "st");
#elif defined(__arm__) || defined(_ARM_)
    retval = __lrint_internal(x);
#endif
  return retval;
}

But I'm not an assembly coding expert, so perhaps someone else will spot
the fix faster.

> The confidentiality or integrity of this message can not be guaranteed following transmission on the Internet.

Not the worst disclaimer (it is at least not stating something that is
unenforceable), but we do prefer that messages on this list be sent
without company legalese (even if that means sending from a personal
address instead).

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-24 12:54 ` bug in lrint [was: FW: Printing long int in C program under cygwin64] Eric Blake
@ 2017-05-24 16:53   ` Erik Bray
  2017-05-24 16:57     ` Erik Bray
  2017-05-25  1:31   ` Steven Penny
  2017-06-07  9:10   ` Corinna Vinschen
  2 siblings, 1 reply; 16+ messages in thread
From: Erik Bray @ 2017-05-24 16:53 UTC (permalink / raw)
  To: cygwin

On Wed, May 24, 2017 at 2:33 PM, Eric Blake wrote:
> On 05/24/2017 07:00 AM, Carl Fredrik Forsberg wrote:
>> I am experiencing problems printing long int values under cygwin64 installed on a Windows 10 machine.
>>
>> Below is a test program followed by its output to demonstrate the problem. The program was initially written to demonstrate the output from lrint(), and developed further to demonstrate to myself how negative integers are tackled by printf type specifiers (e.g. %li, %ld etc).
>
> Are you compiling with -Wall, or even -Wformat?
>
>>
>> My understanding is that lrint() should return a long int. However I am unable to get printf to print the correct number. Instead its output is treated as an unsigned integer.
>> Any  help or hints would be much appreciated.
>>
>> Regards
>> Carl Fredrik
>>
>> #include <stdio.h>      /* printf */
>> #include <math.h>       /* lrint */
>>
>> int main ()
>> {
>>   char text[64];
>>   printf ( "int -2 = %i\n", -2 );
>>   printf ( "int -1 = %i\n", -1 );
>>   printf ( "int 0 = %i\n", 0 );
>>   printf ( "int 1 = %i\n", 1 );
>
> Okay so far.
>
>>   printf ( "long int -2 = %li\n", -2 );
>>   printf ( "long int -1 = %li\n", -1 );
>
> Both buggy.  You are passing an int through varargs, but then telling
> printf to grab a long int.  It may or may not work depending on ABI and
> stack sizes and what not, but gcc will warn you that it is bogus.
>
>>   printf ( "type cast -1 = %li\n", (long int)-1 );
>>   printf ( "type cast lrint(-1.0) = %li\n", (long int)lrint(-1.0) );
>>   printf ( "lrint(-1.0) = %li\n", lrint(-1.0) );
>>   printf ( "lrint(1.0) = %li\n", lrint(1.0) );
>
> Okay.
>
>>   printf ( "long int 0 = %li\n", 0 );
>>   printf ( "long int 1 = %li\n", 1 );
>>   sprintf( text,"long int -1 = %li", -1 );
>
> Buggy.
>
>>   printf ( "Via sprintf: %s\n", text);
>
> Okay (well, if you overlook the fact that text was populated in a buggy
> manner)
>
>>   printf ( "size of long int: %i\n", sizeof(long int));
>>   printf ( "size of int: %i\n", sizeof(int));
>
> Buggy.  size_t should be printed with %zi, not %i (since size_t and int
> are not necessarily the same type).
>
>>   return 0;
>> }
>>
>>
>> compiled by:
>> gcc lrint_test.c -o lrint_test.exe
>
> Missing -Wall.  Also, some platforms require the use of -lm to actually
> link with lrint() (cygwin does not, though).
>
>>
>> Output:
>>
>> int -2 = -2
>> int -1 = -1
>> int 0 = 0
>> int 1 = 1
>> long int -2 = 4294967294
>> long int -1 = 4294967295
>
> Evidence of your bugs.
>
>> type cast -1 = -1
>> type cast lrint(-1.0) = 4294967295
>
> Now that's an interesting one - it may be that cygwin1.dll actually has
> buggy behavior in lrint().  In the source code, cygwin/math/lrint.c is
> dropping down to assembly; it could very well be that the assembly code
> is incorrectly truncating things at 32 bits (where it is just fine for
> 32-bit Cygwin, but wrong for 64-bit):
>
> long lrint (double x)
> {
>   long retval = 0L;
> #if defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) ||
> defined(__i386__)
>   __asm__ __volatile__ ("fistpl %0"  : "=m" (retval) : "t" (x) : "st");
> #elif defined(__arm__) || defined(_ARM_)
>     retval = __lrint_internal(x);
> #endif
>   return retval;
> }
>
> But I'm not an assembly coding expert, so perhaps someone else will spot
> the fix faster.

I took a look at this.  The code in Cygwin looks fine, I think.  But
the assembly is wrong:

000000018015cd40 <lrint>:
   18015cd40:   48 83 ec 28             sub    $0x28,%rsp
   18015cd44:   f2 0f 11 44 24 08       movsd  %xmm0,0x8(%rsp)
   18015cd4a:   dd 44 24 08             fldl   0x8(%rsp)
   18015cd4e:   db 5c 24 18             fistpl 0x18(%rsp)
   18015cd52:   48 8b 44 24 18          mov    0x18(%rsp),%rax
   18015cd57:   48 83 c4 28             add    $0x28,%rsp
   18015cd5b:   c3                      retq

That last `mov` should be a `movq`.  The result in $rsp+0x18 is
correct (I checked in gdb), but the `mov` truncates it.  Not sure if
that's a gcc bug or what.

Best,
Erik

--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-24 16:53   ` Erik Bray
@ 2017-05-24 16:57     ` Erik Bray
  2017-05-24 17:40       ` Eric Blake
  0 siblings, 1 reply; 16+ messages in thread
From: Erik Bray @ 2017-05-24 16:57 UTC (permalink / raw)
  To: cygwin

On Wed, May 24, 2017 at 5:55 PM, Erik Bray <erik.m.bray@gmail.com> wrote:
> On Wed, May 24, 2017 at 2:33 PM, Eric Blake wrote:
>> On 05/24/2017 07:00 AM, Carl Fredrik Forsberg wrote:
>>> I am experiencing problems printing long int values under cygwin64 installed on a Windows 10 machine.
>>>
>>> Below is a test program followed by its output to demonstrate the problem. The program was initially written to demonstrate the output from lrint(), and developed further to demonstrate to myself how negative integers are tackled by printf type specifiers (e.g. %li, %ld etc).
>>
>> Are you compiling with -Wall, or even -Wformat?
>>
>>>
>>> My understanding is that lrint() should return a long int. However I am unable to get printf to print the correct number. Instead its output is treated as an unsigned integer.
>>> Any  help or hints would be much appreciated.
>>>
>>> Regards
>>> Carl Fredrik
>>>
>>> #include <stdio.h>      /* printf */
>>> #include <math.h>       /* lrint */
>>>
>>> int main ()
>>> {
>>>   char text[64];
>>>   printf ( "int -2 = %i\n", -2 );
>>>   printf ( "int -1 = %i\n", -1 );
>>>   printf ( "int 0 = %i\n", 0 );
>>>   printf ( "int 1 = %i\n", 1 );
>>
>> Okay so far.
>>
>>>   printf ( "long int -2 = %li\n", -2 );
>>>   printf ( "long int -1 = %li\n", -1 );
>>
>> Both buggy.  You are passing an int through varargs, but then telling
>> printf to grab a long int.  It may or may not work depending on ABI and
>> stack sizes and what not, but gcc will warn you that it is bogus.
>>
>>>   printf ( "type cast -1 = %li\n", (long int)-1 );
>>>   printf ( "type cast lrint(-1.0) = %li\n", (long int)lrint(-1.0) );
>>>   printf ( "lrint(-1.0) = %li\n", lrint(-1.0) );
>>>   printf ( "lrint(1.0) = %li\n", lrint(1.0) );
>>
>> Okay.
>>
>>>   printf ( "long int 0 = %li\n", 0 );
>>>   printf ( "long int 1 = %li\n", 1 );
>>>   sprintf( text,"long int -1 = %li", -1 );
>>
>> Buggy.
>>
>>>   printf ( "Via sprintf: %s\n", text);
>>
>> Okay (well, if you overlook the fact that text was populated in a buggy
>> manner)
>>
>>>   printf ( "size of long int: %i\n", sizeof(long int));
>>>   printf ( "size of int: %i\n", sizeof(int));
>>
>> Buggy.  size_t should be printed with %zi, not %i (since size_t and int
>> are not necessarily the same type).
>>
>>>   return 0;
>>> }
>>>
>>>
>>> compiled by:
>>> gcc lrint_test.c -o lrint_test.exe
>>
>> Missing -Wall.  Also, some platforms require the use of -lm to actually
>> link with lrint() (cygwin does not, though).
>>
>>>
>>> Output:
>>>
>>> int -2 = -2
>>> int -1 = -1
>>> int 0 = 0
>>> int 1 = 1
>>> long int -2 = 4294967294
>>> long int -1 = 4294967295
>>
>> Evidence of your bugs.
>>
>>> type cast -1 = -1
>>> type cast lrint(-1.0) = 4294967295
>>
>> Now that's an interesting one - it may be that cygwin1.dll actually has
>> buggy behavior in lrint().  In the source code, cygwin/math/lrint.c is
>> dropping down to assembly; it could very well be that the assembly code
>> is incorrectly truncating things at 32 bits (where it is just fine for
>> 32-bit Cygwin, but wrong for 64-bit):
>>
>> long lrint (double x)
>> {
>>   long retval = 0L;
>> #if defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) ||
>> defined(__i386__)
>>   __asm__ __volatile__ ("fistpl %0"  : "=m" (retval) : "t" (x) : "st");
>> #elif defined(__arm__) || defined(_ARM_)
>>     retval = __lrint_internal(x);
>> #endif
>>   return retval;
>> }
>>
>> But I'm not an assembly coding expert, so perhaps someone else will spot
>> the fix faster.
>
> I took a look at this.  The code in Cygwin looks fine, I think.  But
> the assembly is wrong:
>
> 000000018015cd40 <lrint>:
>    18015cd40:   48 83 ec 28             sub    $0x28,%rsp
>    18015cd44:   f2 0f 11 44 24 08       movsd  %xmm0,0x8(%rsp)
>    18015cd4a:   dd 44 24 08             fldl   0x8(%rsp)
>    18015cd4e:   db 5c 24 18             fistpl 0x18(%rsp)
>    18015cd52:   48 8b 44 24 18          mov    0x18(%rsp),%rax
>    18015cd57:   48 83 c4 28             add    $0x28,%rsp
>    18015cd5b:   c3                      retq
>
> That last `mov` should be a `movq`.  The result in $rsp+0x18 is
> correct (I checked in gdb), but the `mov` truncates it.  Not sure if
> that's a gcc bug or what.

Actually, I take it back.  gdb/objdump (and presumably binutils in
general) was being deceptive to me about the nature of that mov
instruction.  And in fact the fistpl should be fistpq.  That fixes it.

Erik

--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-24 16:57     ` Erik Bray
@ 2017-05-24 17:40       ` Eric Blake
  2017-05-24 21:19         ` Carl Fredrik Forsberg
  2017-05-26 12:05         ` Erik Bray
  0 siblings, 2 replies; 16+ messages in thread
From: Eric Blake @ 2017-05-24 17:40 UTC (permalink / raw)
  To: cygwin


[-- Attachment #1.1: Type: text/plain, Size: 995 bytes --]

On 05/24/2017 11:53 AM, Erik Bray wrote:

>>> dropping down to assembly; it could very well be that the assembly code
>>> is incorrectly truncating things at 32 bits (where it is just fine for
>>> 32-bit Cygwin, but wrong for 64-bit):
>>>
>>> long lrint (double x)
>>> {
>>>   long retval = 0L;
>>> #if defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) ||
>>> defined(__i386__)
>>>   __asm__ __volatile__ ("fistpl %0"  : "=m" (retval) : "t" (x) : "st");

> Actually, I take it back.  gdb/objdump (and presumably binutils in
> general) was being deceptive to me about the nature of that mov
> instruction.  And in fact the fistpl should be fistpq.  That fixes it.

Is fistpq right on 32-bit, or is this a case where we need different
assembly for 32-bit (fistpl) vs. 64-bit (fistql) to match the size of
long that we are converting to?

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-24 17:40       ` Eric Blake
@ 2017-05-24 21:19         ` Carl Fredrik Forsberg
  2017-05-26 12:05         ` Erik Bray
  1 sibling, 0 replies; 16+ messages in thread
From: Carl Fredrik Forsberg @ 2017-05-24 21:19 UTC (permalink / raw)
  To: Eric Blake, cygwin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2936 bytes --]

Further to my first question, I also tried llrint() as below. It gives the same output as lrint(). This may not be a big surprise as long long int and long int have the same length.

#include <stdio.h>      /* printf */
#include <math.h>       /* lrint, llrint, rint */

int main ()
{
  char text[64];
  printf ( "type cast -1 = %li\n", (long int)-1 );
  printf ( "type cast lrint(-1.0) = %li\n", (long int)lrint(-1.0) );
  printf ( "rint(-1.0) = %f\n", rint(-1.0) );
  printf ( "lrint(-1.0) = %li\n", lrint(-1.0) );
  printf ( "llrint(-1.0) = %lli\n", llrint(-1.0) );
  printf ( "lrint(1.0) = %li\n", lrint(1.0) );
  printf ( "llrint(1.0) = %lli\n", llrint(1.0) );
  sprintf( text,"int -1 = %i", -1 );
  printf ( "Via sprintf: %s\n", text);
  printf ( "size of long long int: %zi\n", sizeof(long long int));
  printf ( "size of long int: %zi\n", sizeof(long int));
  printf ( "size of int: %zi\n", sizeof(int));
  return 0;

compiled by
gcc -Wall lrint_test.c -o lrint_test.exe

output:
type cast -1 = -1
type cast lrint(-1.0) = 4294967295
rint(-1.0) = -1.000000
lrint(-1.0) = 4294967295
llrint(-1.0) = 4294967295
lrint(1.0) = 1
llrint(1.0) = 1
Via sprintf: int -1 = -1
size of long long int: 8
size of long int: 8
size of int: 4
-----Original Message-----
From: cygwin-owner@cygwin.com [mailto:cygwin-owner@cygwin.com] On Behalf Of Eric Blake
Sent: 24 May 2017 18:57
To: cygwin@cygwin.com
Subject: Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]

On 05/24/2017 11:53 AM, Erik Bray wrote:

>>> dropping down to assembly; it could very well be that the assembly
>>> code is incorrectly truncating things at 32 bits (where it is just
>>> fine for 32-bit Cygwin, but wrong for 64-bit):
>>>
>>> long lrint (double x)
>>> {
>>>   long retval = 0L;
>>> #if defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) ||
>>> defined(__i386__)
>>>   __asm__ __volatile__ ("fistpl %0"  : "=m" (retval) : "t" (x) :
>>> "st");

> Actually, I take it back.  gdb/objdump (and presumably binutils in
> general) was being deceptive to me about the nature of that mov
> instruction.  And in fact the fistpl should be fistpq.  That fixes it.

Is fistpq right on 32-bit, or is this a case where we need different assembly for 32-bit (fistpl) vs. 64-bit (fistql) to match the size of long that we are converting to?

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

The confidentiality or integrity of this message can not be guaranteed following transmission on the Internet. The addressee should be aware of this before using the contents of this message.
\x03B‹KCB”\x1c›Ø›\x19[H\x1c™\^[ܝ\x1cΈ\b\b\b\b\b\b\x1a\x1d\x1d\x1c\x0e‹ËØÞYÝÚ[‹˜ÛÛKÜ\x1c›Ø›\x19[\Ëš\x1d^[[\x03B‘TNˆ\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\x1a\x1d\x1d\x1c\x0e‹ËØÞYÝÚ[‹˜ÛÛKÙ˜\KÃB‘^[ØÝ[Y[\x18]\x1a[ÛŽˆ\b\b\b\b\b\b\b\b\x1a\x1d\x1d\x1c\x0e‹ËØÞYÝÚ[‹˜ÛÛKÙ^[ØÜËš\x1d^[[\x03B•[œÝXœØÜšX™H\x1a[™›Îˆ\b\b\b\b\b\x1a\x1d\x1d\x1c\x0e‹ËØÞYÝÚ[‹˜ÛÛKÛ[\vÈÝ[œÝXœØÜšX™K\Ú[\^[\x19CBƒB

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-24 12:54 ` bug in lrint [was: FW: Printing long int in C program under cygwin64] Eric Blake
  2017-05-24 16:53   ` Erik Bray
@ 2017-05-25  1:31   ` Steven Penny
  2017-05-25  7:50     ` Steven Penny
  2017-05-25 19:25     ` Eric Blake
  2017-06-07  9:10   ` Corinna Vinschen
  2 siblings, 2 replies; 16+ messages in thread
From: Steven Penny @ 2017-05-25  1:31 UTC (permalink / raw)
  To: cygwin

On Wed, 24 May 2017 07:33:27, Eric Blake wrote:
> Buggy.  size_t should be printed with %zi, not %i (since size_t and int
> are not necessarily the same type).

Aren’t both wrong? By definition %i is a signed integer, and size_t is unsigned.
So %zu or %llu would be more correct:

http://wikipedia.org/wiki/C_data_types

They all seem to do the job though:

    $ cat alfa.c
    #define __USE_MINGW_ANSI_STDIO 1
    #include <stdio.h>
    int main() {
      size_t bravo = 1;
      printf("%zi %zu %llu\n", bravo, bravo, bravo);
    }

    $ x86_64-w64-mingw32-gcc -o alfa alfa.c

    $ ./alfa
    1 1 1


--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-25  1:31   ` Steven Penny
@ 2017-05-25  7:50     ` Steven Penny
  2017-05-25 17:34       ` Brian Inglis
  2017-05-25 19:25     ` Eric Blake
  1 sibling, 1 reply; 16+ messages in thread
From: Steven Penny @ 2017-05-25  7:50 UTC (permalink / raw)
  To: cygwin

On Wed, 24 May 2017 16:36:03, Steven Penny wrote:
> Aren’t both wrong? By definition %i is a signed integer, and size_t is unsigned.
> So %zu or %llu would be more correct:
> 
> http://wikipedia.org/wiki/C_data_types
> 
> They all seem to do the job though:

Correcting myself. Here is why you cannot use %zi:

    $ cat alfa.c
    #define __USE_MINGW_ANSI_STDIO 1
    #include <stdio.h>
    int main() {
      printf("%zi %zu %llu\n", __SIZE_MAX__, __SIZE_MAX__, __SIZE_MAX__);
    }

    $ x86_64-w64-mingw32-gcc -o alfa alfa.c

    $ ./alfa
    -1 18446744073709551615 18446744073709551615


--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-25  7:50     ` Steven Penny
@ 2017-05-25 17:34       ` Brian Inglis
  0 siblings, 0 replies; 16+ messages in thread
From: Brian Inglis @ 2017-05-25 17:34 UTC (permalink / raw)
  To: cygwin

On 2017-05-24 19:31, Steven Penny wrote:
> On Wed, 24 May 2017 16:36:03, Steven Penny wrote:
>> Aren’t both wrong? By definition %i is a signed integer, and size_t is
>> unsigned.
>> So %zu or %llu would be more correct:
>> http://wikipedia.org/wiki/C_data_types
>> They all seem to do the job though:
> Correcting myself. Here is why you cannot use %zi:
>	$ cat alfa.c
>	#define __USE_MINGW_ANSI_STDIO 1
>	#include <stdio.h>
>	int main() {
>		printf("%zi %zu %llu\n", __SIZE_MAX__, __SIZE_MAX__, __SIZE_MAX__);
>	}
>	$ x86_64-w64-mingw32-gcc -o alfa alfa.c
>	$ ./alfa
>	-1 18446744073709551615 18446744073709551615

I think either 10+ digits or a negative value are adequate indicators
that something may have gone wrong, and -1 is a more compact format for
*_MAX, unless you need to see actual values.

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-25  1:31   ` Steven Penny
  2017-05-25  7:50     ` Steven Penny
@ 2017-05-25 19:25     ` Eric Blake
  2017-05-26  1:53       ` Steven Penny
  1 sibling, 1 reply; 16+ messages in thread
From: Eric Blake @ 2017-05-25 19:25 UTC (permalink / raw)
  To: cygwin


[-- Attachment #1.1: Type: text/plain, Size: 1131 bytes --]

On 05/24/2017 06:36 PM, Steven Penny wrote:
> On Wed, 24 May 2017 07:33:27, Eric Blake wrote:
>> Buggy.  size_t should be printed with %zi, not %i (since size_t and int
>> are not necessarily the same type).
> 
> Aren’t both wrong? By definition %i is a signed integer, and size_t is
> unsigned.
> So %zu

Correct.  Newer gcc's -Wformat-signedness will flag the discrepency.

> or %llu would be more correct:

NO. Do NOT use %llu with size_t, because it is not portable to 32-bit
platforms.  That's WHY %zu exists.

> They all seem to do the job though:

Yes. On all modern platforms, you can freely mix signed and unsigned
integers and get correct (when the number is positive and does not
exceed the signed maximum) or at least sane results (2s complement
counterpart for all other values) regardless of which direction you mess
with incorrect signedness.  However, such behavior is technically not
required by the C standard, which is why gcc added -Wformat-signedness.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-25 19:25     ` Eric Blake
@ 2017-05-26  1:53       ` Steven Penny
  2017-05-26  5:01         ` Steven Penny
  0 siblings, 1 reply; 16+ messages in thread
From: Steven Penny @ 2017-05-26  1:53 UTC (permalink / raw)
  To: cygwin

On Thu, 25 May 2017 13:17:30, Eric Blake wrote:
> Correct.  Newer gcc's -Wformat-signedness will flag the discrepency.

Uh, have you actually tried this? It doesnt do anything:

    $ cat alfa.c
    #define __USE_MINGW_ANSI_STDIO 1
    #include <stdio.h>
    int main() {
      printf("%zi %zu %llu\n", __SIZE_MAX__, __SIZE_MAX__, __SIZE_MAX__);
    }

    $ x86_64-w64-mingw32-gcc -Wformat-signedness -o alfa alfa.c

    $ ./alfa
    -1 18446744073709551615 18446744073709551615


--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-26  1:53       ` Steven Penny
@ 2017-05-26  5:01         ` Steven Penny
  0 siblings, 0 replies; 16+ messages in thread
From: Steven Penny @ 2017-05-26  5:01 UTC (permalink / raw)
  To: cygwin

On Thu, 25 May 2017 18:43:58, Steven Penny wrote:
> Uh, have you actually tried this? It doesnt do anything:
> 
>     $ cat alfa.c
>     #define __USE_MINGW_ANSI_STDIO 1
>     #include <stdio.h>
>     int main() {
>       printf("%zi %zu %llu\n", __SIZE_MAX__, __SIZE_MAX__, __SIZE_MAX__);
>     }
> 
>     $ x86_64-w64-mingw32-gcc -Wformat-signedness -o alfa alfa.c

Correcting myself: you need 2 flags to get this working:

    $ x86_64-w64-mingw32-gcc -Wformat -Wformat-signedness alfa.c
    alfa.c: In function ‘main’:
    alfa.c:11:10: warning: format ‘%zi’ expects argument of type
    ‘signed size_t’, but argument 2 has type ‘long long unsigned int’
    [-Wformat=]
       printf("%zi %zu %llu\n", __SIZE_MAX__, __SIZE_MAX__, __SIZE_MAX__);
              ^


--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-24 17:40       ` Eric Blake
  2017-05-24 21:19         ` Carl Fredrik Forsberg
@ 2017-05-26 12:05         ` Erik Bray
  1 sibling, 0 replies; 16+ messages in thread
From: Erik Bray @ 2017-05-26 12:05 UTC (permalink / raw)
  To: cygwin

On Wed, May 24, 2017 at 6:57 PM, Eric Blake wrote:
> On 05/24/2017 11:53 AM, Erik Bray wrote:
>
>>>> dropping down to assembly; it could very well be that the assembly code
>>>> is incorrectly truncating things at 32 bits (where it is just fine for
>>>> 32-bit Cygwin, but wrong for 64-bit):
>>>>
>>>> long lrint (double x)
>>>> {
>>>>   long retval = 0L;
>>>> #if defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) ||
>>>> defined(__i386__)
>>>>   __asm__ __volatile__ ("fistpl %0"  : "=m" (retval) : "t" (x) : "st");
>
>> Actually, I take it back.  gdb/objdump (and presumably binutils in
>> general) was being deceptive to me about the nature of that mov
>> instruction.  And in fact the fistpl should be fistpq.  That fixes it.
>
> Is fistpq right on 32-bit, or is this a case where we need different
> assembly for 32-bit (fistpl) vs. 64-bit (fistql) to match the size of
> long that we are converting to?

Right.  I didn't read that pre-processer line past the first couple
defines.  Really this should be fistpq on 64-bit and fistpl on 32-bit.
And if llrint has the same bug then it should be fixed there too.

The discussion about printf format specifiers is orthogonal to this.
I can submit a patch for l(l)rint if you'd like.

Erik

--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-05-24 12:54 ` bug in lrint [was: FW: Printing long int in C program under cygwin64] Eric Blake
  2017-05-24 16:53   ` Erik Bray
  2017-05-25  1:31   ` Steven Penny
@ 2017-06-07  9:10   ` Corinna Vinschen
  2 siblings, 0 replies; 16+ messages in thread
From: Corinna Vinschen @ 2017-06-07  9:10 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 1281 bytes --]

On May 24 07:33, Eric Blake wrote:
> On 05/24/2017 07:00 AM, Carl Fredrik Forsberg wrote:
> > type cast lrint(-1.0) = 4294967295
> 
> Now that's an interesting one - it may be that cygwin1.dll actually has
> buggy behavior in lrint().  In the source code, cygwin/math/lrint.c is
> dropping down to assembly; it could very well be that the assembly code
> is incorrectly truncating things at 32 bits (where it is just fine for
> 32-bit Cygwin, but wrong for 64-bit):
> 
> long lrint (double x)
> {
>   long retval = 0L;
> #if defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) ||
> defined(__i386__)
>   __asm__ __volatile__ ("fistpl %0"  : "=m" (retval) : "t" (x) : "st");
> #elif defined(__arm__) || defined(_ARM_)
>     retval = __lrint_internal(x);
> #endif
>   return retval;
> }
> 
> But I'm not an assembly coding expert, so perhaps someone else will spot
> the fix faster.

I just applied a patch to fix this.  Using fistpl is fine and dandy for
Mingw because sizeof(long) == 4, but on 64 bit Cygwin this function
has to use fistpll to account for sizeof(long) == 8.


Thanks,
Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Maintainer                 cygwin AT cygwin DOT com
Red Hat

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
  2017-06-19 11:09 Carl Fredrik Forsberg
@ 2017-06-20 11:22 ` Corinna Vinschen
  0 siblings, 0 replies; 16+ messages in thread
From: Corinna Vinschen @ 2017-06-20 11:22 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 444 bytes --]

On Jun 19 11:09, Carl Fredrik Forsberg wrote:
> Hello again.
> I have performed a few more tests with the program below.

https://cygwin.com/ml/cygwin/2017-06/msg00032.html

Please check again with the latest developer snapshots from
https://cygwin.com/snapshots/


Thanks,
Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Maintainer                 cygwin AT cygwin DOT com
Red Hat

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: bug in lrint [was: FW: Printing long int in C program under cygwin64]
@ 2017-06-19 11:09 Carl Fredrik Forsberg
  2017-06-20 11:22 ` Corinna Vinschen
  0 siblings, 1 reply; 16+ messages in thread
From: Carl Fredrik Forsberg @ 2017-06-19 11:09 UTC (permalink / raw)
  To: cygwin

Hello again.
I have performed a few more tests with the program below.
The lrint() family of functions I tested all appear tohave problems with negative numbers. There seem to be an unsigned vs. signed integer problems.

I could not find  cygwin/math/lrint.c  on my Cygwin installation where patches were applied by Corinna Vinschen as discussed below. This probably  reflects that I am not familiar
with processes that go on "behind the scenes".

A workaround I applied to the program was to  add:

#define lrint(x) (long int)(int)lrint(x)

to the program. This seems to work, but I expect it will fail if all the long int digits are needed.

Program:
#include <stdio.h>      /* printf */
#include <math.h>       /* lrint */
// define statement put in here

int main ()
{

  printf ( "long int -1 = %i\n", -1 );
  printf ( "type cast -1 = %li\n", (long int)-1 );
  printf ( "type cast lrint(-1.0) = %li\n", (long int)(int)lrint(-1.0) );
  printf ( "rint(-1.0) = %f\n", rint(-1.0) );
  printf ( "int of rint(-1.4)-0.5 = %i\n", (int)(rint(-1.4) - 0.5) );
  printf ( "lrint(-1.0) = %li\n", lrint(-1.0) );
  printf ( "lrintf(-1.0) = %li\n", lrintf(-1.0) );
  printf ( "lrintl(-1.0) = %li\n", lrintl(-1.0) );
  printf ( "llrintl(-1.0) = %lli\n", llrintl(-1.0) );

  printf ( "(int)lrint(-1.0) = %i\n", (int)lrint(-1.0) );
  printf ( "Typecasting llrint(-1.0) = %lli\n", (long long)(int)llrint(-1.0) );
  printf ( "lrint(1.0) = %li\n", lrint(1.0) );
  printf ( "llrint(1.0) = %lli\n", llrint(1.0) );
  printf ( "Type cast long long unsigned -1.0 = %llu\n", (unsigned long long)-1 );
  return 0;
}

/*compiled by:
gcc -Wall lrint_test.c -o lrint_test.exe

Result:

long int -1 = -1
type cast -1 = -1
type cast lrint(-1.0) = -1
rint(-1.0) = -1.000000
int of rint(-1.4)-0.5 = -1
lrint(-1.0) = 4294967295
lrintf(-1.0) = 4294967295
lrintl(-1.0) = 4294967295
(int)lrint(-1.0) = -1
Typecasting llrint(-1.0) = -1
lrint(1.0) = 1
llrint(1.0) = 1
Type cast long long unsigned -1.0 = 18446744073709551615

Result with #define statement above.
long int -1 = -1
type cast -1 = -1
type cast lrint(-1.0) = -1
rint(-1.0) = -1.000000
int of rint(-1.4)-0.5 = -1
lrint(-1.0) = -1
lrintf(-1.0) = 4294967295
lrintl(-1.0) = 4294967295
llrintl(-1.0) = 4294967295
(int)lrint(-1.0) = -1
Typecasting llrint(-1.0) = -1
lrint(1.0) = 1
llrint(1.0) = 1
Type cast long long unsigned -1.0 = 18446744073709551615

gcc version:
gcc (GCC) 5.4.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.*/

On May 24 07:33, Eric Blake wrote:
> On 05/24/2017 07:00 AM, Carl Fredrik Forsberg wrote:
> > type cast lrint(-1.0) = 4294967295
>
> Now that's an interesting one - it may be that cygwin1.dll actually has
> buggy behavior in lrint().  In the source code, cygwin/math/lrint.c is
> dropping down to assembly; it could very well be that the assembly code
> is incorrectly truncating things at 32 bits (where it is just fine for
> 32-bit Cygwin, but wrong for 64-bit):
>
> long lrint (double x)
> {
>   long retval = 0L;
> #if defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) ||
> defined(__i386__)
>   __asm__ __volatile__ ("fistpl %0"  : "=m" (retval) : "t" (x) : "st");
> #elif defined(__arm__) || defined(_ARM_)
>     retval = __lrint_internal(x);
> #endif
>   return retval;
> }
>
> But I'm not an assembly coding expert, so perhaps someone else will spot
> the fix faster.

I just applied a patch to fix this.  Using fistpl is fine and dandy for
Mingw because sizeof(long) == 4, but on 64 bit Cygwin this function
has to use fistpll to account for sizeof(long) == 8.


Thanks,
Corinna

--
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Maintainer                 cygwin AT cygwin DOT com
Red Hat
The confidentiality or integrity of this message can not be guaranteed following transmission on the Internet. The addressee should be aware of this before using the contents of this message.

--
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

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2017-06-20 11:22 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-24 12:18 FW: Printing long int in C program under cygwin64 Carl Fredrik Forsberg
2017-05-24 12:54 ` bug in lrint [was: FW: Printing long int in C program under cygwin64] Eric Blake
2017-05-24 16:53   ` Erik Bray
2017-05-24 16:57     ` Erik Bray
2017-05-24 17:40       ` Eric Blake
2017-05-24 21:19         ` Carl Fredrik Forsberg
2017-05-26 12:05         ` Erik Bray
2017-05-25  1:31   ` Steven Penny
2017-05-25  7:50     ` Steven Penny
2017-05-25 17:34       ` Brian Inglis
2017-05-25 19:25     ` Eric Blake
2017-05-26  1:53       ` Steven Penny
2017-05-26  5:01         ` Steven Penny
2017-06-07  9:10   ` Corinna Vinschen
2017-06-19 11:09 Carl Fredrik Forsberg
2017-06-20 11:22 ` Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).