php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73954 NAN check fails on Alpine Linux with musl
Submitted: 2017-01-17 08:53 UTC Modified: 2017-02-05 13:55 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:2 (100.0%)
From: zaq178miami at gmail dot com Assigned: ajf (profile)
Status: Closed Package: *General Issues
PHP Version: Irrelevant OS: Alpine Linux
Private report: No CVE-ID: None
 [2017-01-17 08:53 UTC] zaq178miami at gmail dot com
Description:
------------
It seems to be that is_nan check fails or sth like that as when passing NAN to as an int parameter it silently casted to int(0). While int(0) is valid result for explicit (int)NAN cast, according to Andrea (https://wiki.php.net/rfc/zpp_fail_on_overflow).

As already discussed on SO (http://chat.stackoverflow.com/transcript/message/35136128#35136128) it might be just a musl bug, but maybe we should check what NAN do we have and maybe alter config scripts and/or php_get_nan() accordingly? 

Here is runnable snippet: https://3v4l.org/m7hpq



Test script:
---------------
<?php
function test(int $test) {
    var_dump($test);
}

test(NAN);

Expected result:
----------------
Fatal error: Uncaught TypeError: Argument 1 passed to test() must be of the type integer, float given, called in /in/m7hpq on line 6 and defined in /in/m7hpq:2 Stack trace: #0 /in/m7hpq(6): test(NAN) #1 {main} thrown in /in/m7hpq on line 2

Actual result:
--------------
int(0)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-01-17 17:49 UTC] cmb@php.net
-Status: Open +Status: Feedback -Assigned To: +Assigned To: cmb
 [2017-01-17 17:49 UTC] cmb@php.net
This has nothing to do with ZPP, because it's a userland function.
What do you get with the following script with musl:

  <?php
  
  var_dump(chr(NAN));
 [2017-01-17 20:05 UTC] alex dot masterow at gmail dot com
I also know about this problem.

> What do you get with the following script with musl:
> var_dump(chr(NAN));

string(1) ""

Unicode: U+0000
HTML: &#0;
 [2017-01-17 20:21 UTC] ajf@php.net
It doesn't use ZPP-the-function, yes, but typehints for userland and internal functions inherit their handling of NaN for integer parameters from ZPP (and actually share the code for this with ZPP internally), which is why I linked the OP to that RFC.
 [2017-01-17 20:26 UTC] ajf@php.net
Specifically, ZPP and type declarations call to zend_parse_arg_long_weak(). The key line here would be https://github.com/php/php-src/blob/db894fa6aa6e98811bcc39b1331fc201e33c10ef/Zend/zend_API.c#L317:

		if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) {
			return 0;
		}

Possibly zend_isnan() is broken here.
 [2017-01-17 20:31 UTC] ajf@php.net
zend_isnan is defined in https://github.com/php/php-src/blob/db894fa6aa6e98811bcc39b1331fc201e33c10ef/Zend/configure.in#L72-L80:

#ifndef zend_isnan
#ifdef HAVE_ISNAN
#define zend_isnan(a) isnan(a)
#elif defined(HAVE_FPCLASS)
#define zend_isnan(a) ((fpclass(a) == FP_SNAN) || (fpclass(a) == FP_QNAN))
#else
#define zend_isnan(a) 0
#endif
#endif

That last one doesn't look like a safe default. I wonder if it's falling back to that. ((a)!=(a)) would be a safer default.

OP, could you see if is_nan(NAN) returns TRUE?

On the same note, are you certain NAN is actually a NaN? Could you try var_dump(NAN);? I am wondering if I possibly broke that constant a little while ago.
 [2017-01-17 20:58 UTC] alex dot masterow at gmail dot com
> OP, could you see if is_nan(NAN) returns TRUE?
It returns FALSE.

> are you certain NAN is actually a NaN? Could you try var_dump(NAN);?
float(NAN)

The same output as documentation is_nan().
 [2017-01-17 23:01 UTC] cmb@php.net
-Status: Feedback +Status: Open -Assigned To: cmb +Assigned To: ajf
 [2017-01-17 23:01 UTC] cmb@php.net
It seems to me that the NaN handling is broken (not only with
musl). Andrea, could you please take a closer look at this?
 [2017-01-17 23:06 UTC] ajf@php.net
I can look into it, but it works for me. So, what particular OS, compiler and version are you dealing with?
 [2017-01-18 00:45 UTC] alex dot masterow at gmail dot com
> So, what particular OS, compiler and version are you dealing with?

Alpine Linux (alpine:3.5/edge on Docker hub)

$ uname -a
Linux version 3.16.0-4-amd64

