aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/erl_bif_ddll.c3
-rw-r--r--erts/emulator/beam/erl_nif.c54
-rw-r--r--erts/emulator/beam/global.h14
-rw-r--r--erts/emulator/beam/io.c36
-rw-r--r--erts/emulator/test/driver_SUITE.erl12
-rwxr-xr-xerts/emulator/utils/make_driver_tab38
6 files changed, 107 insertions, 50 deletions
diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c
index 579e9b12f4..294bce115f 100644
--- a/erts/emulator/beam/erl_bif_ddll.c
+++ b/erts/emulator/beam/erl_bif_ddll.c
@@ -1505,6 +1505,7 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name)
res = ERL_DE_LOAD_ERROR_BAD_NAME;
goto error;
}
+
erts_atomic_init_nob(&(dh->refc), (erts_aint_t) 0);
erts_atomic32_init_nob(&dh->port_count, 0);
dh->full_path = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sys_strlen(path) + 1);
@@ -1512,7 +1513,7 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name)
dh->flags = 0;
dh->status = ERL_DE_OK;
- if (erts_add_driver_entry(dp, dh, 1) != 0 /* io.c */) {
+ if (erts_add_driver_entry(dp, dh, 1, 1) != 0 /* io.c */) {
/*
* The init in the driver struct did not return 0
*/
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index f883b3f1e3..0e0013e8a4 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -3768,16 +3768,26 @@ static Eterm mkatom(const char *str)
return am_atom_put(str, sys_strlen(str));
}
-static struct tainted_module_t
+struct tainted_module_t
{
struct tainted_module_t* next;
Eterm module_atom;
-}*first_tainted_module = NULL;
+};
+
+erts_atomic_t first_taint; /* struct tainted_module_t* */
-static void add_taint(Eterm mod_atom)
+void erts_add_taint(Eterm mod_atom)
{
- struct tainted_module_t* t;
- for (t=first_tainted_module ; t!=NULL; t=t->next) {
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ extern erts_rwmtx_t erts_driver_list_lock; /* Mutex for driver list */
+#endif
+ struct tainted_module_t *first, *t;
+
+ ERTS_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_driver_list_lock)
+ || erts_thr_progress_is_blocking());
+
+ first = (struct tainted_module_t*) erts_atomic_read_nob(&first_taint);
+ for (t=first ; t; t=t->next) {
if (t->module_atom == mod_atom) {
return;
}
@@ -3785,22 +3795,24 @@ static void add_taint(Eterm mod_atom)
t = erts_alloc_fnf(ERTS_ALC_T_TAINT, sizeof(*t));
if (t != NULL) {
t->module_atom = mod_atom;
- t->next = first_tainted_module;
- first_tainted_module = t;
+ t->next = first;
+ erts_atomic_set_nob(&first_taint, (erts_aint_t)t);
}
}
Eterm erts_nif_taints(Process* p)
{
- struct tainted_module_t* t;
+ struct tainted_module_t *first, *t;
unsigned cnt = 0;
Eterm list = NIL;
Eterm* hp;
- for (t=first_tainted_module ; t!=NULL; t=t->next) {
+
+ first = (struct tainted_module_t*) erts_atomic_read_nob(&first_taint);
+ for (t=first ; t!=NULL; t=t->next) {
cnt++;
}
hp = HAlloc(p,cnt*2);
- for (t=first_tainted_module ; t!=NULL; t=t->next) {
+ for (t=first ; t!=NULL; t=t->next) {
list = CONS(hp, t->module_atom, list);
hp += 2;
}
@@ -3809,9 +3821,11 @@ Eterm erts_nif_taints(Process* p)
void erts_print_nif_taints(fmtfn_t to, void* to_arg)
{
- struct tainted_module_t* t;
+ struct tainted_module_t *t;
const char* delim = "";
- for (t=first_tainted_module ; t!=NULL; t=t->next) {
+
+ t = (struct tainted_module_t*) erts_atomic_read_nob(&first_taint);
+ for ( ; t; t = t->next) {
const Atom* atom = atom_tab(atom_val(t->module_atom));
erts_cbprintf(to,to_arg,"%s%.*s", delim, atom->len, atom->name);
delim = ",";
@@ -3925,6 +3939,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
ErtsSysDdllError errdesc = ERTS_SYS_DDLL_ERROR_INIT;
Eterm ret = am_ok;
int veto;
+ int taint = 1;
struct erl_module_nif* lib = NULL;
struct erl_module_instance* this_mi;
struct erl_module_instance* prev_mi;
@@ -3971,10 +3986,15 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
ASSERT(module_p != NULL);
mod_atomp = atom_tab(atom_val(mod_atom));
- init_func = erts_static_nif_get_nif_init((char*)mod_atomp->name, mod_atomp->len);
- if (init_func != NULL)
- handle = init_func;
-
+ {
+ ErtsStaticNifEntry* sne;
+ sne = erts_static_nif_get_nif_init((char*)mod_atomp->name, mod_atomp->len);
+ if (sne != NULL) {
+ init_func = sne->nif_init;
+ handle = init_func;
+ taint = sne->taint;
+ }
+ }
this_mi = &module_p->curr;
prev_mi = &module_p->old;
if (in_area(caller, module_p->old.code_hdr, module_p->old.code_length)) {
@@ -4011,7 +4031,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
" function: '%s'", errdesc.str);
}
- else if ((add_taint(mod_atom),
+ else if ((taint ? erts_add_taint(mod_atom) : 0,
(entry = erts_sys_ddll_call_nif_init(init_func)) == NULL)) {
ret = load_nif_error(BIF_P, bad_lib, "Library init-call unsuccessful");
}
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index d853b2e352..7724231cd5 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -116,6 +116,7 @@ extern void erts_post_nif(struct enif_environment_t* env);
extern void erts_resource_stop(ErtsResource*, ErlNifEvent, int is_direct_call);
void erts_fire_nif_monitor(ErtsMonitor *tmon);
void erts_nif_demonitored(ErtsResource* resource);
+extern void erts_add_taint(Eterm mod_atom);
extern Eterm erts_nif_taints(Process* p);
extern void erts_print_nif_taints(fmtfn_t to, void* to_arg);
void erts_unload_nif(struct erl_module_nif* nif);
@@ -1150,7 +1151,7 @@ typedef struct {
#define ERTS_SPAWN_DRIVER 1
#define ERTS_SPAWN_EXECUTABLE 2
#define ERTS_SPAWN_ANY (ERTS_SPAWN_DRIVER | ERTS_SPAWN_EXECUTABLE)
-int erts_add_driver_entry(ErlDrvEntry *drv, DE_Handle *handle, int driver_list_locked);
+int erts_add_driver_entry(ErlDrvEntry *drv, DE_Handle *handle, int driver_list_locked, int taint);
void erts_destroy_driver(erts_driver_t *drv);
int erts_save_suspend_process_on_port(Port*, Process*);
Port *erts_open_driver(erts_driver_t*, Eterm, char*, SysDriverOpts*, int *, int *);
@@ -1175,8 +1176,17 @@ void erts_lcnt_update_port_locks(int enable);
#endif
/* driver_tab.c */
+typedef struct {
+ ErlDrvEntry* de;
+ int taint;
+} ErtsStaticDriver;
typedef void *(*ErtsStaticNifInitFPtr)(void);
-ErtsStaticNifInitFPtr erts_static_nif_get_nif_init(const char *name, int len);
+typedef struct ErtsStaticNifEntry_ {
+ const char *nif_name;
+ ErtsStaticNifInitFPtr nif_init;
+ int taint;
+} ErtsStaticNifEntry;
+ErtsStaticNifEntry* erts_static_nif_get_nif_init(const char *name, int len);
int erts_is_static_nif(void *handle);
void erts_init_static_drivers(void);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 9f87285b71..66b8005975 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -61,7 +61,7 @@ extern ErlDrvEntry spawn_driver_entry;
#ifndef __WIN32__
extern ErlDrvEntry forker_driver_entry;
#endif
-extern ErlDrvEntry *driver_tab[]; /* table of static drivers, only used during initialization */
+extern ErtsStaticDriver driver_tab[]; /* table of static drivers, only used during initialization */
erts_driver_t *driver_list; /* List of all drivers, static and dynamic. */
erts_rwmtx_t erts_driver_list_lock; /* Mutex for driver list */
@@ -2835,7 +2835,7 @@ void erts_init_io(int port_tab_size,
int port_tab_size_ignore_files,
int legacy_port_tab)
{
- ErlDrvEntry** dp;
+ ErtsStaticDriver* dp;
UWord common_element_size;
erts_rwmtx_opt_t drv_list_rwmtx_opts = ERTS_RWMTX_OPT_DEFAULT_INITER;
drv_list_rwmtx_opts.type = ERTS_RWMTX_TYPE_EXTREMELY_FREQUENT_READ;
@@ -2894,8 +2894,8 @@ void erts_init_io(int port_tab_size,
init_driver(&forker_driver, &forker_driver_entry, NULL);
#endif
erts_init_static_drivers();
- for (dp = driver_tab; *dp != NULL; dp++)
- erts_add_driver_entry(*dp, NULL, 1);
+ for (dp = driver_tab; dp->de != NULL; dp++)
+ erts_add_driver_entry(dp->de, NULL, 1, dp->taint);
erts_tsd_set(driver_list_lock_status_key, NULL);
erts_rwmtx_rwunlock(&erts_driver_list_lock);
@@ -7351,7 +7351,8 @@ no_stop_select_callback(ErlDrvEvent event, void* private)
}
#define IS_DRIVER_VERSION_GE(DE,MAJOR,MINOR) \
- ((DE)->major_version >= (MAJOR) && (DE)->minor_version >= (MINOR))
+ ((DE)->major_version > (MAJOR) || \
+ ((DE)->major_version == (MAJOR) && (DE)->minor_version >= (MINOR)))
static int
init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle)
@@ -7434,13 +7435,14 @@ void add_driver_entry(ErlDrvEntry *drv){
* Ignore result of erts_add_driver_entry, the init is not
* allowed to fail when drivers are added by drivers.
*/
- erts_add_driver_entry(drv, NULL, rec_lock != NULL);
+ erts_add_driver_entry(drv, NULL, rec_lock != NULL, 0);
}
-int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, int driver_list_locked)
+int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle,
+ int driver_list_locked, int taint)
{
erts_driver_t *dp = erts_alloc(ERTS_ALC_T_DRIVER, sizeof(erts_driver_t));
- int res;
+ int err = 0;
if (!driver_list_locked) {
erts_rwmtx_rwlock(&erts_driver_list_lock);
@@ -7457,9 +7459,21 @@ int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, int driver_list_lo
erts_tsd_set(driver_list_lock_status_key, (void *) 1);
}
- res = init_driver(dp, de, handle);
+ if (taint) {
+ Eterm name_atom = erts_atom_put((byte*)de->driver_name,
+ sys_strlen(de->driver_name),
+ ERTS_ATOM_ENC_LATIN1, 0);
+ if (is_atom(name_atom))
+ erts_add_taint(name_atom);
+ else
+ err = 1;
+ }
+
+ if (!err) {
+ err = init_driver(dp, de, handle);
+ }
- if (res != 0) {
+ if (err) {
/*
* Remove it all again...
*/
@@ -7474,7 +7488,7 @@ int erts_add_driver_entry(ErlDrvEntry *de, DE_Handle *handle, int driver_list_lo
erts_tsd_set(driver_list_lock_status_key, NULL);
erts_rwmtx_rwunlock(&erts_driver_list_lock);
}
- return res;
+ return err;
}
/* Not allowed for dynamic drivers */
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index 294c42780d..40c7cc11e1 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -2589,8 +2589,18 @@ stop_driver(Port, Name) ->
ok = erl_ddll:stop().
load_driver(Dir, Driver) ->
+ Before = erlang:system_info(taints),
case erl_ddll:load_driver(Dir, Driver) of
- ok -> ok;
+ ok ->
+ After = erlang:system_info(taints),
+ case lists:member(Driver, Before) of
+ true ->
+ After = Before;
+ false ->
+ true = lists:member(Driver, After),
+ Before = lists:delete(Driver, After)
+ end,
+ ok;
{error, Error} = Res ->
io:format("~s\n", [erl_ddll:format_error(Error)]),
Res
diff --git a/erts/emulator/utils/make_driver_tab b/erts/emulator/utils/make_driver_tab
index ffb5f58ebf..b7bca1dc3a 100755
--- a/erts/emulator/utils/make_driver_tab
+++ b/erts/emulator/utils/make_driver_tab
@@ -30,6 +30,7 @@ use File::Basename;
my $file = "";
my $nif = "";
my @emu_drivers = ();
+my @emu_nifs = ();
my @static_drivers = ();
my @static_nifs = ();
my $mode = 1;
@@ -61,7 +62,7 @@ while (@ARGV) {
} elsif ($mode == 2) {
$d = basename $d;
$d =~ s/_nif(\..*|)$//; # strip nif.* or just nif
- push(@static_nifs, $d);
+ push(@emu_nifs, $d);
next;
}
$d = basename $d;
@@ -94,37 +95,33 @@ foreach (@static_drivers) {
}
# The array itself
-print "\nErlDrvEntry *driver_tab[] =\n{\n";
+print "\nErtsStaticDriver driver_tab[] =\n{\n";
foreach (@emu_drivers) {
- print " &${_}driver_entry,\n";
+ print " {&${_}driver_entry, 0},\n";
}
foreach (@static_drivers) {
- print " NULL, /* ${_} */\n";
+ print " {NULL, 1}, /* ${_} */\n";
}
-print " NULL\n};\n";
+print " {NULL}\n};\n";
print "void erts_init_static_drivers() {\n";
my $index = 0;
foreach (@static_drivers) {
- print " driver_tab[".(scalar @emu_drivers+$index)."] = ${_}_driver_init();\n";
+ print " driver_tab[".(scalar @emu_drivers+$index)."].de = ${_}_driver_init();\n";
$index++;
}
print "}\n";
-print <<EOF;
-
-typedef struct ErtsStaticNifEntry_ {
- const char *nif_name;
- ErtsStaticNifInitFPtr nif_init;
-} ErtsStaticNifEntry;
-
-EOF
-
# prototypes
+foreach (@emu_nifs) {
+ my $d = ${_};
+ $d =~ s/\.debug//; # strip .debug
+ print "void *".$d."_nif_init(void);\n";
+}
foreach (@static_nifs) {
my $d = ${_};
$d =~ s/\.debug//; # strip .debug
@@ -134,20 +131,25 @@ foreach (@static_nifs) {
# The array itself
print "static ErtsStaticNifEntry static_nif_tab[] =\n{\n";
+foreach (@emu_nifs) {
+ my $d = ${_};
+ $d =~ s/\.debug//; # strip .debug
+ print " {\"${_}\", &".$d."_nif_init, 0},\n";
+}
foreach (@static_nifs) {
my $d = ${_};
$d =~ s/\.debug//; # strip .debug
- print "{\"${_}\",&".$d."_nif_init},\n";
+ print " {\"${_}\", &".$d."_nif_init, 1},\n";
}
print " {NULL,NULL}\n};\n";
print <<EOF;
-ErtsStaticNifInitFPtr erts_static_nif_get_nif_init(const char *name, int len) {
+ErtsStaticNifEntry* erts_static_nif_get_nif_init(const char *name, int len) {
ErtsStaticNifEntry* p;
for (p = static_nif_tab; p->nif_name != NULL; p++)
if (strncmp(p->nif_name, name, len) == 0 && p->nif_name[len] == 0)
- return p->nif_init;
+ return p;
return NULL;
}