Merge branch '1.2.x' into 1.3.x
authorMark Wooding <mdw@distorted.org.uk>
Wed, 27 Nov 2019 15:11:08 +0000 (15:11 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Wed, 27 Nov 2019 15:11:08 +0000 (15:11 +0000)
* 1.2.x: (89 commits)
  t/: Add a test suite.
  ec.c: Don't lose error status when constructing points from a sequence.
  ec.c: Free partially constructed points coordinatewise.
  *.c: Be more careful about `PySequence_Size'.
  key.c: Reformat the rest of the `KeyError' constructor.
  key.c: Parse `KeyError' constructor arguments by hand.
  catacomb-python.h: Add a macro for raising `OverflowError'.
  key.c: Collect `KeyError' argument count as a separate step.
  key.c: Use tuple functions on `KeyError' argument tuple.
  key.c: Rename sad-path label to `end'.
  key.c: Delete duplicate setting of `errstring'.
  util.c (mkexc): Populate dictionary before constructing exception class.
  key.c: Only set the error code.
  catacomb.c, util.c: Publish negative constants correctly.
  field.c: Delete the completely unused `getfe' function.
  key.c (convfilter): Fix sense of error tests.
  buffer.c, ec.c: Fix required size for EC `buffer' encoding.
  algorithms.c: Fix `max' property name in docstrings.
  catacomb/__init__.py (_HashBase): Check that integers are within bounds.
  debian/rules: Build using the provided Makefile.
  ...

19 files changed:
1  2 
MANIFEST.in
algorithms.c
algorithms.py
buffer.c
catacomb-python.h
catacomb.c
catacomb/__init__.py
debian/changelog
debian/control
ec.c
field.c
group.c
key.c
mp.c
pgen.c
pubkey.c
rand.c
setup.py
util.c

diff --cc MANIFEST.in
@@@ -8,16 -8,11 +8,17 @@@ include MANIFEST.in setup.py Makefil
  
  ## C extension code.
  include *.c *.h
+ include t/*.py t/keyring
  include algorithms.py
  exclude algorithms.h
 +
 +## Scripts.
 +include pock
  include pwsafe
  
 +## Manual pages.
 +include *.[13]
 +
  ## Python wrapping.
  recursive-include catacomb *.py
  
diff --cc algorithms.c
Simple merge
diff --cc algorithms.py
Simple merge
diff --cc buffer.c
Simple merge
    goto end;                                                           \
  } while (0)
  #define VALERR(str) EXCERR(PyExc_ValueError, str)
+ #define OVFERR(str) EXCERR(PyExc_OverflowError, str)
  #define TYERR(str) EXCERR(PyExc_TypeError, str)
 +#define IXERR(str) EXCERR(PyExc_IndexError, str)
  #define ZDIVERR(str) EXCERR(PyExc_ZeroDivisionError, str)
  #define SYSERR(str) EXCERR(PyExc_SystemError, str)
  #define NIERR(str) EXCERR(PyExc_NotImplementedError, str)
@@@ -233,9 -234,8 +236,10 @@@ MODULES(DO
      return (d);                                                               \
    }
  
- struct nameval { const char *name; unsigned long value; };
 +#define KWLIST (/*unconst*/ char **)kwlist
 +
+ struct nameval { const char *name; unsigned f; unsigned long value; };
+ #define CF_SIGNED 1u
  extern void setconstants(PyObject *, const struct nameval *);
  
  extern PyObject *mexp_common(PyObject *, PyObject *, size_t,
diff --cc catacomb.c
Simple merge
Simple merge
@@@ -1,26 -1,9 +1,32 @@@
 +catacomb-python (1.3.0.1) experimental; urgency=medium
 +
 +  * Fix required Catacomb version in `setup.py' script.  Only affects the
 +    source package.
 +
 + -- Mark Wooding <mdw@distorted.org.uk>  Sun, 22 Sep 2019 01:21:28 +0100
 +
 +catacomb-python (1.3.0) experimental; urgency=medium
 +
 +  * catacomb: Bindings for new blockcipher-based MACs, and AEAD schemes.
 +  * catacomb: Invalidate `grand' objects passed into Python through prime-
 +    generation events.
 +  * catacomb: Improve class docstrings.  (They're still extremely terse.)
 +  * catacomb: Add missing `copy' methods on hash and Keccak objects.
 +  * catacomb: Add `WriteBuffer.contents' as a more convenient way to
 +    extract the contents than coercing to `str' or `ByteString'.
 +  * catacomb: Set `RTLD_DEEPBIND' while loading the native module to work
 +    around #868366.
 +  * pock: New program for generating efficiently verifiable prime numbers,
 +    and for verifying their certificates.
 +
 + -- Mark Wooding <mdw@distorted.org.uk>  Sat, 21 Sep 2019 23:00:25 +0100
 +
+ catacomb-python (1.2.1.1) experimental; urgency=medium
+   * Fixing to build against Debian `stretch'.
+  -- Mark Wooding <mdw@distorted.org.uk>  Mon, 24 Dec 2018 15:21:08 +0000
  catacomb-python (1.2.1) experimental; urgency=low
  
    * Fix use-after-free bug in ECPt hashing causing hash instability.
diff --cc debian/control
@@@ -3,9 -3,9 +3,9 @@@ Section: pytho
  Priority: extra
  XS-Python-Version: >= 2.6, << 2.8
  Maintainer: Mark Wooding <mdw@distorted.org.uk>
- Build-Depends: debhelper (>= 9), pkg-config,
+ Build-Depends: debhelper (>= 9), dh-python, pkg-config,
        python (>= 2.6.6-3~), python-all-dev,
 -      mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.4.0)
 +      mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.5.0)
  Standards-Version: 3.8.0
  
  Package: python-catacomb