musl 1.1.16-r2
gcc 6.3.0-r1
php 7.0.14/15
 [2017-01-18 23:00 UTC] cmb@php.net
> I can look into it, but it works for me.

See <https://3v4l.org/PHBQK>. Why does Z_PARAM_LONG accept NAN,
but a userland `int` type declaration does not?

The different behavior with musl[1] would have been to be resolved
also, but I have some doubts that the test script in the OP should
really have the reported expected result, especially when
considering

> […], but typehints for userland and internal functions inherit
> their handling of NaN for integer parameters from ZPP (and
> actually share the code for this with ZPP internally), […]

[1] <https://www.musl-libc.org/>
 [2017-01-19 00:22 UTC] ajf@php.net
> See <https://3v4l.org/PHBQK>. Why does Z_PARAM_LONG accept NAN,
> but a userland `int` type declaration does not?

chr() uses ZEND_PARSE_PARAMS_QUIET to suppress errors in parameter parsing, so it does not display the normal behaviour. It ignoring NAN is expected. Additionally, chr() usually doesn't actually get called, because it is a special-cased function which zend_compile.c replaces with an opcode.
 [2017-01-19 10:16 UTC] cmb@php.net
Thanks for the explanation, Andrea. So this is solely a musl
issue.
 [2017-02-04 23:47 UTC] ajf@php.net
Okay, I got an Alpine install up and running in a VM and I can reproduce this for php-src master:

localhost:~/php-src# uname -a; sapi/cli/php -v; sapi/cli/php -r 'function foo(in
t $x) {} var_dump(foo(NAN));'
Linux localhost 4.4.45-0-virtgrsec #1-Alpine SMP Thu Jan 26 14:32:43 GMT 2017 x86_64 Linux
PHP 7.2.0-dev (cli) (built: Feb  4 2017 23:35:47) ( NTS DEBUG )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.2.0-dev, Copyright (c) 1998-2017 Zend Technologies
NULL

Whereas on macOS:

Andreas-MacBook-Air:php-src ajf$ uname -a; sapi/cli/php -v; sapi/cli/php -r 'function foo(int $x) {} var_dump(foo(NAN));'
Darwin Andreas-MacBook-Air.local 16.4.0 Darwin Kernel Version 16.4.0: Thu Dec 22 22:53:21 PST 2016; root:xnu-3789.41.3~3/RELEASE_X86_64 x86_64
PHP 7.2.0-dev (cli) (built: Jan 31 2017 21:23:57) ( NTS DEBUG )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.2.0-dev, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.2.0-dev, Copyright (c) 1999-2017, by Zend Technologies

Fatal error: Uncaught TypeError: Argument 1 passed to foo() must be of the type integer, float given, called in Command line code on line 1 and defined in Command line code:1
Stack trace:
#0 Command line code(1): foo(NAN)
#1 {main}
  thrown in Command line code on line 1
 [2017-02-04 23:56 UTC] nikic@php.net
Note that there is a PR up to fix this issue: https://github.com/php/php-src/pull/2356
 [2017-02-05 00:10 UTC] ajf@php.net
I'm not sure if that PR actually fixes the issue, but I'll test it.

Side-note: we currently define zend_isnan() twice, in both Zend.m4 and configure.m4. I don't know why, that might be my fault.
 [2017-02-05 00:14 UTC] ajf@php.net
(Sure enough, it's mine. I moved it from ext/standard, but it was already in a different m4 file in Zend. Oops.)
 [2017-02-05 00:17 UTC] ajf@php.net
…no, wait, I just can't read source code properly without syntax highlighting. Ignore me, sorry.
 [2017-02-05 01:34 UTC] ajf@php.net
Automatic comment on behalf of ajf@ajf.me
Revision: http://git.php.net/?p=php-src.git;a=commit;h=21d7878690c18124fa788f2aa22e505a4fa6ceeb
Log: Fix bug #73954
 [2017-02-05 01:34 UTC] ajf@php.net
-Status: Assigned +Status: Closed
 [2017-02-05 01:34 UTC] ajf@php.net
Automatic comment on behalf of ajf@ajf.me
Revision: http://git.php.net/?p=php-src.git;a=commit;h=21d7878690c18124fa788f2aa22e505a4fa6ceeb
Log: Fix bug #73954
 [2017-02-05 01:35 UTC] ajf@php.net
Automatic comment on behalf of ajf@ajf.me
Revision: http://git.php.net/?p=php-src.git;a=commit;h=21d7878690c18124fa788f2aa22e505a4fa6ceeb
Log: Fix bug #73954
 [2017-02-05 13:55 UTC] zaq178miami at gmail dot com
Thank you for taking care!
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC