Skip to content

Commit 5cb1af1

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

File tree

5 files changed

+38
-4
lines changed

5 files changed

+38
-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: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,16 @@ 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+
#define mp_nan_obj_bits (0x7fc00000)
189+
#define MP_OBJ_NEW_FLOAT(f) (mp_obj_t)((((((uint64_t)f) & ~3) | 2) + 0x80800000) & 0xffffffff)
190+
#define MP_OBJ_NEW_CONST_FLOAT(f) MP_ROM_PTR(MP_OBJ_NEW_FLOAT(f))
188191
#define mp_const_float_e MP_OBJ_NEW_CONST_FLOAT(0x402df854)
189192
#define mp_const_float_pi MP_OBJ_NEW_CONST_FLOAT(0x40490fdb)
190193
#if MICROPY_PY_MATH_CONSTANTS
191194
#define mp_const_float_tau MP_OBJ_NEW_CONST_FLOAT(0x40c90fdb)
192195
#define mp_const_float_inf MP_OBJ_NEW_CONST_FLOAT(0x7f800000)
193-
#define mp_const_float_nan MP_OBJ_NEW_CONST_FLOAT(0xffc00000)
196+
#define mp_const_float_nan MP_OBJ_NEW_CONST_FLOAT(mp_nan_obj_bits)
194197
#endif
195198

196199
static inline bool mp_obj_is_float(mp_const_obj_t o) {
@@ -207,6 +210,10 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
207210
return num.f;
208211
}
209212
static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
213+
if (isnan(f)) {
214+
// prevent creation of bad nanboxed pointers via array.array or struct
215+
return MP_OBJ_NEW_FLOAT(mp_nan_obj_bits);
216+
}
210217
union {
211218
mp_float_t f;
212219
mp_uint_t u;
@@ -257,12 +264,13 @@ static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
257264
#error MICROPY_OBJ_REPR_D requires MICROPY_FLOAT_IMPL_DOUBLE
258265
#endif
259266

267+
#include <math.h>
260268
#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))}
261269
#define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))}
262270
#if MICROPY_PY_MATH_CONSTANTS
263271
#define mp_const_float_tau {((mp_obj_t)((uint64_t)0x401921fb54442d18 + 0x8004000000000000))}
264272
#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))}
273+
#define mp_const_float_nan {((mp_obj_t)((uint64_t)0x7ff8000000000000 + 0x8004000000000000))}
266274
#endif
267275

268276
static inline bool mp_obj_is_float(mp_const_obj_t o) {
@@ -276,6 +284,13 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
276284
return num.f;
277285
}
278286
static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
287+
if (isnan(f)) {
288+
// prevent creation of bad nanboxed pointers via array.array or struct
289+
struct {
290+
uint64_t r;
291+
} num = mp_const_float_nan;
292+
return num.r;
293+
}
279294
union {
280295
mp_float_t f;
281296
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 _ in (0x3DCCCCCC, 0x7F800024, 0x7FC00004):
24+
f = array("f", bytes(array("I", [_])))[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