diff --cc ec.c
--- 1/ec.c
--- 2/ec.c
+++ b/ec.c
@@@ -297,11 -290,12 +290,12 @@@ static PyObject *epmeth_ec2osp(PyObjec
    char *p;
    ec_curve *c = ECPT_C(me);
    ec pp = EC_INIT;
-   int f = EC_EXPLY;
+   unsigned f = EC_EXPLY;
    int len;
 -  char *kwlist[] = { "flags", 0 };
 +  static const char *const kwlist[] = { "flags", 0 };
  
-   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|i:ectosp", KWLIST, &f))
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:ec2osp", kwlist,
++  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:ec2osp", KWLIST,
+                                  convuint, &f))
      return (0);
    len = c->f->noctets * 2 + 1;
    rc = bytestring_pywrap(0, len);
@@@ -863,12 -860,12 +862,12 @@@ static PyObject *meth__ECPtCurve_os2ecp
    buf b;
    PyObject *rc = 0;
    ec_curve *cc;
-   int f = EC_XONLY | EC_LSB | EC_SORT | EC_EXPLY;
+   unsigned f = EC_XONLY | EC_LSB | EC_SORT | EC_EXPLY;
    ec pp = EC_INIT;
-   static const char *const kwlist[] = { "buf", "flags", 0 };
 -  char *kwlist[] = { "class", "buf", "flags", 0 };
++  static const char *const kwlist[] = { "class", "buf", "flags", 0 };
  
-   if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|f:os2ecp", KWLIST,
-                                  &me, &p, &len, &f))
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|O&:os2ecp", kwlist,
++  if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|O&:os2ecp", KWLIST,
+                                  &me, &p, &len, convuint, &f))
      return (0);
    buf_init(&b, p, len);
    cc = ECCURVE_C(me);
diff --cc field.c
Simple merge
diff --cc group.c
+++ b/group.c
@@@ -92,12 -92,14 +92,14 @@@ static PyObject *meth__DHInfo_generate(
    unsigned ql = 0, pl;
    unsigned steps = 0;
    grand *r = &rand_global;
-   pgev evt = { 0 };
+   struct excinfo exc = EXCINFO_INIT;
+   pypgev evt = { { 0 } };
 -  char *kwlist[] =
 +  static const char *const kwlist[] =
      { "class", "pbits", "qbits", "event", "rng", "nsteps", 0 };
    PyObject *rc = 0;
  
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
+   evt.exc = &exc;
 +  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", KWLIST,
                                   &me, convuint, &pl, convuint, &ql,
                                   convpgev, &evt, convgrand, &r,
                                   convuint, &steps))
@@@ -117,19 -119,19 +119,21 @@@ static PyObject *meth__DHInfo_genlimlee
    unsigned ql, pl;
    unsigned steps = 0;
    grand *r = &rand_global;
-   pgev oe = { 0 }, ie = { 0 };
+   struct excinfo exc = EXCINFO_INIT;
+   pypgev oe = { { 0 } }, ie = { { 0 } };
    int subgroupp = 1;
    unsigned f = 0;
 -  char *kwlist[] = { "class", "pbits", "qbits", "event", "ievent",
 -                   "rng", "nsteps", "subgroupp", 0 };
 +  static const char *const kwlist[] = {
 +    "class", "pbits", "qbits", "event", "ievent",
 +    "rng", "nsteps", "subgroupp", 0
 +  };
    size_t i, nf;
    mp **v = 0;
    PyObject *rc = 0, *vec = 0;
  
