Skip to content

Commit 72ff5c2

Browse files
committed
Fixed ToInt32() with values >= 2**(53+30).
1 parent 3457c71 commit 72ff5c2

File tree

2 files changed

+68
-3
lines changed

2 files changed

+68
-3
lines changed

src/njs_number.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,12 @@ njs_number_to_int32(double num)
8585

8686
exp = (conv.u64 & NJS_DBL_EXPONENT_MASK) >> NJS_DBL_SIGNIFICAND_SIZE;
8787

88-
if (njs_fast_path(exp < (NJS_DBL_EXPONENT_OFFSET + 30))) {
88+
if (njs_fast_path(exp < (NJS_DBL_EXPONENT_OFFSET + 31))) {
8989
/* |num| < 2**31. */
9090
return num;
9191
}
9292

93-
if (exp < (NJS_DBL_EXPONENT_OFFSET + 30 + 53)) {
93+
if (exp < (NJS_DBL_EXPONENT_OFFSET + 31 + 53)) {
9494
v = (conv.u64 & NJS_DBL_SIGNIFICAND_MASK) | NJS_DBL_HIDDEN_BIT;
9595
v <<= (exp - NJS_DBL_EXPONENT_BIAS + 32);
9696
r = v >> 32;
@@ -105,7 +105,7 @@ njs_number_to_int32(double num)
105105
/*
106106
* ES5.1: integer must be modulo 2^32.
107107
* The distance between larger doubles
108-
* (exp >= NJS_DBL_EXPONENT_OFFSET + 30 + 53) is a multiple of 2**32 => 0.
108+
* (exp >= NJS_DBL_EXPONENT_OFFSET + 31 + 53) is a multiple of 2**32 => 0.
109109
* This also handles NaN and Inf.
110110
*/
111111

src/test/njs_unit_test.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22303,6 +22303,69 @@ njs_string_to_index_test(njs_vm_t *vm, njs_opts_t *opts, njs_stat_t *stat)
2230322303
}
2230422304

2230522305

22306+
static njs_int_t
22307+
njs_to_int32_test(njs_vm_t *vm, njs_opts_t *opts, njs_stat_t *stat)
22308+
{
22309+
int32_t i32, second;
22310+
njs_uint_t i;
22311+
22312+
static const struct {
22313+
double value;
22314+
int32_t expected;
22315+
} tests[] = {
22316+
{ -1.0, -1 },
22317+
{ 0.0, 0 },
22318+
{ 0.001, 0 },
22319+
{ 1.0, 1 },
22320+
{ 2147483647.0, 2147483647 },
22321+
{ 2147483648.0, -2147483648 },
22322+
{ 2147483649.0, -2147483647 },
22323+
{ -1844674406941458432.0, -2147483648 },
22324+
{ 4.835703278458518e+24 /* 2**(53+29) + 2**30 */, 1073741824 },
22325+
{ 9.671406556917036e+24 /* 2**(53+30) + 2**31 */, -2147483648 },
22326+
};
22327+
22328+
for (i = 0; i < njs_nitems(tests); i++) {
22329+
i32 = njs_number_to_int32(tests[i].value);
22330+
22331+
if (i32 != tests[i].expected) {
22332+
njs_printf("njs_to_int32_test(%f):\n"
22333+
"expected: %D\n got: %D\n",
22334+
tests[i].value, tests[i].expected, i32);
22335+
22336+
stat->failed++;
22337+
continue;
22338+
}
22339+
22340+
second = njs_number_to_int32(i32);
22341+
22342+
if (i32 != second) {
22343+
njs_printf("njs_to_int32_test(%f): not idempodent\n"
22344+
"expected: %D\n got: %D\n",
22345+
tests[i].value, i32, second);
22346+
22347+
stat->failed++;
22348+
continue;
22349+
}
22350+
22351+
second = njs_number_to_int32(njs_number_to_uint32(tests[i].value));
22352+
22353+
if (i32 != second) {
22354+
njs_printf("ToInt32(%f) != ToInt32(ToUint32(%f))\n"
22355+
"left: %D\n right: %D\n",
22356+
tests[i].value, tests[i].value, i32, second);
22357+
22358+
stat->failed++;
22359+
continue;
22360+
}
22361+
22362+
stat->passed++;
22363+
}
22364+
22365+
return NJS_OK;
22366+
}
22367+
22368+
2230622369
static njs_int_t
2230722370
njs_vm_internal_api_test(njs_unit_test_t unused[], size_t num, njs_str_t *name,
2230822371
njs_opts_t *opts, njs_stat_t *stat)
@@ -22329,6 +22392,8 @@ njs_vm_internal_api_test(njs_unit_test_t unused[], size_t num, njs_str_t *name,
2232922392
njs_str("njs_sort_test") },
2233022393
{ njs_string_to_index_test,
2233122394
njs_str("njs_string_to_index_test") },
22395+
{ njs_to_int32_test,
22396+
njs_str("njs_to_int32_test") },
2233222397
};
2233322398

2233422399
vm = NULL;

0 commit comments

Comments
 (0)