[Python-Dev] test_threaded_import

Tim Peters tim.one@home.com
Wed, 29 Aug 2001 19:42:59 -0400


[Jack Jansen]
> ...
> Elementary, my dear Watson. I do a "make install", which runs the
> regression tests twice, succeeding both times. Then I do "python" and
> "import autotest", at which point it fails, thereby failing
> approximately 30% of the time. Of course, not being Sherlock Jansen, I
> didn't realise autotest!=regrtest for this:-)

Ah, a signficant digits error.  Had you said "approximately 33% of the
time", or even "approximately 3e1%", I would have guessed instantly <wink>.

> ...
> I'll apply your patch, which seems to fix the problem fine for the
> time being. Still, there's three issues that I think need to be solved
> at some point:
> - the fact that you (or some other thread) are holding the import lock
>   is one of the few Python state bits that are not open to
>   introspection.

The patch below adds introspection, sufficient to avoid special-casing
autotest.  Guido?  I'd upload the patch to SF instead, but, as you've (Jack)
noted, that's a black hole <0.9 wink>.

> - There may be denial of service attacks possible with this if a 16
>   year old scriptkiddy can think of a way to exploit it in a
>   restricted interpreter.

Someone else will have to worry about that; in a world where a 20-character
regexp can take centuries to match, I don't take DOS from a general-purpose
programming language seriously.

> - The whole idea that a process deadlocked on semaphore locks is
>   completely uninterruptible also smells bad.

That's threads for you:  start a thread, risk a deadlock.  There's no
portable way to interrupt a thread waiting on a lock, and, e.g., no *safe*
way at all on Windows short of killing the whole process.
Index: Python/import.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/import.c,v
retrieving revision 2.185
diff -c -r2.185 import.c
*** Python/import.c	2001/08/13 23:05:44	2.185
--- Python/import.c	2001/08/29 23:25:28
***************
*** 138,143 ****
--- 138,151 ----
  static long import_lock_thread = -1;
  static int import_lock_level = 0;

+ static PyObject *
+ imp_lock_held(PyObject *self, PyObject *args)
+ {
+ 	if (!PyArg_ParseTuple(args, ":lock_held"))
+ 		return NULL;
+ 	return PyInt_FromLong(import_lock_thread != -1);
+ }
+
  static void
  lock_import(void)
  {
***************
*** 179,184 ****
--- 187,200 ----
  #define lock_import()
  #define unlock_import()

+ static PyObject *
+ imp_lock_held(PyObject *self, PyObject *args)
+ {
+ 	if (!PyArg_ParseTuple(args, ":lock_held"))
+ 		return NULL;
+ 	return PyInt_FromLong(0);
+ }
+
  #endif

  /* Helper for sys */
***************
*** 2339,2350 ****
--- 2355,2373 ----
  The module name must include the full package name, if any.\
  ";

+ static char doc_lock_held[] = "\
+ lock_held() -> 0 or 1\n\
+ Return 1 if the import lock is currently held.\n\
+ On platforms without threads, return 0.\
+ ";
+
  static PyMethodDef imp_methods[] = {
  	{"find_module",		imp_find_module,	1, doc_find_module},
  	{"get_magic",		imp_get_magic,		1, doc_get_magic},
  	{"get_suffixes",	imp_get_suffixes,	1, doc_get_suffixes},
  	{"load_module",		imp_load_module,	1, doc_load_module},
  	{"new_module",		imp_new_module,		1, doc_new_module},
+ 	{"lock_held",		imp_lock_held,		1, doc_lock_held},
  	/* The rest are obsolete */
  	{"get_frozen_object",	imp_get_frozen_object,	1},
  	{"init_builtin",	imp_init_builtin,	1},