+   oe.exc = ie.exc = &exc;
    if (!PyArg_ParseTupleAndKeywords(arg, kw,
 -                                 "OO&O&|O&O&O&O&O&:genlimlee", kwlist,
 +                                 "OO&O&|O&O&O&O&O&:genlimlee", KWLIST,
                                   &me, convuint, &pl, convuint, &ql,
                                   convpgev, &oe, convpgev, &ie,
                                   convgrand, &r, convuint, &steps,
@@@ -156,13 -158,15 +160,15 @@@ static PyObject *meth__DHInfo_genkcdsa(
    unsigned ql, pl;
    unsigned steps = 0;
    grand *r = &rand_global;
-   pgev evt = { 0 };
+   struct excinfo exc = EXCINFO_INIT;
+   pypgev evt = { { 0 } };
 -  char *kwlist[] = { "class", "pbits", "qbits",
 -                   "event", "rng", "nsteps", 0 };
 +  static const char *const kwlist[] =
 +    { "class", "pbits", "qbits", "event", "rng", "nsteps", 0 };
    mp *v = MP_NEW;
    PyObject *rc = 0;
  
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&|O&O&O&:genkcdsa", kwlist,
+   evt.exc = &exc;
 +  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&|O&O&O&:genkcdsa", KWLIST,
                                   &me, convuint, &pl, convuint, &ql,
                                   convpgev, &evt, convgrand, &r,
                                   convuint, &steps))
@@@ -187,12 -191,14 +193,14 @@@ static PyObject *meth__DHInfo_gendsa(Py
    dsa_seed ds;
    char *k;
    Py_ssize_t ksz;
-   pgev evt = { 0 };
+   struct excinfo exc = EXCINFO_INIT;
+   pypgev evt = { { 0 } };
 -  char *kwlist[] =
 +  static const char *const kwlist[] =
      { "class", "pbits", "qbits", "seed", "event", "nsteps", 0 };
    PyObject *rc = 0;
  
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&s#|O&O&:gendsa", kwlist,
+   evt.exc = &exc;
 +  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&s#|O&O&:gendsa", KWLIST,
                                   &me, convuint, &pl, convuint, &ql,
                                   &k, &ksz, convpgev, &evt,
                                   convuint, &steps))
