Skip to content

Commit eb994af

Browse files
committed
py/obj: Fix nan handling in REPR_C and REPR_D.
CPython math.nan is positive with regards to copysign. The signaling bit (aka sign flag) was incorrectly set. In addition, REPR_C and REPR_D should only use the _true_ nan to prevent system crash in case of hand-crafted floats. For instance, with REPR_C, any nan-like float following the pattern `01111111 1xxxxxxx xxxxxxxx xxxxx1xx` would be switched to an immediate object or a qstr string. When the qstr index is too large, this would cause a crash. This commit fixes the issue, and adds the relevant test cases. Signed-off-by: Yoctopuce dev <dev@yoctopuce.com>
1 parent 09541b7 commit eb994af

File tree

5 files changed

+37
-4
lines changed

5 files changed

+37
-4
lines changed

ports/windows/mpconfigport.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,11 @@ typedef long mp_off_t;
266266
#endif
267267
#endif
268268

269+
// VC++ 2017 fixes
270+
#if (_MSC_VER < 1920)
271+
#define MICROPY_PY_MATH_COPYSIGN_FIX_NAN (1)
272+
#endif
273+
269274
// CL specific definitions
270275

271276
#ifndef __cplusplus

py/modmath.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ MATH_FUN_2(atan2, atan2)
161161
MATH_FUN_1_TO_INT(ceil, ceil)
162162
// copysign(x, y)
163163
static mp_float_t MICROPY_FLOAT_C_FUN(copysign_func)(mp_float_t x, mp_float_t y) {
164+
#if MICROPY_PY_MATH_COPYSIGN_FIX_NAN
165+
if (isnan(y)) {
166+
y = 0.0;
167+
}
168+
#endif
164169
return MICROPY_FLOAT_C_FUN(copysign)(x, y);
165170
}
166171
MATH_FUN_2(copysign, copysign_func)

py/obj.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,15 @@ static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
184184
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))
185185

186186
#if MICROPY_PY_BUILTINS_FLOAT
187-
#define MP_OBJ_NEW_CONST_FLOAT(f) MP_ROM_PTR((mp_obj_t)((((((uint64_t)f) & ~3) | 2) + 0x80800000) & 0xffffffff))
187+
#include <math.h>
188+
// note: MP_OBJ_NEW_CONST_FLOAT should be a MP_ROM_PTR but that macro isn't available yet
189+
#define MP_OBJ_NEW_CONST_FLOAT(f) ((mp_obj_t)((((((uint64_t)f) & ~3) | 2) + 0x80800000) & 0xffffffff))
188190
#define mp_const_float_e MP_OBJ_NEW_CONST_FLOAT(0x402df854)
189191
#define mp_const_float_pi MP_OBJ_NEW_CONST_FLOAT(0x40490fdb)
190192
#if MICROPY_PY_MATH_CONSTANTS
191193
#define mp_const_float_tau MP_OBJ_NEW_CONST_FLOAT(0x40c90fdb)
192194
#define mp_const_float_inf MP_OBJ_NEW_CONST_FLOAT(0x7f800000)
193-
#define mp_const_float_nan MP_OBJ_NEW_CONST_FLOAT(0xffc00000)
195+
#define mp_const_float_nan MP_OBJ_NEW_CONST_FLOAT(0x7fc00000)
194196
#endif
195197

196198
static inline bool mp_obj_is_float(mp_const_obj_t o) {
@@ -207,6 +209,10 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
207209
return num.f;
208210
}
209211
static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
212+
if (isnan(f)) {
213+
// prevent creation of bad nanboxed pointers via array.array or struct
214+
return MP_OBJ_NEW_FLOAT(mp_nan_obj_bits);
215+
}
210216
union {
211217
mp_float_t f;
212218
mp_uint_t u;
@@ -257,12 +263,13 @@ static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
257263
#error MICROPY_OBJ_REPR_D requires MICROPY_FLOAT_IMPL_DOUBLE
258264
#endif
259265

266+
#include <math.h>
260267
#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))}
261268
#define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))}
262269
#if MICROPY_PY_MATH_CONSTANTS
263270
#define mp_const_float_tau {((mp_obj_t)((uint64_t)0x401921fb54442d18 + 0x8004000000000000))}
264271
#define mp_const_float_inf {((mp_obj_t)((uint64_t)0x7ff0000000000000 + 0x8004000000000000))}
265-
#define mp_const_float_nan {((mp_obj_t)((uint64_t)0xfff8000000000000 + 0x8004000000000000))}
272+
#define mp_const_float_nan {((mp_obj_t)((uint64_t)0x7ff8000000000000 + 0x8004000000000000))}
266273
#endif
267274

268275
static inline bool mp_obj_is_float(mp_const_obj_t o) {
@@ -276,6 +283,13 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
276283
return num.f;
277284
}
278285
static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
286+
if (isnan(f)) {
287+
// prevent creation of bad nanboxed pointers via array.array or struct
288+
struct {
289+
uint64_t r;
290+
} num = mp_const_float_nan;
291+
return num.r;
292+
}
279293
union {
280294
mp_float_t f;
281295
uint64_t r;

tests/float/float_array.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,10 @@ def test(a):
1919
test(array("f"))
2020
test(array("d"))
2121

22-
print("{:.4f}".format(array("f", bytes(array("I", [0x3DCCCCCC])))[0]))
22+
# hand-crafted floats, including non-standard nan
23+
for float_hex in (0x3DCCCCCC, 0x7F800024, 0x7FC00004):
24+
f = array("f", bytes(array("I", [float_hex])))[0]
25+
if type(f) is float:
26+
print("{:.4e}".format(f))
27+
else:
28+
print(f)

tests/float/math_constants_extra.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
raise SystemExit
1010

1111
print(math.tau == 2.0 * math.pi)
12+
print(math.copysign(1.0, math.tau))
1213

1314
print(math.inf == float("inf"))
1415
print(-math.inf == -float("inf"))
16+
print(math.copysign(1.0, math.inf))
1517

1618
print(isnan(math.nan))
1719
print(isnan(-math.nan))
20+
print(math.copysign(1.0, math.nan))

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy