diff -c SpreadModule-1.5/setup.py SpreadModule-1.5v4/setup.py *** SpreadModule-1.5/setup.py Tue Jan 25 11:40:45 2005 --- SpreadModule-1.5v4/setup.py Tue Dec 19 13:41:06 2006 *************** *** 64,74 **** ext = Extension('spread', ['spreadmodule.c'], include_dirs = [SPREAD_DIR + "/include"], library_dirs = [SPREAD_DIR + "/lib"], ! libraries = ['tspread'], ) setup(name = "SpreadModule", ! version = "1.5", maintainer = "Zope Corporation", maintainer_email = "zodb-dev@zope.org", description = doclines[0], --- 64,74 ---- ext = Extension('spread', ['spreadmodule.c'], include_dirs = [SPREAD_DIR + "/include"], library_dirs = [SPREAD_DIR + "/lib"], ! libraries = ['tspread-core'], ) setup(name = "SpreadModule", ! version = "1.5v4", maintainer = "Zope Corporation", maintainer_email = "zodb-dev@zope.org", description = doclines[0], diff -c SpreadModule-1.5/spreadmodule.c SpreadModule-1.5v4/spreadmodule.c *** SpreadModule-1.5/spreadmodule.c Tue Jan 18 14:08:42 2005 --- SpreadModule-1.5v4/spreadmodule.c Mon Dec 18 13:43:40 2006 *************** *** 62,67 **** --- 62,70 ---- #define DEFAULT_GROUPS_SIZE 10 #define DEFAULT_BUFFER_SIZE 10000 + #define MAX_VSSETS 10 + #define MAX_MEMBERS 100 + typedef struct { PyObject_HEAD mailbox mbox; *************** *** 89,95 **** PyObject *group; PyObject *group_id; PyObject *members; ! PyObject *extra; /* that are still members */ } MembershipMsg; typedef struct { --- 92,98 ---- PyObject *group; PyObject *group_id; PyObject *members; ! PyObject *orig_members; /* the vs sets that came together in this vs */ } MembershipMsg; typedef struct { *************** *** 193,206 **** char (*members)[MAX_GROUP_NAME], char *buffer, int size) { MembershipMsg *self; ! int32 num_extra_members; ! group_id grp_id; /* Although extra_members isn't referenced unless num_extra_members is * greater than 0, gcc doesn't realize that, so force extra_members to * be initialized (suppressing a nuisance complaint from the compiler). */ ! char *extra_members = NULL; ! int i; assert(group != NULL); self = PyObject_New(MembershipMsg, &MembershipMsg_Type); --- 196,216 ---- char (*members)[MAX_GROUP_NAME], char *buffer, int size) { MembershipMsg *self; ! int32 num_extra_members; ! group_id grp_id; /* Although extra_members isn't referenced unless num_extra_members is * greater than 0, gcc doesn't realize that, so force extra_members to * be initialized (suppressing a nuisance complaint from the compiler). */ ! membership_info memb_info; ! int max_num_vs_sets = MAX_VSSETS; ! vs_set_info vssets_buffer[MAX_VSSETS]; ! vs_set_info *vssets = vssets_buffer; ! unsigned int my_vsset_index; ! int num_vs_sets, max_members; ! char vs_members_buffer[MAX_MEMBERS][MAX_GROUP_NAME]; ! char (*vs_members)[MAX_GROUP_NAME] = vs_members_buffer; ! int i, j, ret; assert(group != NULL); self = PyObject_New(MembershipMsg, &MembershipMsg_Type); *************** *** 210,216 **** Py_INCREF(group); self->group = group; self->members = NULL; ! self->extra = NULL; self->group_id = NULL; self->members = PyTuple_New(num_members); if (self->members == NULL) { --- 220,226 ---- Py_INCREF(group); self->group = group; self->members = NULL; ! self->orig_members = NULL; self->group_id = NULL; self->members = PyTuple_New(num_members); if (self->members == NULL) { *************** *** 226,285 **** PyTuple_SET_ITEM(self->members, i, s); } ! num_extra_members = 0; ! if (SP_get_vs_set_offset_memb_mess() <= size) { ! /* Pick grp_id and num_extra_members out of the buffer. ! * This uses memcpy instead of casting tricks because there's ! * no guarantee that the offsets in buffer are properly ! * aligned for the type. Even gcc's memcpy() can produce ! * segfaults then, unless the natural type is first cast ! * away to char*. ! */ ! memcpy((char *)&grp_id, ! buffer + SP_get_gid_offset_memb_mess(), ! sizeof(grp_id)); ! self->group_id = new_group_id(grp_id); if (self->group_id == NULL) { Py_DECREF(self); return NULL; } ! memcpy((char *)&num_extra_members, ! buffer + SP_get_num_vs_offset_memb_mess(), ! sizeof(num_extra_members)); ! extra_members = buffer + SP_get_vs_set_offset_memb_mess(); ! ! if (size - SP_get_vs_set_offset_memb_mess() < ! num_extra_members * MAX_GROUP_NAME) { ! /* SP_receive error (corrupted message). */ ! Py_DECREF(self); ! PyErr_Format(PyExc_AssertionError, ! "SP_receive: a membership message said " ! "there were %d extra members, but only %d " ! "bytes remain in the buffer. Corrupted " ! "message?", ! num_extra_members, ! size - SP_get_vs_set_offset_memb_mess()); ! return NULL; } ! } ! ! self->extra = PyTuple_New(num_extra_members); ! if (self->extra == NULL) { ! Py_DECREF(self); ! return NULL; ! } ! for (i = 0; i < num_extra_members; i++, extra_members+= MAX_GROUP_NAME) { ! PyObject *s; ! /* Spread promises this: */ ! assert(strlen(extra_members) < MAX_GROUP_NAME); ! s = PyString_FromString(extra_members); ! if (!s) { ! Py_DECREF(self); ! return NULL; } - PyTuple_SET_ITEM(self->extra, i, s); } return (PyObject *)self; } static void --- 236,313 ---- PyTuple_SET_ITEM(self->members, i, s); } ! ret = SP_get_memb_info( buffer, type, &memb_info ); ! if (ret < 0) { ! Py_DECREF(self); /* printf("BUG: membership message does not have valid body\n"); */ ! return NULL; ! } ! ! if ( type & REG_MEMB_MESS ) { ! self->group_id = new_group_id(memb_info.gid); if (self->group_id == NULL) { Py_DECREF(self); return NULL; } ! if ( memb_info.num_vs_sets > max_num_vs_sets ) { ! max_num_vs_sets = memb_info.num_vs_sets; ! vssets = malloc(sizeof(vs_set_info) * max_num_vs_sets); ! if (vssets == NULL) { ! PyErr_NoMemory(); ! goto memb_error; ! } } ! num_vs_sets = SP_get_vs_sets_info( buffer, &vssets[0], max_num_vs_sets, &my_vsset_index ); ! if (num_vs_sets < 0) { ! goto memb_error; /* shouldn't happen */ ! } ! self->orig_members = PyTuple_New(num_vs_sets); ! if (self->orig_members == NULL) { ! goto memb_error; ! } ! max_members = 0; ! for ( i = 0; i < num_vs_sets; i++ ) { ! if ( vssets[i].num_members > max_members ) { max_members = vssets[i].num_members; } ! } ! if ( max_members > MAX_MEMBERS ) { ! vs_members = malloc( MAX_GROUP_NAME * max_members ); ! if (vs_members == NULL) { ! PyErr_NoMemory(); ! goto memb_error; ! } ! } ! for ( i = 0; i < num_vs_sets; i++ ) { ! PyObject *t; ! ret = SP_get_vs_set_members(buffer, &vssets[i], vs_members, max_members); ! if (ret < 0) { ! goto memb_error; /* shouldn't happen */ ! } ! t = PyTuple_New(vssets[i].num_members); ! for ( j = 0; j < vssets[i].num_members; j++ ) { ! PyObject *s; ! /* Spread promises this: */ ! assert(strlen(vs_members[j]) < MAX_GROUP_NAME); ! s = PyString_FromString(vs_members[j]); ! if (!s) { ! goto memb_error; ! } ! PyTuple_SET_ITEM(t, j, s); ! } ! PyTuple_SET_ITEM(self->orig_members, i, t); } } + + if (vssets != vssets_buffer) + free(vssets); + if (vs_members != vs_members_buffer) + free(vs_members); return (PyObject *)self; + memb_error: + if (vssets != vssets_buffer) + free(vssets); + if (vs_members != vs_members_buffer) + free(vs_members); + Py_DECREF(self); + return NULL; } static void *************** *** 287,293 **** { Py_XDECREF(self->group); Py_XDECREF(self->members); ! Py_XDECREF(self->extra); Py_XDECREF(self->group_id); PyObject_Del(self); } --- 315,321 ---- { Py_XDECREF(self->group); Py_XDECREF(self->members); ! Py_XDECREF(self->orig_members); Py_XDECREF(self->group_id); PyObject_Del(self); } *************** *** 299,305 **** {"group", T_OBJECT, OFF(group)}, {"group_id", T_OBJECT, OFF(group_id)}, {"members", T_OBJECT, OFF(members)}, ! {"extra", T_OBJECT, OFF(extra)}, {NULL} }; --- 327,333 ---- {"group", T_OBJECT, OFF(group)}, {"group_id", T_OBJECT, OFF(group_id)}, {"members", T_OBJECT, OFF(members)}, ! {"orig_members", T_OBJECT, OFF(orig_members)}, {NULL} }; diff -c SpreadModule-1.5/testspread.py SpreadModule-1.5v4/testspread.py *** SpreadModule-1.5/testspread.py Tue Jan 18 14:08:42 2005 --- SpreadModule-1.5v4/testspread.py Mon Dec 18 13:58:21 2006 *************** *** 83,91 **** "expected group to have one member") self.assertEqual(msg.members[0], mbox.private_group, "expected this mbox to be in group") ! self.assertEqual(len(msg.extra), 1, "expected one mbox to cause the join") ! self.assertEqual(msg.extra[0], mbox.private_group, "expected this mbox to cause the join") mbox.leave(group) --- 83,93 ---- "expected group to have one member") self.assertEqual(msg.members[0], mbox.private_group, "expected this mbox to be in group") ! self.assertEqual(len(msg.orig_members), 1, "expected one mbox to cause the join") ! self.assertEqual(len(msg.orig_members[0]), 1, ! "expected one mbox to cause the join") ! self.assertEqual(msg.orig_members[0][0], mbox.private_group, "expected this mbox to cause the join") mbox.leave(group) *************** *** 94,100 **** self.assertEqual(msg.group, group) self.assertEqual(msg.reason, spread.CAUSED_BY_LEAVE) self.assertEqual(len(msg.members), 0) ! self.assertEqual(len(msg.extra), 0) mbox.disconnect() --- 96,102 ---- self.assertEqual(msg.group, group) self.assertEqual(msg.reason, spread.CAUSED_BY_LEAVE) self.assertEqual(len(msg.members), 0) ! self.assertEqual(msg.orig_members, None) mbox.disconnect()