diff --cc key.c
Simple merge
diff --cc mp.c
--- 1/mp.c
--- 2/mp.c
+++ b/mp.c
@@@ -1712,10 -1720,11 +1720,11 @@@ static void mpcrt_pydealloc(PyObject *m
  static PyObject *mpcrt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
  {
    mpcrt_mod *v = 0;
-   int n, i = 0;
+   Py_ssize_t n, i = 0, j;
 -  char *kwlist[] = { "mv", 0 };
 +  static const char *const kwlist[] = { "mv", 0 };
    PyObject *q = 0, *x;
-   mp *xx;
+   mp *xx = MP_NEW, *y = MP_NEW, *g = MP_NEW;
+   mpmul mm;
    mpcrt_pyobj *c = 0;
  
    if (PyTuple_Size(arg) > 1)
diff --cc pgen.c
--- 1/pgen.c
--- 2/pgen.c
+++ b/pgen.c
@@@ -548,15 -549,14 +549,14 @@@ static int pgev_python(int rq, pgen_eve
    PyObject *rc = 0;
    int st = PGEN_ABORT;
    long l;
 -  char *meth[] = {
 -    "pg_abort", "pg_done", "pg_begin", "pg_try", "pg_fail", "pg_pass"
 -  };
 +  static const char *const meth[] =
 +    { "pg_abort", "pg_done", "pg_begin", "pg_try", "pg_fail", "pg_pass" };
  
-   Py_INCREF(py);
    rq++;
    if (rq > N(meth)) SYSERR("event code out of range");
    pyev = pgevent_pywrap(ev);
-   if ((rc = PyObject_CallMethod(py, (/*unconst*/ char *)meth[rq],
 -  if ((rc = PyObject_CallMethod(pg->obj, meth[rq], "(O)", pyev)) == 0)
++  if ((rc = PyObject_CallMethod(pg->obj, (/*unconst*/ char *)meth[rq],
 +                              "(O)", pyev)) == 0)
      goto end;
    if (rc == Py_None)
      st = PGEN_TRY;
@@@ -926,14 -925,16 +925,16 @@@ static PyObject *meth_pgen(PyObject *me
    char *p = "p";
    pgen_filterctx fc = { 2 };
    rabin tc;
-   pgev step = { 0 }, test = { 0 }, evt = { 0 };
+   struct excinfo exc = EXCINFO_INIT;
+   pypgev step = { { 0 } }, test = { { 0 } }, evt = { { 0 } };
    unsigned nsteps = 0, ntests = 0;
 -  char *kwlist[] = { "start", "name", "stepper", "tester", "event",
 -                   "nsteps", "ntests", 0 };
 +  static const char *const kwlist[] =
 +    { "start", "name", "stepper", "tester", "event", "nsteps", "ntests", 0 };
  
-   step.proc = pgen_filter; step.ctx = &fc;
-   test.proc = pgen_test; test.ctx = &tc;
+   step.exc = &exc; step.ev.proc = pgen_filter; step.ev.ctx = &fc;
+   test.exc = &exc; test.ev.proc = pgen_test; test.ev.ctx = &tc;
+   evt.exc = &exc;
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&O&O&:pgen", kwlist,
 +  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&O&O&:pgen", KWLIST,
                                   convmp, &x, &p, convpgev, &step,
                                   convpgev, &test, convpgev, &evt,
                                   convuint, &nsteps, convuint, &ntests))
@@@ -961,12 -960,13 +960,14 @@@ static PyObject *meth_strongprime_setup
    unsigned nbits;
    char *name = "p";
    unsigned n = 0;
-   pgev evt = { 0 };
+   struct excinfo exc = EXCINFO_INIT;
+   pypgev evt = { { 0 } };
    PyObject *rc = 0;
 -  char *kwlist[] = { "nbits", "name", "event", "rng", "nsteps", 0 };
 +  static const char *const kwlist[] =
 +    { "nbits", "name", "event", "rng", "nsteps", 0 };
  
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", kwlist,
+   evt.exc = &exc;
 +  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
                                   convuint, &nbits, &name,
                                   convpgev, &evt, convgrand, &r,
                                   convuint, &n))
@@@ -989,12 -989,13 +990,14 @@@ static PyObject *meth_strongprime(PyObj
    unsigned nbits;
    char *name = "p";
    unsigned n = 0;
-   pgev evt = { 0 };
+   struct excinfo exc = EXCINFO_INIT;
+   pypgev evt = { { 0 } };
    PyObject *rc = 0;
 -  char *kwlist[] = { "nbits", "name", "event", "rng", "nsteps", 0 };
 +  static const char *const kwlist[] =
 +    { "nbits", "name", "event", "rng", "nsteps", 0 };
  
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", kwlist,
+   evt.exc = &exc;
 +  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
                                   convuint, &nbits, &name,
                                   convpgev, &evt, convgrand, &r,
                                   convuint, &n))
@@@ -1019,11 -1021,12 +1023,12 @@@ static PyObject *meth_limlee(PyObject *
    unsigned on = 0;
    size_t i, nf = 0;
    PyObject *rc = 0, *vec;
 -  char *kwlist[] = { "pbits", "qbits", "name", "event", "ievent",
 -                   "rng", "nsteps", 0 };
 +  static const char *const kwlist[] =
 +    { "pbits", "qbits", "name", "event", "ievent", "rng", "nsteps", 0 };
    mp *x = 0, **v = 0;
  
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|sO&O&O&O&:limlee", kwlist,
+   ie.exc = oe.exc = &exc;
 +  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|sO&O&O&O&:limlee", KWLIST,
                                   convuint, &pl, convuint, &ql,
                                   &p, convpgev, &oe, convpgev, &ie,
                                   convgrand, &r, convuint, &on))
diff --cc pubkey.c
+++ b/pubkey.c
@@@ -733,12 -733,13 +733,14 @@@ static PyObject *meth__RSAPriv_generate
    unsigned n = 0;
    rsa_priv rp;
    mp *e = 0;
-   pgev evt = { 0 };
+   struct excinfo exc = EXCINFO_INIT;
+   pypgev evt = { { 0 } };
 -  char *kwlist[] = { "class", "nbits", "event", "rng", "nsteps", "e", 0 };
 +  static const char *const kwlist[] =
 +    { "class", "nbits", "event", "rng", "nsteps", "e", 0 };
    PyObject *rc = 0;
  
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
+   evt.exc = &exc;
 +  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", KWLIST,
                                   &me, convuint, &nbits, convpgev, &evt,
                                   convgrand, &r, convuint, &n,
                                   convmp, &e))
