Skip to content

Commit a90379e

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 a90379e

File tree

5 files changed

+34
-3
lines changed

5 files changed

+34
-3
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: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ 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+
#include <math.h>
187188
#define MP_OBJ_NEW_CONST_FLOAT(f) MP_ROM_PTR((mp_obj_t)((((((uint64_t)f) & ~3) | 2) + 0x80800000) & 0xffffffff))
188189
#define mp_const_float_e MP_OBJ_NEW_CONST_FLOAT(0x402df854)
189190
#define mp_const_float_pi MP_OBJ_NEW_CONST_FLOAT(0x40490fdb)
@@ -203,14 +204,18 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
203204
union {
204205
mp_float_t f;
205206
mp_uint_t u;
206-
} num = {.u = ((mp_uint_t)o - 0x80800000u) & ~3u};
207+
} num = {.u = ((mp_uint_t)o - 0x80800000u) };
207208
return num.f;
208209
}
209210
static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
210211
union {
211212
mp_float_t f;
212213
mp_uint_t u;
213214
} num = {.f = f};
215+
if (isnan(f)) {
216+
// prevent creation of bad nanboxed pointers via array.array or struct
217+
return (mp_obj_t)((((uint64_t)0xffc00000 & ~0x3u) | 2u) + 0x80800000u);
218+
}
214219
return (mp_obj_t)(((num.u & ~0x3u) | 2u) + 0x80800000u);
215220
}
216221
#endif
@@ -257,12 +262,15 @@ static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
257262
#error MICROPY_OBJ_REPR_D requires MICROPY_FLOAT_IMPL_DOUBLE
258263
#endif
259264

265+
#include <math.h>
266+
#define mp_obj_true_nan ((mp_obj_t)((uint64_t)0x7ff8000000000000 + 0x8004000000000000))
267+
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_true_nan}
266274
#endif
267275

268276
static inline bool mp_obj_is_float(mp_const_obj_t o) {
@@ -276,6 +284,10 @@ 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+
return mp_obj_true_nan;
290+
}
279291
union {
280292
mp_float_t f;
281293
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-crafter 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