ruby-changes:53552
From: shyouhei <ko1@a...>
Date: Fri, 16 Nov 2018 18:04:39 +0900 (JST)
Subject: [ruby-changes:53552] shyouhei:r65768 (trunk): pack.c: cast from double to float can be undefined
shyouhei 2018-11-16 18:04:34 +0900 (Fri, 16 Nov 2018) New Revision: 65768 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=65768 Log: pack.c: cast from double to float can be undefined Generally speaking, a value of double is not always representable when demoted to a float. ISO C defines what to do when such conversion loses precision, but leaves it undefined when the value is completely out of range. (cf: ISO/IEC 9899:1990 section 6.2.1.4). Because ruby do not have half-precision floating-point types this is not a frequent headache but for pack / unpack, there are specifiers that has something to do with C float types. We have to explicitly care these situations. Modified files: trunk/pack.c Index: pack.c =================================================================== --- pack.c (revision 65767) +++ pack.c (revision 65768) @@ -14,6 +14,7 @@ https://github.com/ruby/ruby/blob/trunk/pack.c#L14 #include <sys/types.h> #include <ctype.h> #include <errno.h> +#include <float.h> /* * It is intentional that the condition for natstr is HAVE_TRUE_LONG_LONG @@ -148,6 +149,26 @@ unknown_directive(const char *mode, char https://github.com/ruby/ruby/blob/trunk/pack.c#L149 mode, unknown, fmt); } +static float +VALUE_to_float(VALUE obj) +{ + VALUE v = rb_to_float(obj); + double d = RFLOAT_VALUE(v); + + if (isnan(d)) { + return NAN; + } + else if (d < -FLT_MAX) { + return -INFINITY; + } + else if (d <= FLT_MAX) { + return d; + } + else { + return INFINITY; + } +} + /* * call-seq: * arr.pack( aTemplateString ) -> aBinaryString @@ -663,7 +684,7 @@ pack_pack(int argc, VALUE *argv, VALUE a https://github.com/ruby/ruby/blob/trunk/pack.c#L684 float f; from = NEXTFROM; - f = (float)RFLOAT_VALUE(rb_to_float(from)); + f = VALUE_to_float(from); rb_str_buf_cat(res, (char*)&f, sizeof(float)); } break; @@ -673,7 +694,7 @@ pack_pack(int argc, VALUE *argv, VALUE a https://github.com/ruby/ruby/blob/trunk/pack.c#L694 FLOAT_CONVWITH(tmp); from = NEXTFROM; - tmp.f = (float)RFLOAT_VALUE(rb_to_float(from)); + tmp.f = VALUE_to_float(from); HTOVF(tmp); rb_str_buf_cat(res, tmp.buf, sizeof(float)); } @@ -704,7 +725,7 @@ pack_pack(int argc, VALUE *argv, VALUE a https://github.com/ruby/ruby/blob/trunk/pack.c#L725 while (len-- > 0) { FLOAT_CONVWITH(tmp); from = NEXTFROM; - tmp.f = (float)RFLOAT_VALUE(rb_to_float(from)); + tmp.f = VALUE_to_float(from); HTONF(tmp); rb_str_buf_cat(res, tmp.buf, sizeof(float)); } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/