diff --cc rand.c
--- 1/rand.c
--- 2/rand.c
+++ b/rand.c
@@@ -503,10 -503,10 +503,10 @@@ static PyObject *trmeth_timer(PyObject 
  static PyObject *truerand_pynew(PyTypeObject *ty,
                                PyObject *arg, PyObject *kw)
  {
 -  char *kwlist[] = { 0 };
 +  static const char *const kwlist[] = { 0 };
    grand *r;
    PyObject *rc = 0;
-   if (PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST)) goto end;
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist)) goto end;
++  if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST)) goto end;
    r = rand_create();
    r->ops->misc(r, RAND_NOISESRC, &noise_source);
    r->ops->misc(r, RAND_SEED, 160);
@@@ -1267,9 -1261,8 +1267,9 @@@ static PyObject *bbsget_x(PyObject *me
  
  static int bbsset_x(PyObject *me, PyObject *val, void *hunoz)
  {
-   mp *x = 0; grand *r = GRAND_R(me); int rc = -1; if (!x) NIERR("__del__");
+   mp *x = 0; grand *r = GRAND_R(me); int rc = -1; if (!val) NIERR("__del__");
 -  if ((x = getmp(val)) == 0) goto end; r->ops->misc(r, BBS_SET, x); rc = 0;
 +  if ((x = getmp(val)) == 0) goto end;
 +  r->ops->misc(r, BBS_SET, x); rc = 0;
    end: mp_drop(x); return (rc);
  }
  
@@@ -1383,14 -1376,15 +1383,16 @@@ static PyObject *meth__BBSPriv_generate
  {
    bbs_priv bp = { 0 };
    mp *x = MP_TWO;
-   pgev evt = { 0 };
+   struct excinfo exc = EXCINFO_INIT;
+   pypgev evt = { { 0 } };
    unsigned nbits, n = 0;
    grand *r = &rand_global;
 -  char *kwlist[] = { "class", "nbits", "event", "rng", "nsteps", "seed", 0 };
 +  static const char *const kwlist[] =
 +    { "class", "nbits", "event", "rng", "nsteps", "seed", 0 };
    bbspriv_pyobj *rc = 0;
  
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
+   evt.exc = &exc;
 +  if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", KWLIST,
                                   &me, convuint, &nbits, convpgev, &evt,
                                   convgrand, &r, convuint, &n, convmp, &x))
      goto end;
diff --cc setup.py
+++ b/setup.py
@@@ -23,7 -23,11 +23,12 @@@ MS.setup(name = 'catacomb-python'
           author_email = 'mdw@distorted.org.uk',
           license = 'GNU General Public License',
           packages = ['catacomb'],
 -         scripts = ['pwsafe'],
 +         scripts = ['pock', 'pwsafe'],
 +         data_files = [('share/man/man1', ['pock.1', 'pwsafe.1'])],
           genfiles = [MS.Generate('algorithms.h')],
+          unittest_dir = "t",
+          unittests = ["t-misc", "t-algorithms", "t-bytes", "t-buffer",
+                       "t-convert", "t-ec", "t-field", "t-group", "t-key",
+                       "t-mp", "t-passphrase", "t-pgen", "t-pubkey",
+                       "t-rand", "t-rat", "t-share"],
           ext_modules = [cat])
diff --cc util.c
--- 1/util.c
--- 2/util.c
+++ b/util.c
@@@ -609,9 -743,7 +743,9 @@@ PyObject *gmapmeth_get(PyObject *me, Py
  {
    PyObject *k, *def = Py_None, *v;
  
-   if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO:get",
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:get", def_kwlist, &k, &def))
++  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:get",
 +                                 (/*unconst*/ char **)def_kwlist,
 +                                 &k, &def))
      return (0);
    if ((v = PyObject_GetItem(me, k)) != 0) return (v);
    PyErr_Clear();
@@@ -622,9 -754,8 +756,9 @@@ PyObject *gmapmeth_setdefault(PyObject 
  {
    PyObject *k, *def = Py_None, *v;
  
-   if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO:setdefault",
+   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:setdefault",
 -                                 def_kwlist, &k, &def))
 +                                 (/*unconst*/ char **)def_kwlist,
 +                                 &k, &def))
      return (0);
    if ((v = PyObject_GetItem(me, k)) != 0) return (v);
    PyErr_Clear();
@@@ -636,9 -767,7 +770,9 @@@ PyObject *gmapmeth_pop(PyObject *me, Py
  {
    PyObject *k, *def = 0, *v;
  
-   if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO:pop",
 -  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:pop", def_kwlist, &k, &def))
++  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:pop",
 +                                 (/*unconst*/ char **)def_kwlist,
 +                                 &k, &def))
      return (0);
    if ((v = PyObject_GetItem(me, k)) != 0) {
      PyObject_DelItem(me, k);