Jim Fulton:

        - Loading non-binary string pickles checks for insecure
          strings. This is needed because cPickle (still)
          uses a restricted eval to parse non-binary string pickles.
          This change is needed to prevent untrusted
          pickles like::

            "S'hello world'*2000000\012p0\012."

          from hosing an application.

        - User-defined types can now support unpickling without
          executing a constructor.

          The second value returned from __reduce__ can now be None,
          rather than an argument tuple. On unpickling, if the second
          value returned from __reduce__ during pickling was None, then
          rather than calling the first value returned from __reduce__,
          directly, the __basicnew__ method of the first value returned
          from __reduce__ is called without arguments.
diff --git a/Modules/cPickle.c b/Modules/cPickle.c
index 138a8d1..c8d15d8 100644
--- a/Modules/cPickle.c
+++ b/Modules/cPickle.c
@@ -1,5 +1,5 @@
 /*
-     cPickle.c,v 1.46 1997/12/04 00:08:07 jim Exp
+     cPickle.c,v 1.48 1997/12/07 14:37:39 jim Exp
 
      Copyright 
 
@@ -55,7 +55,7 @@
 static char cPickle_module_documentation[] = 
 "C implementation and optimization of the Python pickle module\n"
 "\n"
-"cPickle.c,v 1.46 1997/12/04 00:08:07 jim Exp\n"
+"cPickle.c,v 1.48 1997/12/07 14:37:39 jim Exp\n"
 ;
 
 #include "Python.h"
@@ -132,7 +132,7 @@
 static PyObject *__class___str, *__getinitargs___str, *__dict___str,
   *__getstate___str, *__setstate___str, *__name___str, *__reduce___str,
   *write_str, *__safe_for_unpickling___str, *append_str,
-  *read_str, *readline_str, *__main___str,
+  *read_str, *readline_str, *__main___str, *__basicnew___str,
   *copy_reg_str, *dispatch_table_str, *safe_constructors_str;
 
 static int save();
@@ -155,7 +155,7 @@
      PyObject *class_map;
 } Picklerobject;
 
-static PyTypeObject Picklertype;
+staticforward PyTypeObject Picklertype;
 
 typedef struct {
      PyObject_HEAD
@@ -180,7 +180,7 @@
      PyObject *class_map;
 } Unpicklerobject;
  
-static PyTypeObject Unpicklertype;
+staticforward PyTypeObject Unpicklertype;
 
 int 
 cPickle_PyMapping_HasKey(PyObject *o, PyObject *key) {
@@ -1659,7 +1659,7 @@
             state = PyTuple_GET_ITEM(t, 2);
         }
 
-        UNLESS(PyTuple_Check(arg_tup)) {
+        UNLESS(PyTuple_Check(arg_tup) || arg_tup==Py_None) {
             PyErr_Format(PicklingError, "Second element of tuple "
                 "returned by %s must be a tuple", "O", __reduce__);
             goto finally;
@@ -1931,9 +1931,8 @@
 "Objects that know how to pickle objects\n"
 ;
 
-static PyTypeObject Picklertype_value() {
-  PyTypeObject Picklertype = {
-    PyObject_HEAD_INIT(&PyType_Type)
+static PyTypeObject Picklertype = {
+    PyObject_HEAD_INIT(NULL)
     0,                            /*ob_size*/
     "Pickler",                    /*tp_name*/
     sizeof(Picklerobject),                /*tp_basicsize*/
@@ -1955,9 +1954,7 @@
     /* Space for future expansion */
     0L,0L,0L,0L,
     Picklertype__doc__ /* Documentation string */
-  };
-  return Picklertype;
-}
+};
 
 static PyObject *
 find_class(PyObject *class_map,
@@ -2257,14 +2254,30 @@
 static int
 load_string(Unpicklerobject *self) {
     PyObject *str = 0;
-    int len, res = -1;
-    char *s;
+    int len, res = -1, nslash;
+    char *s, q, *p;
 
     static PyObject *eval_dict = 0;
 
     if ((len = (*self->readline_func)(self, &s)) < 0) return -1;
     UNLESS(s=pystrndup(s,len)) return -1;
 
+    /* Check for unquoted quotes (evil strings) */
+    q=*s;
+    if(q != '"' && q != '\'') goto insecure;
+    for(p=s+1, nslash=0; *p; p++)
+      {
+	if(*p==q && nslash%2==0) break;
+	if(*p=='\\') nslash++;
+	else nslash=0;
+      }
+    if(*p==q)
+      {
+	for(p++; *p; p++) if(*p > ' ') goto insecure;
+      }
+    else goto insecure;
+    /********************************************/
+
     UNLESS(eval_dict)
         UNLESS(eval_dict = Py_BuildValue("{s{}}", "__builtins__"))
             goto finally;
@@ -2282,6 +2295,11 @@
     Py_XDECREF(str);
 
     return res;
+    
+insecure:
+    free(s);
+    PyErr_SetString(PyExc_ValueError,"insecure string pickle");
+    return -1;
 } 
 
 
@@ -2555,6 +2573,17 @@
       return NULL;
   }
 
+  if(args==Py_None)
+    {
+      /* Special case, call cls.__basicnew__() */
+      PyObject *basicnew;
+      
+      UNLESS(basicnew=PyObject_GetAttr(cls, __basicnew___str)) return NULL;
+      r=PyObject_CallObject(basicnew, NULL);
+      Py_DECREF(basicnew);
+      if(r) return r;
+    }
+
   if((r=PyObject_CallObject(cls, args))) return r;
 
 err:
@@ -4129,9 +4158,8 @@
 static char Unpicklertype__doc__[] = 
 "Objects that know how to unpickle";
 
-static PyTypeObject Unpicklertype_value() {
-  PyTypeObject Unpicklertype = {
-    PyObject_HEAD_INIT(&PyType_Type)
+static PyTypeObject Unpicklertype = {
+    PyObject_HEAD_INIT(NULL)
     0,                            /*ob_size*/
     "Unpickler",                  /*tp_name*/
     sizeof(Unpicklerobject),              /*tp_basicsize*/
@@ -4153,9 +4181,7 @@
     /* Space for future expansion */
     0L,0L,0L,0L,
     Unpicklertype__doc__ /* Documentation string */
-  };
-  return Unpicklertype;
-}
+};
 
 static struct PyMethodDef cPickle_methods[] = {
   {"dump",         (PyCFunction)cpm_dump,         1,
@@ -4227,6 +4253,7 @@
     INIT_STR(copy_reg);
     INIT_STR(dispatch_table);
     INIT_STR(safe_constructors);
+    INIT_STR(__basicnew__);
 
     UNLESS(copy_reg = PyImport_ImportModule("copy_reg"))
         return -1;
@@ -4280,19 +4307,18 @@
 void
 initcPickle() {
     PyObject *m, *d, *v;
-    char *rev="1.46";
+    char *rev="1.48";
     PyObject *format_version;
     PyObject *compatible_formats;
 
+    Picklertype.ob_type = &PyType_Type;
+    Unpicklertype.ob_type = &PyType_Type;
 
     /* Create the module and add the functions */
     m = Py_InitModule4("cPickle", cPickle_methods,
                      cPickle_module_documentation,
                      (PyObject*)NULL,PYTHON_API_VERSION);
 
-    Picklertype=Picklertype_value();
-    Unpicklertype=Unpicklertype_value();
-
     /* Add some symbolic constants to the module */
     d = PyModule_GetDict(m);
     PyDict_SetItemString(d,"__version__", v = PyString_FromString(rev));