public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: cygwin@cygwin.com
Subject: bug in lrint [was: FW: Printing long int in C program under cygwin64]
Date: Wed, 24 May 2017 12:54:00 -0000	[thread overview]
Message-ID: <d252aaae-b298-6fc8-7e5b-8d8be9f27f21@redhat.com> (raw)
In-Reply-To: <6f28f46906804c6f8f6b4b861e202492@CASMBX02.oslo.ngi.no>


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

  reply	other threads:[~2017-05-24 12:33 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-24 12:18 FW: Printing long int in C program under cygwin64 Carl Fredrik Forsberg
2017-05-24 12:54 ` Eric Blake [this message]
2017-05-24 16:53   ` bug in lrint [was: FW: Printing long int in C program under cygwin64] 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d252aaae-b298-6fc8-7e5b-8d8be9f27f21@redhat.com \
    --to=eblake@redhat.com \
    --cc=cygwin@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).