From c2d70945dce9cb09d5d7120d6e9ddf7faac8d230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6gberg?= Date: Wed, 22 Nov 2017 13:19:57 +0100 Subject: Replace the libc environment with a thread-safe emulation putenv(3) and friends aren't thread-safe regardless of how you slice it; a global lock around all environment operations (like before) keeps things safe as far as our own operations go, but we have absolutely no control over what libc or a library dragged in by a driver/NIF does -- they're free to call getenv(3) or putenv(3) without honoring our lock. This commit solves this by setting up an "emulated" environment which can't be touched without going through our interfaces. Third-party libraries can still shoot themselves in the foot but benign uses of os:putenv/2 will no longer risk crashing the emulator. --- erts/emulator/beam/bif.tab | 8 +- erts/emulator/beam/break.c | 16 +-- erts/emulator/beam/dist.c | 2 +- erts/emulator/beam/erl_alloc.types | 6 +- erts/emulator/beam/erl_bif_info.c | 2 +- erts/emulator/beam/erl_bif_os.c | 199 ++++++++++--------------------------- erts/emulator/beam/erl_bif_port.c | 193 +++++++++++------------------------ erts/emulator/beam/erl_init.c | 13 +-- erts/emulator/beam/erl_unicode.c | 16 +-- erts/emulator/beam/global.h | 2 +- erts/emulator/beam/io.c | 18 +++- erts/emulator/beam/sys.h | 37 ++++--- erts/emulator/beam/utils.c | 19 ++-- 13 files changed, 184 insertions(+), 347 deletions(-) (limited to 'erts/emulator/beam') diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 1bd4acbf95..1c5e19cd88 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -374,9 +374,10 @@ bif ets:match_spec_run_r/3 # Bifs in os module. # -bif os:putenv/2 -bif os:getenv/0 -bif os:getenv/1 +bif os:get_env_var/1 +bif os:set_env_var/2 +bif os:unset_env_var/1 +bif os:list_env_vars/0 bif os:getpid/0 bif os:timestamp/0 bif os:system_time/0 @@ -617,7 +618,6 @@ bif erlang:float_to_binary/2 bif erlang:binary_to_float/1 bif io:printable_range/0 -bif os:unsetenv/1 # # New in 17.0 diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 2bfb481771..cb8812c455 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -775,16 +775,16 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) * - write dump until alarm or file is written completely */ - if (erts_sys_getenv__("ERL_CRASH_DUMP_SECONDS", env, &envsz) != 0) { - env_erl_crash_dump_seconds_set = 0; - secs = -1; + if (erts_sys_explicit_8bit_getenv("ERL_CRASH_DUMP_SECONDS", env, &envsz) == 1) { + env_erl_crash_dump_seconds_set = 1; + secs = atoi(env); } else { - env_erl_crash_dump_seconds_set = 1; - secs = atoi(env); + env_erl_crash_dump_seconds_set = 0; + secs = -1; } if (secs == 0) { - return; + return; } /* erts_sys_prepare_crash_dump returns 1 if heart port is found, otherwise 0 @@ -800,7 +800,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) crash_dump_limit = ERTS_SINT64_MAX; envsz = sizeof(env); - if (erts_sys_getenv__("ERL_CRASH_DUMP_BYTES", env, &envsz) == 0) { + if (erts_sys_explicit_8bit_getenv("ERL_CRASH_DUMP_BYTES", env, &envsz) == 1) { Sint64 limit; char* endptr; errno = 0; @@ -813,7 +813,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) } } - if (erts_sys_getenv__("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0) + if (erts_sys_explicit_8bit_getenv("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 1) dumpname = "erl_crash.dump"; else dumpname = &dumpnamebuf[0]; diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 7ff7462bf6..30390cdb5e 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -1212,7 +1212,7 @@ erts_dsig_send_group_leader(ErtsDSigData *dsdp, Eterm leader, Eterm remote) # define PURIFY_MSG(msg) \ do { \ char buf__[1]; size_t bufsz__ = sizeof(buf__); \ - if (erts_sys_getenv_raw("VALGRIND_LOG_XML", buf__, &bufsz__) >= 0) { \ + if (erts_sys_explicit_8bit_getenv("VALGRIND_LOG_XML", buf__, &bufsz__) >= 0) { \ VALGRIND_PRINTF_XML("" \ "%s, line %d: %s\n", \ __FILE__, __LINE__, msg); \ diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index c6cc5c78b3..8107f133aa 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -283,6 +283,8 @@ type THR_PRGR_DATA LONG_LIVED SYSTEM thr_prgr_data type T_THR_PRGR_DATA SHORT_LIVED SYSTEM temp_thr_prgr_data type RELEASE_LAREA SHORT_LIVED SYSTEM release_literal_area +type ENVIRONMENT SYSTEM SYSTEM environment + # # Types used for special emulators # @@ -370,8 +372,6 @@ type SYS_READ_BUF TEMPORARY SYSTEM sys_read_buf type FD_TAB LONG_LIVED SYSTEM fd_tab type FD_ENTRY_BUF STANDARD SYSTEM fd_entry_buf type CS_PROG_PATH LONG_LIVED SYSTEM cs_prog_path -type ENVIRONMENT TEMPORARY SYSTEM environment -type PUTENV_STR SYSTEM SYSTEM putenv_string type PRT_REP_EXIT STANDARD SYSTEM port_report_exit type SYS_BLOCKING STANDARD SYSTEM sys_blocking @@ -383,9 +383,7 @@ type SYS_WRITE_BUF TEMPORARY SYSTEM sys_write_buf type DRV_DATA_BUF SYSTEM SYSTEM drv_data_buf type PRELOADED LONG_LIVED SYSTEM preloaded -type PUTENV_STR SYSTEM SYSTEM putenv_string type WAITER_OBJ LONG_LIVED SYSTEM waiter_object -type ENVIRONMENT SYSTEM SYSTEM environment type CON_VPRINTF_BUF TEMPORARY SYSTEM con_vprintf_buf +endif diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 64639e157b..9aafab86c0 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -1754,7 +1754,7 @@ static int check_if_xml(void) { char buf[1]; size_t bufsz = sizeof(buf); - return erts_sys_getenv_raw("VALGRIND_LOG_XML", buf, &bufsz) >= 0; + return erts_sys_explicit_8bit_getenv("VALGRIND_LOG_XML", buf, &bufsz) >= 0; } #else #define check_if_xml() 0 diff --git a/erts/emulator/beam/erl_bif_os.c b/erts/emulator/beam/erl_bif_os.c index 910325a2f4..ce2b27409b 100644 --- a/erts/emulator/beam/erl_bif_os.c +++ b/erts/emulator/beam/erl_bif_os.c @@ -36,8 +36,7 @@ #include "big.h" #include "dist.h" #include "erl_version.h" - -static int check_env_name(char *name); +#include "erl_osenv.h" /* * Return the pid for the Erlang process in the host OS. @@ -67,148 +66,78 @@ BIF_RETTYPE os_getpid_0(BIF_ALIST_0) BIF_RET(buf_to_intlist(&hp, pid_string, n, NIL)); } -BIF_RETTYPE os_getenv_0(BIF_ALIST_0) +static void os_getenv_foreach(Process *process, Eterm *result, Eterm key, Eterm value) { - GETENV_STATE state; - char *cp; - Eterm* hp; - Eterm ret; - Eterm str; + Eterm kvp_term, *hp; - init_getenv_state(&state); + hp = HAlloc(process, 5); + kvp_term = TUPLE2(hp, key, value); + hp += 3; - ret = NIL; - while ((cp = getenv_string(&state)) != NULL) { - str = erts_convert_native_to_filename(BIF_P,(byte *)cp); - hp = HAlloc(BIF_P, 2); - ret = CONS(hp, str, ret); - } + (*result) = CONS(hp, kvp_term, (*result)); +} - fini_getenv_state(&state); +BIF_RETTYPE os_list_env_vars_0(BIF_ALIST_0) +{ + const erts_osenv_t *global_env; + Eterm result = NIL; + + global_env = erts_sys_rlock_global_osenv(); + erts_osenv_foreach_term(global_env, BIF_P, &result, (void*)&os_getenv_foreach); + erts_sys_runlock_global_osenv(); - return ret; + return result; } -#define STATIC_BUF_SIZE 1024 -BIF_RETTYPE os_getenv_1(BIF_ALIST_1) +BIF_RETTYPE os_get_env_var_1(BIF_ALIST_1) { - Process* p = BIF_P; - Eterm str; - Sint len; - int res; - char *key_str, *val; - char buf[STATIC_BUF_SIZE]; - size_t val_size = sizeof(buf); - - key_str = erts_convert_filename_to_native(BIF_ARG_1,buf,STATIC_BUF_SIZE, - ERTS_ALC_T_TMP,1,0,&len); - - if (!check_env_name(key_str)) { - if (key_str && key_str != &buf[0]) - erts_free(ERTS_ALC_T_TMP, key_str); - BIF_ERROR(p, BADARG); - } + const erts_osenv_t *global_env; + Eterm out_term; + int error; - if (key_str != &buf[0]) - val = &buf[0]; - else { - /* len includes zero byte */ - val_size -= len; - val = &buf[len]; - } - res = erts_sys_getenv(key_str, val, &val_size); - - if (res < 0) { - no_var: - str = am_false; - } else { - if (res > 0) { - val = erts_alloc(ERTS_ALC_T_TMP, val_size); - while (1) { - res = erts_sys_getenv(key_str, val, &val_size); - if (res == 0) - break; - else if (res < 0) - goto no_var; - else - val = erts_realloc(ERTS_ALC_T_TMP, val, val_size); - } - } - str = erts_convert_native_to_filename(p,(byte *)val); - } - if (key_str != &buf[0]) - erts_free(ERTS_ALC_T_TMP, key_str); - if (val < &buf[0] || &buf[sizeof(buf)-1] < val) - erts_free(ERTS_ALC_T_TMP, val); - BIF_RET(str); + global_env = erts_sys_rlock_global_osenv(); + error = erts_osenv_get_term(global_env, BIF_P, BIF_ARG_1, &out_term); + erts_sys_runlock_global_osenv(); + + if (error == 0) { + return am_false; + } else if (error < 0) { + BIF_ERROR(BIF_P, BADARG); + } + + return out_term; } -BIF_RETTYPE os_putenv_2(BIF_ALIST_2) +BIF_RETTYPE os_set_env_var_2(BIF_ALIST_2) { - char def_buf_key[STATIC_BUF_SIZE]; - char def_buf_value[STATIC_BUF_SIZE]; - char *key_buf = NULL, *value_buf = NULL; - - key_buf = erts_convert_filename_to_native(BIF_ARG_1,def_buf_key, - STATIC_BUF_SIZE, - ERTS_ALC_T_TMP,0,0,NULL); - if (!check_env_name(key_buf)) - goto badarg; - - value_buf = erts_convert_filename_to_native(BIF_ARG_2,def_buf_value, - STATIC_BUF_SIZE, - ERTS_ALC_T_TMP,1,0, - NULL); - if (!value_buf) - goto badarg; - - if (erts_sys_putenv(key_buf, value_buf)) { - if (key_buf != def_buf_key) { - erts_free(ERTS_ALC_T_TMP, key_buf); - } - if (value_buf != def_buf_value) { - erts_free(ERTS_ALC_T_TMP, value_buf); - } - BIF_ERROR(BIF_P, BADARG); - } - if (key_buf != def_buf_key) { - erts_free(ERTS_ALC_T_TMP, key_buf); - } - if (value_buf != def_buf_value) { - erts_free(ERTS_ALC_T_TMP, value_buf); + erts_osenv_t *global_env; + int error; + + global_env = erts_sys_rwlock_global_osenv(); + error = erts_osenv_put_term(global_env, BIF_ARG_1, BIF_ARG_2); + erts_sys_rwunlock_global_osenv(); + + if (error < 0) { + BIF_ERROR(BIF_P, BADARG); } - BIF_RET(am_true); -badarg: - if (key_buf && key_buf != def_buf_key) - erts_free(ERTS_ALC_T_TMP, key_buf); - if (value_buf && value_buf != def_buf_value) - erts_free(ERTS_ALC_T_TMP, value_buf); - BIF_ERROR(BIF_P, BADARG); + BIF_RET(am_true); } -BIF_RETTYPE os_unsetenv_1(BIF_ALIST_1) +BIF_RETTYPE os_unset_env_var_1(BIF_ALIST_1) { - char *key_buf; - char buf[STATIC_BUF_SIZE]; + erts_osenv_t *global_env; + int error; - key_buf = erts_convert_filename_to_native(BIF_ARG_1,buf,STATIC_BUF_SIZE, - ERTS_ALC_T_TMP,0,0,NULL); - if (!check_env_name(key_buf)) - goto badarg; + global_env = erts_sys_rwlock_global_osenv(); + error = erts_osenv_unset_term(global_env, BIF_ARG_1); + erts_sys_rwunlock_global_osenv(); - if (erts_sys_unsetenv(key_buf)) - goto badarg; - - if (key_buf != buf) { - erts_free(ERTS_ALC_T_TMP, key_buf); + if (error < 0) { + BIF_ERROR(BIF_P, BADARG); } - BIF_RET(am_true); -badarg: - if (key_buf && key_buf != buf) - erts_free(ERTS_ALC_T_TMP, key_buf); - BIF_ERROR(BIF_P, BADARG); + BIF_RET(am_true); } BIF_RETTYPE os_set_signal_2(BIF_ALIST_2) { @@ -224,27 +153,3 @@ BIF_RETTYPE os_set_signal_2(BIF_ALIST_2) { error: BIF_ERROR(BIF_P, BADARG); } - -static int -check_env_name(char *raw_name) -{ - byte *c = (byte *) raw_name; - int encoding; - - if (!c) - return 0; - - encoding = erts_get_native_filename_encoding(); - - if (erts_raw_env_char_is_7bit_ascii_char('\0', c, encoding)) - return 0; /* Do not allow empty name... */ - - /* Verify no '=' characters in variable name... */ - do { - if (erts_raw_env_char_is_7bit_ascii_char('=', c, encoding)) - return 0; - c = erts_raw_env_next_char(c, encoding); - } while (!erts_raw_env_char_is_7bit_ascii_char('\0', c, encoding)); - - return 1; /* Seems ok... */ -} diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index c4a4dd5863..9f0c90ff7b 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -45,7 +45,7 @@ #include "dtrace-wrapper.h" static Port *open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump); -static char* convert_environment(Eterm env); +static int merge_global_environment(erts_osenv_t *env, Eterm key_value_pairs); static char **convert_args(Eterm); static void free_args(char **); @@ -651,6 +651,7 @@ BIF_RETTYPE port_get_data_1(BIF_ALIST_1) static Port * open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) { + int merged_environment = 0; Sint i; Eterm option; Uint arity; @@ -672,12 +673,13 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) opts.read_write = 0; opts.hide_window = 0; opts.wd = NULL; - opts.envir = NULL; opts.exit_status = 0; opts.overlapped_io = 0; opts.spawn_type = ERTS_SPAWN_ANY; opts.argv = NULL; opts.parallelism = erts_port_parallelism; + erts_osenv_init(&opts.envir); + linebuf = 0; *err_nump = 0; @@ -718,11 +720,16 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) goto badarg; } } else if (option == am_env) { - if (opts.envir) /* ignore previous env option... */ - erts_free(ERTS_ALC_T_OPEN_PORT_ENV, opts.envir); - opts.envir = convert_environment(*tp); - if (!opts.envir) - goto badarg; + if (merged_environment) { + /* Ignore previous env option */ + erts_osenv_clear(&opts.envir); + } + + merged_environment = 1; + + if (merge_global_environment(&opts.envir, *tp)) { + goto badarg; + } } else if (option == am_args) { char **av; char **oav = opts.argv; @@ -807,6 +814,12 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) if((linebuf && opts.packet_bytes) || (opts.redir_stderr && !opts.use_stdio)) { goto badarg; +} + + /* If we lacked an env option, fill in the global environment without + * changes. */ + if (!merged_environment) { + merge_global_environment(&opts.envir, NIL); } /* @@ -956,8 +969,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) erts_atomic32_read_bor_relb(&port->state, sflgs); do_return: - if (opts.envir) - erts_free(ERTS_ALC_T_OPEN_PORT_ENV, opts.envir); + erts_osenv_clear(&opts.envir); if (name_buf) erts_free(ERTS_ALC_T_TMP, (void *) name_buf); if (opts.argv) { @@ -977,6 +989,45 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) goto do_return; } +/* Merges the the global environment and the given {Key, Value} list into env, + * unsetting all keys whose value is either 'false' or NIL. The behavior on + * NIL is undocumented and perhaps surprising, but the previous implementation + * worked in this manner. */ +static int merge_global_environment(erts_osenv_t *env, Eterm key_value_pairs) { + const erts_osenv_t *global_env = erts_sys_rlock_global_osenv(); + erts_osenv_merge(env, global_env, 0); + erts_sys_runlock_global_osenv(); + + while (is_list(key_value_pairs)) { + Eterm *cell, *tuple; + + cell = list_val(key_value_pairs); + + if(!is_tuple_arity(CAR(cell), 2)) { + return -1; + } + + tuple = tuple_val(CAR(cell)); + key_value_pairs = CDR(cell); + + if(is_nil(tuple[2]) || tuple[2] == am_false) { + if(erts_osenv_unset_term(env, tuple[1]) < 0) { + return -1; + } + } else { + if(erts_osenv_put_term(env, tuple[1], tuple[2]) < 0) { + return -1; + } + } + } + + if(!is_nil(key_value_pairs)) { + return -1; + } + + return 0; +} + /* Arguments can be given i unicode and as raw binaries, convert filename is used to convert */ static char **convert_args(Eterm l) { @@ -1024,130 +1075,6 @@ static void free_args(char **av) erts_free(ERTS_ALC_T_TMP, av); } -#ifdef DEBUG -#define ERTS_CONV_ENV_BUF_EXTRA 2 -#else -#define ERTS_CONV_ENV_BUF_EXTRA 1024 -#endif - -static char* convert_environment(Eterm env) -{ - /* - * Returns environment buffer in memory allocated - * as ERTS_ALC_T_OPEN_PORT_ENV. Caller *needs* - * to deallocate... - */ - - Sint size, alloc_size; - byte* bytes; - int encoding = erts_get_native_filename_encoding(); - - alloc_size = ERTS_CONV_ENV_BUF_EXTRA; - bytes = erts_alloc(ERTS_ALC_T_OPEN_PORT_ENV, - alloc_size); - size = 0; - - /* ERTS_CONV_ENV_BUF_EXTRA >= for end delimiter... */ - ERTS_CT_ASSERT(ERTS_CONV_ENV_BUF_EXTRA >= 2); - - while (is_list(env)) { - Sint var_sz, val_sz, need; - byte *str, *limit; - Eterm tmp, *tp, *consp; - - consp = list_val(env); - tmp = CAR(consp); - if (is_not_tuple_arity(tmp, 2)) - goto error; - - tp = tuple_val(tmp); - - /* Check encoding of env variable... */ - if (is_not_list(tp[1])) - goto error; - var_sz = erts_native_filename_need(tp[1], encoding); - if (var_sz <= 0) - goto error; - /* Check encoding of value... */ - if (tp[2] == am_false || is_nil(tp[2])) - val_sz = 0; - else if (is_not_list(tp[2])) - goto error; - else { - val_sz = erts_native_filename_need(tp[2], encoding); - if (val_sz < 0) - goto error; - } - - /* Ensure enough memory... */ - need = size; - need += var_sz + val_sz; - /* '=' and '\0' */ - need += 2 * erts_raw_env_7bit_ascii_char_need(encoding); - if (need > alloc_size) { - alloc_size = (need - alloc_size) + alloc_size; - alloc_size += ERTS_CONV_ENV_BUF_EXTRA; - bytes = erts_realloc(ERTS_ALC_T_OPEN_PORT_ENV, - bytes, alloc_size); - } - - /* Write environment variable name... */ - str = bytes + size; - erts_native_filename_put(tp[1], encoding, str); - /* empty variable name is not allowed... */ - if (erts_raw_env_char_is_7bit_ascii_char('\0', str, encoding)) - goto error; - - /* - * Drop null characters at the end and verify that we do - * not have any '=' characters in the name... - */ - limit = str + var_sz; - while (str < limit) { - if (erts_raw_env_char_is_7bit_ascii_char('\0', str, encoding)) - break; - if (erts_raw_env_char_is_7bit_ascii_char('=', str, encoding)) - goto error; - str = erts_raw_env_next_char(str, encoding); - } - - /* Write the equals sign... */ - str = erts_raw_env_7bit_ascii_char_put('=', str, encoding); - - /* Write the value... */ - if (val_sz > 0) { - limit = str + val_sz; - erts_native_filename_put(tp[2], encoding, str); - while (str < limit) { - if (erts_raw_env_char_is_7bit_ascii_char('\0', str, encoding)) - break; - str = erts_raw_env_next_char(str, encoding); - } - } - - /* Delimit... */ - str = erts_raw_env_7bit_ascii_char_put('\0', str, encoding); - - size = str - bytes; - ASSERT(size <= alloc_size); - - env = CDR(consp); - } - - /* End delimit... */ - (void) erts_raw_env_7bit_ascii_char_put('\0', &bytes[size], encoding); - - if (is_nil(env)) - return (char *) bytes; - -error: - - if (bytes) - erts_free(ERTS_ALC_T_OPEN_PORT_ENV, bytes); - - return (char *) NULL; /* error... */ -} - /* ------------ decode_packet() and friends: */ struct packet_callback_args diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 6cef9bd0e3..f52eed41d5 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -50,7 +50,7 @@ #define ERTS_WANT_TIMER_WHEEL_API #include "erl_time.h" #include "erl_check_io.h" - +#include "erl_osenv.h" #ifdef HIPE #include "hipe_mode_switch.h" /* for hipe_mode_switch_init() */ #include "hipe_signal.h" /* for hipe_signal_init() */ @@ -803,8 +803,9 @@ early_init(int *argc, char **argv) /* envbufsz = sizeof(envbuf); - /* erts_sys_getenv(_raw)() not initialized yet; need erts_sys_getenv__() */ - if (erts_sys_getenv__("ERL_THREAD_POOL_SIZE", envbuf, &envbufsz) == 0) + /* erts_osenv hasn't been initialized yet, so we need to fall back to + * erts_sys_explicit_host_getenv() */ + if (erts_sys_explicit_host_getenv("ERL_THREAD_POOL_SIZE", envbuf, &envbufsz) == 1) erts_async_max_threads = atoi(envbuf); else erts_async_max_threads = ERTS_DEFAULT_NO_ASYNC_THREADS; @@ -1210,20 +1211,20 @@ erl_start(int argc, char **argv) &time_warp_mode); envbufsz = sizeof(envbuf); - if (erts_sys_getenv_raw(ERL_MAX_ETS_TABLES_ENV, envbuf, &envbufsz) == 0) + if (erts_sys_explicit_8bit_getenv(ERL_MAX_ETS_TABLES_ENV, envbuf, &envbufsz) == 1) user_requested_db_max_tabs = atoi(envbuf); else user_requested_db_max_tabs = 0; envbufsz = sizeof(envbuf); - if (erts_sys_getenv_raw("ERL_FULLSWEEP_AFTER", envbuf, &envbufsz) == 0) { + if (erts_sys_explicit_8bit_getenv("ERL_FULLSWEEP_AFTER", envbuf, &envbufsz) == 1) { Uint16 max_gen_gcs = atoi(envbuf); erts_atomic32_set_nob(&erts_max_gen_gcs, (erts_aint32_t) max_gen_gcs); } envbufsz = sizeof(envbuf); - if (erts_sys_getenv_raw("ERL_MAX_PORTS", envbuf, &envbufsz) == 0) { + if (erts_sys_explicit_8bit_getenv("ERL_MAX_PORTS", envbuf, &envbufsz) == 1) { port_tab_sz = atoi(envbuf); port_tab_sz_ignore_files = 1; } diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c index b7a5c45fea..bd5439ba24 100644 --- a/erts/emulator/beam/erl_unicode.c +++ b/erts/emulator/beam/erl_unicode.c @@ -2083,18 +2083,9 @@ char* erts_convert_filename_to_wchar(byte* bytes, Uint size, return name_buf; } - -static int filename_len_16bit(byte *str) -{ - byte *p = str; - while(*p != '\0' || p[1] != '\0') { - p += 2; - } - return (p - str); -} -Eterm erts_convert_native_to_filename(Process *p, byte *bytes) +Eterm erts_convert_native_to_filename(Process *p, size_t size, byte *bytes) { - Uint size,num_chars; + Uint num_chars; Eterm *hp; byte *err_pos; Uint num_built; /* characters */ @@ -2108,7 +2099,6 @@ Eterm erts_convert_native_to_filename(Process *p, byte *bytes) case ERL_FILENAME_UTF8_MAC: mac = 1; case ERL_FILENAME_UTF8: - size = strlen((char *) bytes); if (size == 0) return NIL; if (erts_analyze_utf8(bytes,size,&err_pos,&num_chars,NULL) != ERTS_UTF8_OK) { @@ -2123,7 +2113,6 @@ Eterm erts_convert_native_to_filename(Process *p, byte *bytes) } return ret; case ERL_FILENAME_WIN_WCHAR: - size=filename_len_16bit(bytes); if ((size % 2) != 0) { /* Panic fixup to avoid crashing the emulator */ size--; hp = HAlloc(p, size+2); @@ -2146,7 +2135,6 @@ Eterm erts_convert_native_to_filename(Process *p, byte *bytes) goto noconvert; } noconvert: - size = strlen((char *) bytes); hp = HAlloc(p, 2 * size); return erts_bin_bytes_to_list(NIL, hp, bytes, size, 0); } diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 09207364eb..09500c5bc0 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1264,7 +1264,7 @@ char* erts_convert_filename_to_wchar(byte* bytes, Uint size, char *statbuf, size_t statbuf_size, ErtsAlcType_t alloc_type, Sint* used, Uint extra_wchars); -Eterm erts_convert_native_to_filename(Process *p, byte *bytes); +Eterm erts_convert_native_to_filename(Process *p, size_t size, byte *bytes); Eterm erts_utf8_to_list(Process *p, Uint num, byte *bytes, Uint sz, Uint left, Uint *num_built, Uint *num_eaten, Eterm tail); int erts_utf8_to_latin1(byte* dest, const byte* source, int slen); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 9933c8dda4..6158e9613a 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -7715,13 +7715,27 @@ int null_func(void) int erl_drv_putenv(const char *key, char *value) { - return erts_sys_putenv_raw((char*)key, value); + switch (erts_sys_explicit_8bit_putenv((char*)key, value)) { + case -1: /* Insufficient buffer space */ + return 1; + case 1: /* Success */ + return 0; + default: /* Not found */ + return -1; + } } int erl_drv_getenv(const char *key, char *value, size_t *value_size) { - return erts_sys_getenv_raw((char*)key, value, value_size); + switch (erts_sys_explicit_8bit_getenv((char*)key, value, value_size)) { + case -1: /* Insufficient buffer space */ + return 1; + case 1: /* Success */ + return 0; + default: /* Not found */ + return -1; + } } /* get heart_port diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index bf7d310568..290e0b209a 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -636,6 +636,8 @@ typedef struct preload { */ typedef Eterm ErtsTracer; +#include "erl_osenv.h" + /* * This structure contains options to all built in drivers. * None of the drivers use all of the fields. @@ -651,8 +653,7 @@ typedef struct _SysDriverOpts { int hide_window; /* Hide this windows (Windows). */ int exit_status; /* Report exit status of subprocess. */ int overlapped_io; /* Only has effect on windows NT et al */ - char *envir; /* Environment of the port process, */ - /* in Windows format. */ + erts_osenv_t envir; /* Environment of the port process */ char **argv; /* Argument vector in Unix'ish format. */ char *wd; /* Working directory. */ unsigned spawn_type; /* Bitfield of ERTS_SPAWN_DRIVER | @@ -782,9 +783,6 @@ void set_break_quit(void (*)(void), void (*)(void)); void os_flavor(char*, unsigned); void os_version(int*, int*, int*); -void init_getenv_state(GETENV_STATE *); -char * getenv_string(GETENV_STATE *); -void fini_getenv_state(GETENV_STATE *); #define HAVE_ERTS_CHECK_IO_DEBUG typedef struct { @@ -805,20 +803,21 @@ int sys_double_to_chars_ext(double, char*, size_t, size_t); int sys_double_to_chars_fast(double, char*, int, int, int); void sys_get_pid(char *, size_t); -/* erts_sys_putenv() returns, 0 on success and a value != 0 on failure. */ -int erts_sys_putenv(char *key, char *value); -/* Simple variant used from drivers, raw eightbit interface */ -int erts_sys_putenv_raw(char *key, char *value); -/* erts_sys_getenv() returns 0 on success (length of value string in - *size), a value > 0 if value buffer is too small (*size is set to needed - size), and a value < 0 on failure. */ -int erts_sys_getenv(char *key, char *value, size_t *size); -/* Simple variant used from drivers, raw eightbit interface */ -int erts_sys_getenv_raw(char *key, char *value, size_t *size); -/* erts_sys_getenv__() is only allowed to be used in early init phase */ -int erts_sys_getenv__(char *key, char *value, size_t *size); -/* erst_sys_unsetenv() returns 0 on success and a value != 0 on failure. */ -int erts_sys_unsetenv(char *key); +/* erl_drv_get/putenv have been implicitly 8-bit for so long that we can't + * change them without breaking things on Windows. Their return values are + * identical to erts_osenv_get/putenv */ +int erts_sys_explicit_8bit_getenv(char *key, char *value, size_t *size); +int erts_sys_explicit_8bit_putenv(char *key, char *value); + +/* This is identical to erts_sys_explicit_8bit_getenv but falls down to the + * host OS implementation instead of erts_osenv. */ +int erts_sys_explicit_host_getenv(char *key, char *value, size_t *size); + +const erts_osenv_t *erts_sys_rlock_global_osenv(void); +void erts_sys_runlock_global_osenv(void); + +erts_osenv_t *erts_sys_rwlock_global_osenv(void); +void erts_sys_rwunlock_global_osenv(void); /* Easier to use, but not as efficient, environment functions */ char *erts_read_env(char *key); diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 993585be10..fe9f1c7606 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -4360,15 +4360,20 @@ erts_read_env(char *key) char *value = erts_alloc(ERTS_ALC_T_TMP, value_len); int res; while (1) { - res = erts_sys_getenv_raw(key, value, &value_len); - if (res <= 0) - break; - value = erts_realloc(ERTS_ALC_T_TMP, value, value_len); + res = erts_sys_explicit_8bit_getenv(key, value, &value_len); + + if (res >= 0) { + break; + } + + value = erts_realloc(ERTS_ALC_T_TMP, value, value_len); } - if (res != 0) { - erts_free(ERTS_ALC_T_TMP, value); - return NULL; + + if (res != 1) { + erts_free(ERTS_ALC_T_TMP, value); + return NULL; } + return value; } -- cgit v1.2.3