From f29e6f9020d89d5b071ada8a59a962ce78a656d3 Mon Sep 17 00:00:00 2001 From: Akos Kiss Date: Fri, 27 Mar 2020 11:03:28 +0100 Subject: [PATCH] Fix undefined overflow behavior when converting double to integer (#3629) Overflows in conversions from floating-point to integer are undefined behavior in the C99 standard. (Clause 6.3.1.4: "If the value of the integral part cannot be represented by the integer type, the behavior is undefined.") When UBSAN is enabled, this gets reported at `srand()` calls. (The random seed is usually initialized using the date port API, which represents dates as `double`s. But `srand` takes an `unsigned int`. A simple cast from `double` to `unsigned` becomes undefined behavior if the value is too large. And "now" is too large nowadays. So, effectively, all executions start with an undefined behavior.) This patch fixes this by casting the floating-point value of the date to an integer through a union. JerryScript-DCO-1.0-Signed-off-by: Akos Kiss akiss@inf.u-szeged.hu --- docs/03.API-EXAMPLE.md | 3 ++- jerry-main/main-unix-test.c | 7 ++++++- jerry-main/main-unix.c | 7 ++++++- targets/curie_bsp/jerry_app/quark/main.c | 3 ++- targets/esp8266/user/jerry_run.c | 3 ++- .../jerryscript-mbed-launcher/source/launcher.cpp | 3 ++- targets/riot-stm32f4/source/main-riotos.c | 3 ++- targets/zephyr/src/main-zephyr.c | 3 ++- tests/unit-core/test-common.h | 3 ++- 9 files changed, 26 insertions(+), 9 deletions(-) diff --git a/docs/03.API-EXAMPLE.md b/docs/03.API-EXAMPLE.md index 0c6d689b0..b6c3c633f 100644 --- a/docs/03.API-EXAMPLE.md +++ b/docs/03.API-EXAMPLE.md @@ -1084,7 +1084,8 @@ int main (void) { /* Initialize srand value */ - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); /* Generate a random number, and print it */ const jerry_char_t script[] = "var a = Math.random (); print(a)"; diff --git a/jerry-main/main-unix-test.c b/jerry-main/main-unix-test.c index 3db77b950..0c8fd9ca4 100644 --- a/jerry-main/main-unix-test.c +++ b/jerry-main/main-unix-test.c @@ -72,7 +72,12 @@ int main (int argc, char **argv) { - srand ((unsigned) jerry_port_get_current_time ()); + union + { + double d; + unsigned u; + } now = { .d = jerry_port_get_current_time () }; + srand (now.u); if (argc <= 1 || (argc == 2 && (!strcmp ("-h", argv[1]) || !strcmp ("--help", argv[1])))) { print_help (argv[0]); diff --git a/jerry-main/main-unix.c b/jerry-main/main-unix.c index 9cd8b8ff6..913349ea5 100644 --- a/jerry-main/main-unix.c +++ b/jerry-main/main-unix.c @@ -467,7 +467,12 @@ int main (int argc, char **argv) { - srand ((unsigned) jerry_port_get_current_time ()); + union + { + double d; + unsigned u; + } now = { .d = jerry_port_get_current_time () }; + srand (now.u); JERRY_VLA (const char *, file_names, argc); int files_counter = 0; diff --git a/targets/curie_bsp/jerry_app/quark/main.c b/targets/curie_bsp/jerry_app/quark/main.c index 2aee9143f..2975bbb0b 100644 --- a/targets/curie_bsp/jerry_app/quark/main.c +++ b/targets/curie_bsp/jerry_app/quark/main.c @@ -136,7 +136,8 @@ void eval_jerry_script (int argc, char *argv[], struct tcmd_handler_ctx *ctx) void jerry_start () { - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); jerry_init (JERRY_INIT_EMPTY); jerry_value_t global_obj_val = jerry_get_global_object (); jerry_value_t print_func_name_val = jerry_create_string ((jerry_char_t *) "print"); diff --git a/targets/esp8266/user/jerry_run.c b/targets/esp8266/user/jerry_run.c index ab70ff766..e7fff4c37 100644 --- a/targets/esp8266/user/jerry_run.c +++ b/targets/esp8266/user/jerry_run.c @@ -26,7 +26,8 @@ static const char* fn_sys_loop_name = "sysloop"; void js_entry () { - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); jerry_init (JERRY_INIT_EMPTY); js_register_functions (); diff --git a/targets/mbedos5/jerryscript-mbed/jerryscript-mbed-launcher/source/launcher.cpp b/targets/mbedos5/jerryscript-mbed/jerryscript-mbed-launcher/source/launcher.cpp index 1acf2f169..4c70be883 100644 --- a/targets/mbedos5/jerryscript-mbed/jerryscript-mbed-launcher/source/launcher.cpp +++ b/targets/mbedos5/jerryscript-mbed/jerryscript-mbed-launcher/source/launcher.cpp @@ -68,7 +68,8 @@ static int load_javascript() { } int jsmbed_js_init() { - srand ((unsigned) jerry_port_get_current_time()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); jerry_init_flag_t flags = JERRY_INIT_EMPTY; jerry_init(flags); diff --git a/targets/riot-stm32f4/source/main-riotos.c b/targets/riot-stm32f4/source/main-riotos.c index d77aa274b..28b9df84a 100644 --- a/targets/riot-stm32f4/source/main-riotos.c +++ b/targets/riot-stm32f4/source/main-riotos.c @@ -98,7 +98,8 @@ const shell_command_t shell_commands[] = { int main (void) { - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); printf ("You are running RIOT on a(n) %s board.\n", RIOT_BOARD); printf ("This board features a(n) %s MCU.\n", RIOT_MCU); diff --git a/targets/zephyr/src/main-zephyr.c b/targets/zephyr/src/main-zephyr.c index 6ea0b8466..e250f9d39 100644 --- a/targets/zephyr/src/main-zephyr.c +++ b/targets/zephyr/src/main-zephyr.c @@ -79,7 +79,8 @@ static int shell_cmd_handler (char *source_buffer) void main (void) { - srand ((unsigned) jerry_port_get_current_time ()); + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; + srand (now.u); uint32_t zephyr_ver = sys_kernel_version_get (); printf ("JerryScript build: " __DATE__ " " __TIME__ "\n"); printf ("JerryScript API %d.%d.%d\n", JERRY_API_MAJOR_VERSION, JERRY_API_MINOR_VERSION, JERRY_API_PATCH_VERSION); diff --git a/tests/unit-core/test-common.h b/tests/unit-core/test-common.h index 24c115a66..aaa942d21 100644 --- a/tests/unit-core/test-common.h +++ b/tests/unit-core/test-common.h @@ -49,7 +49,8 @@ #define TEST_INIT() \ do \ { \ - srand ((unsigned) jerry_port_get_current_time ()); \ + union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; \ + srand (now.u); \ } while (0) /**