Add slab allocator; reduce delta with srvx-gs.
authorMichael Poole <mdpoole@troilus.org>
Mon, 31 Jan 2005 05:14:52 +0000 (05:14 +0000)
committerMichael Poole <mdpoole@troilus.org>
Mon, 31 Jan 2005 05:14:52 +0000 (05:14 +0000)
configure.in: Check for getpagesize().  Support --with-malloc=slab.

src/Makefile.am: Add alloc-slab.c as an extra source file.

src/alloc-srvx.c: Clean up srvx_free() slightly.  Check for previously
allocated blocks.

srvx.conf.example, src/chanserv.c, src/main.c, src/modcmd.c,
src/proto-p10.c: Apply patches to bring closer to srvx-gs branch.

src/log.c: Assert and _exit() on fatal log messages.

src/opserv.c: Clarify logic for modes to set on join floods.

src/proto-common.c: Accept off-channel commands in registered channels.
git-archimport-id: srvx@srvx.net--2005-srvx/srvx--devo--1.3--patch-10

17 files changed:
ChangeLog
configure.in
src/Makefile.am
src/alloc-slab.c [new file with mode: 0644]
src/alloc-srvx.c
src/chanserv.c
src/chanserv.h
src/common.h
src/hash.h
src/helpfile.c
src/log.c
src/main.c
src/modcmd.c
src/opserv.c
src/proto-common.c
src/proto-p10.c
srvx.conf.example

index 05846ca326f3a0de842d33302f2242161b298ac4..e309721dc7d5e79000e97f6d93aac3f9696c67b6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,39 @@
 # arch-tag: automatic-ChangeLog--srvx@srvx.net--2005-srvx/srvx--devo--1.3
 #
 
 # arch-tag: automatic-ChangeLog--srvx@srvx.net--2005-srvx/srvx--devo--1.3
 #
 
+2005-01-31 05:14:52 GMT        Michael Poole <mdpoole@troilus.org>     patch-10
+
+    Summary:
+      Add slab allocator; reduce delta with srvx-gs.
+    Revision:
+      srvx--devo--1.3--patch-10
+
+    configure.in: Check for getpagesize().  Support --with-malloc=slab.
+    
+    src/Makefile.am: Add alloc-slab.c as an extra source file.
+    
+    src/alloc-srvx.c: Clean up srvx_free() slightly.  Check for previously
+    allocated blocks.
+    
+    srvx.conf.example, src/chanserv.c, src/main.c, src/modcmd.c,
+    src/proto-p10.c: Apply patches to bring closer to srvx-gs branch.
+    
+    src/log.c: Assert and _exit() on fatal log messages.
+    
+    src/opserv.c: Clarify logic for modes to set on join floods.
+    
+    src/proto-common.c: Accept off-channel commands in registered channels.
+
+    new files:
+     src/.arch-ids/alloc-slab.c.id src/alloc-slab.c
+
+    modified files:
+     ChangeLog configure.in src/Makefile.am src/alloc-srvx.c
+     src/chanserv.c src/chanserv.h src/common.h src/hash.h
+     src/helpfile.c src/log.c src/main.c src/modcmd.c src/opserv.c
+     src/proto-common.c src/proto-p10.c srvx.conf.example
+
+
 2005-01-26 21:16:54 GMT        Michael Poole <mdpoole@troilus.org>     patch-9
 
     Summary:
 2005-01-26 21:16:54 GMT        Michael Poole <mdpoole@troilus.org>     patch-9
 
     Summary:
index 81dd91dc3bff4a7836f14ae3062215a7c56ad981..3df600bf3404a8692c53e8e00860c888c3828b9f 100644 (file)
@@ -79,7 +79,7 @@ if test $ac_cv_func_gettimeofday = no; then
 fi
 
 dnl We have fallbacks in case these are missing, so just check for them.
 fi
 
 dnl We have fallbacks in case these are missing, so just check for them.
-AC_CHECK_FUNCS(bcopy memcpy memset strdup strerror strsignal localtime_r setrlimit inet_ntoa getopt getopt_long regcomp regexec regfree sysconf,,)
+AC_CHECK_FUNCS(bcopy getpagesize memcpy memset strdup strerror strsignal localtime_r setrlimit inet_ntoa getopt getopt_long regcomp regexec regfree sysconf,,)
 
 dnl Check for absolutely required library functions.
 AC_CHECK_FUNCS(select socket strcspn strspn strtod strtoul,,AC_MSG_ERROR([a required function was not found.  srvx build will fail.]))
 
 dnl Check for absolutely required library functions.
 AC_CHECK_FUNCS(select socket strcspn strspn strtod strtoul,,AC_MSG_ERROR([a required function was not found.  srvx build will fail.]))
@@ -180,6 +180,10 @@ elif test "x$withval" = "xsrvx" ; then
   AC_MSG_RESULT(srvx)
   AC_DEFINE(WITH_MALLOC_SRVX, 1, [Define if using the srvx internal debug allocator])
   MODULE_OBJS="$MODULE_OBJS alloc-srvx.\$(OBJEXT)"
   AC_MSG_RESULT(srvx)
   AC_DEFINE(WITH_MALLOC_SRVX, 1, [Define if using the srvx internal debug allocator])
   MODULE_OBJS="$MODULE_OBJS alloc-srvx.\$(OBJEXT)"
+elif test "x$withval" = "xslab" ; then
+  AC_MSG_RESULT(slab)
+  AC_DEFINE(WITH_MALLOC_SLAB, 1, [Define if using the slab internal debug allocator])
+  MODULE_OBJS="$MODULE_OBJS alloc-slab.\$(OBJEXT)"
 else
   AC_MSG_ERROR([Unknown malloc type $withval])
 fi
 else
   AC_MSG_ERROR([Unknown malloc type $withval])
 fi
index 7fe7c1d12f8ecf40389242d41725d00eebec14f8..2ac28aad5190ecb42f14e4ec90689da836b8e704 100644 (file)
@@ -22,7 +22,7 @@ checkversion:
            mv $$TMPFILE arch-version.h ; \
        fi
 
            mv $$TMPFILE arch-version.h ; \
        fi
 
-EXTRA_srvx_SOURCES = alloc-srvx.c proto-bahamut.c proto-common.c proto-p10.c mod-snoop.c mod-memoserv.c mod-helpserv.c mod-sockcheck.c
+EXTRA_srvx_SOURCES = alloc-slab.c alloc-srvx.c proto-bahamut.c proto-common.c proto-p10.c mod-snoop.c mod-memoserv.c mod-helpserv.c mod-sockcheck.c
 srvx_LDADD = @MODULE_OBJS@
 srvx_DEPENDENCIES = @MODULE_OBJS@
 srvx_SOURCES = \
 srvx_LDADD = @MODULE_OBJS@
 srvx_DEPENDENCIES = @MODULE_OBJS@
 srvx_SOURCES = \
diff --git a/src/alloc-slab.c b/src/alloc-slab.c
new file mode 100644 (file)
index 0000000..b44f6a0
--- /dev/null
@@ -0,0 +1,304 @@
+/* alloc-slab.c - Slab debugging allocator
+ * Copyright 2005 srvx Development Team
+ *
+ * This file is part of srvx.
+ *
+ * srvx is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "common.h"
+#include "log.h"
+
+#if defined(HAVE_SYS_MMAN_H)
+# include <sys/mman.h>
+#endif
+
+#if !defined(HAVE_MMAP)
+# error The slab allocator requires that your system have the mmap() system call.
+#endif
+
+struct slab {
+    struct slabset *parent;
+    struct slab *prev;
+    struct slab *next;
+    void *base;
+    void **free;
+    unsigned int used;
+};
+
+struct slabset {
+    struct slabset *next;
+    struct slab *child;
+    size_t size;
+    size_t items_per_slab;
+};
+
+#define SLAB_MIN     (2 * sizeof(void*))
+#define SLAB_GRAIN   sizeof(void*)
+#define SLAB_ALIGN   SLAB_GRAIN
+#define SMALL_CUTOFF 512
+/* Element size < SMALL_CUTOFF -> use small slabs.
+ * Larger elements are allocated directly using mmap().  The largest
+ * regularly allocated struct in srvx 1.x is smaller than
+ * SMALL_CUTOFF, so there is not much point in coding support for
+ * larger slabs.
+ */
+
+static struct slabset *little_slabs[SMALL_CUTOFF / SLAB_GRAIN];
+static struct slabset slabset_slabs;
+unsigned long alloc_count;
+unsigned long alloc_size;
+
+#if defined(MAP_ANON)
+#elif defined(MAP_ANONYMOUS)
+# define MAP_ANON MAP_ANONYMOUS
+#else
+# define MAP_ANON 0
+#endif
+
+static size_t
+slab_pagesize(void)
+{
+    static size_t pagesize;
+    if (pagesize
+#if defined(HAVE_GETPAGESIZE)
+        || (pagesize  = getpagesize())
+#endif
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+        || (pagesize = sysconf(_SC_PAGESIZE))
+#endif
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+        || (pagesize = sysconf(_SC_PAGE_SIZE))
+#endif
+        ) return pagesize;
+    assert(0 && "unable to find system page size");
+    return pagesize = 4096;
+}
+
+static size_t
+slab_round_up(size_t size)
+{
+    return (size + slab_pagesize() - 1) & ~(slab_pagesize() - 1);
+}
+
+static void *
+slab_map(size_t length)
+{
+    static int mmap_fd = -1;
+    void *res;
+
+#if ! MAP_ANON
+    if (mmap_fd < 0) {
+        mmap_fd = open("/dev/zero", 0);
+        if (mmap_fd < 0)
+            log_module(MAIN_LOG, LOG_FATAL, "Unable to open /dev/zero for mmap: %s", strerror(errno()));
+    }
+#endif
+    res = mmap(0, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, mmap_fd, 0);
+    if (res == MAP_FAILED)
+        log_module(MAIN_LOG, LOG_FATAL, "Unable to mmap %lu bytes (%s).", (unsigned long)length, strerror(errno));
+    return res;
+}
+
+static void *slab_alloc(struct slabset *sset);
+static void slab_unalloc(void *ptr, size_t size);
+
+static struct slabset *
+slabset_create(size_t size)
+{
+    unsigned int idx;
+
+    size = (size < SLAB_MIN) ? SLAB_MIN : (size + SLAB_GRAIN - 1) & ~(SLAB_GRAIN - 1);
+    idx = size / SLAB_GRAIN;
+    assert(idx < ArrayLength(little_slabs));
+    if (!little_slabs[idx]) {
+        if (!slabset_slabs.size) {
+            unsigned int idx2 = (sizeof(struct slabset) + SLAB_GRAIN - 1) / SLAB_GRAIN;
+            slabset_slabs.size = sizeof(struct slabset);
+            slabset_slabs.items_per_slab = (slab_pagesize() - sizeof(struct slab)) / ((sizeof(struct slabset) + SLAB_ALIGN - 1) & ~(SLAB_ALIGN - 1));
+            little_slabs[idx2] = &slabset_slabs;
+            if (idx == idx2)
+                return &slabset_slabs;
+        }
+        little_slabs[idx] = slab_alloc(&slabset_slabs);
+        little_slabs[idx]->size = size;
+        little_slabs[idx]->items_per_slab = (slab_pagesize() - sizeof(struct slab)) / ((size + SLAB_ALIGN - 1) & ~(SLAB_ALIGN - 1));
+    }
+    return little_slabs[idx];
+}
+
+static void *
+slab_alloc(struct slabset *sset)
+{
+    struct slab *slab;
+    void **item;
+
+    if (!sset->child || !sset->child->free) {
+        unsigned int ii, step;
+
+        /* Allocate new slab. */
+        item = slab_map(slab_pagesize());
+        slab = (struct slab*)((char*)item + slab_pagesize() - sizeof(*slab));
+        slab->base = item;
+
+        /* Populate free list. */
+        step = (sset->size + SLAB_ALIGN - 1) & ~(SLAB_ALIGN - 1);
+        for (ii = 1, item = slab->free = slab->base;
+             ii < sset->items_per_slab;
+             ++ii, item = (*item = (char*)item + step));
+
+        /* Link to parent slabset. */
+        slab->parent = sset;
+        if ((slab->prev = sset->child)) {
+            slab->next = slab->prev->next;
+            slab->prev->next = slab;
+            if (slab->next)
+                slab->next->prev = slab;
+        }
+        sset->child = slab;
+    }
+
+    slab = sset->child;
+    item = slab->free;
+    slab->free = *item;
+    if (slab->used++ == sset->items_per_slab) {
+        if (sset->child != slab) {
+            /* Unlink slab and reinsert before sset->child. */
+            if (slab->prev)
+                slab->prev->next = slab->next;
+            if (slab->next)
+                slab->next->prev = slab->prev;
+            if ((slab->prev = sset->child->prev))
+                slab->prev->next = slab;
+            if ((slab->next = sset->child))
+                slab->next->prev = slab;
+        } else if (slab->next) {
+            /* Advance sset->child to next pointer. */
+            sset->child = slab->next;
+        }
+    }
+    memset(item, 0, sset->size);
+    return item;
+}
+
+static void
+slab_unalloc(void *ptr, size_t size)
+{
+    void **item;
+    struct slab *slab, *new_next;
+
+    item = ptr;
+    assert(size < SMALL_CUTOFF);
+    slab = (struct slab*)((((unsigned long)ptr | (slab_pagesize() - 1)) + 1) - sizeof(*slab));
+    *item = slab->free;
+    slab->free = item;
+
+    if (slab->used-- == slab->parent->items_per_slab
+        && slab->parent->child != slab) {
+        new_next = slab->parent->child;
+        slab->parent->child = slab;
+    } else if (!slab->used) {
+        for (new_next = slab;
+             new_next->next && new_next->next->used;
+             new_next = new_next->next) ;
+        new_next = new_next->next;
+    } else
+        new_next = NULL;
+
+    if (new_next) {
+        if (slab->prev)
+            slab->prev->next = slab->next;
+        if (slab->next)
+            slab->next->prev = slab->prev;
+        if ((slab->prev = new_next->prev))
+            slab->prev->next = slab;
+        if ((slab->next = new_next->next))
+            slab->next->prev = slab;
+    }
+}
+
+void *
+slab_malloc(UNUSED_ARG(const char *file), UNUSED_ARG(unsigned int line), size_t size)
+{
+    size_t real, *res;
+
+    real = size + sizeof(size_t);
+    if (real < SMALL_CUTOFF)
+        res = slab_alloc(slabset_create(real));
+    else
+        res = slab_map(slab_round_up(real));
+    *res = size;
+    return res + 1;
+}
+
+void *
+slab_realloc(const char *file, unsigned int line, void *ptr, size_t size)
+{
+    size_t orig, *newblock;
+
+    if (!ptr)
+        return slab_malloc(file, line, size);
+
+    verify(ptr);
+    orig = ((size_t*)ptr)[-1];
+    if (orig >= size)
+        return ptr;
+    newblock = slab_malloc(file, line, size);
+    memcpy(newblock, ptr, orig);
+    return newblock;
+}
+
+char *
+slab_strdup(const char *file, unsigned int line, const char *src)
+{
+    char *target;
+    size_t len;
+
+    len = strlen(src) + 1;
+    target = slab_malloc(file, line, len);
+    memcpy(target, src, len);
+    return target;
+}
+
+void
+slab_free(UNUSED_ARG(const char *file), UNUSED_ARG(unsigned int line), void *ptr)
+{
+    size_t real, *size;
+
+    if (!ptr)
+        return;
+    verify(ptr);
+    size = (size_t*)ptr - 1;
+    real = *size + sizeof(size_t);
+    if (real < SMALL_CUTOFF)
+        slab_unalloc(size, real);
+    else
+        munmap(size, slab_round_up(real));
+}
+
+void
+verify(const void *ptr)
+{
+    size_t size;
+
+    if (!ptr)
+        return;
+    else if ((size = ((size_t*)ptr)[-1] + sizeof(size_t)) >= SMALL_CUTOFF)
+        assert(((unsigned long)ptr & (slab_pagesize() - 1)) == sizeof(size_t));
+    else {
+        struct slab *slab;
+        size_t expected;
+
+        expected = (size + SLAB_GRAIN - 1) & ~(SLAB_GRAIN - 1);
+        slab = (struct slab*)((((unsigned long)ptr | (slab_pagesize() - 1)) + 1) - sizeof(*slab));
+        assert(slab->parent->size == expected);
+    }
+}
index 72fca5a6e10947d9b8437d8936a05149e7a66014..45fd15de72cbde97e34a016b41e53240fbb561fd 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "common.h"
  */
 
 #include "common.h"
+#include "log.h"
 
 #undef malloc
 #undef free
 
 #undef malloc
 #undef free
@@ -60,6 +61,11 @@ srvx_malloc(const char *file, unsigned int line, size_t size)
 
     block = malloc(sizeof(*block) + size + sizeof(redzone));
     assert(block != NULL);
 
     block = malloc(sizeof(*block) + size + sizeof(redzone));
     assert(block != NULL);
+    if (block->magic == ALLOC_MAGIC && block->file_id < file_ids_used) {
+        /* Only report the error, due to possible false positives. */
+        log_module(MAIN_LOG, LOG_WARNING, "Detected possible reallocation: %p (called by %s:%u/%u; allocated by %u:%u/%u).",
+                   block, file, line, size, block->file_id, block->line, block->size);
+    }
     memset(block, 0, sizeof(*block) + size);
     memcpy((char*)(block + 1) + size, redzone, sizeof(redzone));
     block->file_id = get_file_id(file);
     memset(block, 0, sizeof(*block) + size);
     memcpy((char*)(block + 1) + size, redzone, sizeof(redzone));
     block->file_id = get_file_id(file);
@@ -116,23 +122,21 @@ srvx_strdup(const char *file, unsigned int line, const char *src)
 }
 
 void
 }
 
 void
-srvx_free(const char *file, unsigned int line, void *ptr)
+srvx_free(UNUSED_ARG(const char *file), UNUSED_ARG(unsigned int line), void *ptr)
 {
     struct alloc_header *block;
     size_t size;
 
     if (!ptr)
         return;
 {
     struct alloc_header *block;
     size_t size;
 
     if (!ptr)
         return;
+    verify(ptr);
     block = (struct alloc_header *)ptr - 1;
     block = (struct alloc_header *)ptr - 1;
-    assert(block->magic == ALLOC_MAGIC);
-    assert(0 == memcmp((char*)(block + 1) + block->size, redzone, sizeof(redzone)));
     size = block->size;
     memset(block + 1, 0xde, size);
     block->magic = FREE_MAGIC;
     free(block);
     alloc_count--;
     alloc_size -= size;
     size = block->size;
     memset(block + 1, 0xde, size);
     block->magic = FREE_MAGIC;
     free(block);
     alloc_count--;
     alloc_size -= size;
-    (void)file; (void)line;
 }
 
 void
 }
 
 void
index c1d6f9124ec950e86630a91afe20fcb1a2d49883..9f6c1412a802f85710c65aa69cb3606efa8709c6 100644 (file)
@@ -1684,7 +1684,8 @@ static CHANSERV_FUNC(cmd_register)
             return 0;
         }
 
             return 0;
         }
 
-        if(!IsHelping(user) && (!(mn = GetUserMode(channel, user)) || !(mn->modes & MODE_CHANOP)))
+        if(!IsHelping(user)
+           && (!(mn = GetUserMode(channel, user)) || !(mn->modes & MODE_CHANOP)))
         {
             reply("CSMSG_MUST_BE_OPPED", channel->name);
             return 0;
         {
             reply("CSMSG_MUST_BE_OPPED", channel->name);
             return 0;
@@ -4456,18 +4457,21 @@ chanserv_expire_suspension(void *data)
 {
     struct suspended *suspended = data;
     struct chanNode *channel;
 {
     struct suspended *suspended = data;
     struct chanNode *channel;
-    struct mod_chanmode change;
 
     if(!suspended->expires || (now < suspended->expires))
         suspended->revoked = now;
     channel = suspended->cData->channel;
     suspended->cData->channel = channel;
     suspended->cData->flags &= ~CHANNEL_SUSPENDED;
 
     if(!suspended->expires || (now < suspended->expires))
         suspended->revoked = now;
     channel = suspended->cData->channel;
     suspended->cData->channel = channel;
     suspended->cData->flags &= ~CHANNEL_SUSPENDED;
-    mod_chanmode_init(&change);
-    change.argc = 1;
-    change.args[0].mode = MODE_CHANOP;
-    change.args[0].u.member = AddChannelUser(chanserv, channel);
-    mod_chanmode_announce(chanserv, channel, &change);
+    if(!IsOffChannel(suspended->cData))
+    {
+        struct mod_chanmode change;
+        mod_chanmode_init(&change);
+        change.argc = 1;
+        change.args[0].mode = MODE_CHANOP;
+        change.args[0].u.member = AddChannelUser(chanserv, channel);
+        mod_chanmode_announce(chanserv, channel, &change);
+    }
 }
 
 static CHANSERV_FUNC(cmd_csuspend)
 }
 
 static CHANSERV_FUNC(cmd_csuspend)
@@ -5494,8 +5498,15 @@ static CHANSERV_FUNC(cmd_giveownership)
     new_owner = GetChannelAccess(cData, new_owner_hi);
     if(!new_owner)
     {
     new_owner = GetChannelAccess(cData, new_owner_hi);
     if(!new_owner)
     {
-        reply("CSMSG_NO_CHAN_USER", new_owner_hi->handle, channel->name);
-        return 0;
+        if(force)
+        {
+            new_owner = add_channel_user(cData, new_owner_hi, UL_COOWNER, 0, NULL);
+        }
+        else
+        {
+            reply("CSMSG_NO_CHAN_USER", new_owner_hi->handle, channel->name);
+            return 0;
+        }
     }
     if((chanserv_get_owned_count(new_owner_hi) >= chanserv_conf.max_owned) && !force)
     {
     }
     if((chanserv_get_owned_count(new_owner_hi) >= chanserv_conf.max_owned) && !force)
     {
@@ -6598,6 +6609,8 @@ ban_read_helper(const char *key, struct record_data *rd, struct chanData *chan)
     s_expires = database_get_data(rd->d.object, KEY_EXPIRES, RECDB_QSTRING);
     owner = database_get_data(rd->d.object, KEY_OWNER, RECDB_QSTRING);
     reason = database_get_data(rd->d.object, KEY_REASON, RECDB_QSTRING);
     s_expires = database_get_data(rd->d.object, KEY_EXPIRES, RECDB_QSTRING);
     owner = database_get_data(rd->d.object, KEY_OWNER, RECDB_QSTRING);
     reason = database_get_data(rd->d.object, KEY_REASON, RECDB_QSTRING);
+    if (!reason || !owner)
+        return;
 
     set_time = set ? (time_t)strtoul(set, NULL, 0) : now;
     triggered_time = triggered ? (time_t)strtoul(triggered, NULL, 0) : 0;
 
     set_time = set ? (time_t)strtoul(set, NULL, 0) : now;
     triggered_time = triggered ? (time_t)strtoul(triggered, NULL, 0) : 0;
index d094595fbe6b50b7128b66516ecbd3be31478828..b01a944617221e503278f766f2472b76a83e390f 100644 (file)
@@ -163,7 +163,7 @@ struct do_not_register
 {
     char   chan_name[CHANNELLEN+1];
     char   setter[NICKSERV_HANDLE_LEN+1];
 {
     char   chan_name[CHANNELLEN+1];
     char   setter[NICKSERV_HANDLE_LEN+1];
-    time_t set; 
+    time_t set;
     char   reason[1];
 };
 
     char   reason[1];
 };
 
index 5982512fe3670eda84f87721e133e8193342ed56..e2ee1675e422257a2ef60c6fb6ac20d76949cd4b 100644 (file)
@@ -102,6 +102,24 @@ extern void srvx_free(const char *, unsigned int, void *);
 extern void verify(const void *ptr);
 #  define verify(x) verify(x)
 # endif
 extern void verify(const void *ptr);
 #  define verify(x) verify(x)
 # endif
+#elif defined(WITH_MALLOC_SLAB)
+# define malloc(n) slab_malloc(__FILE__, __LINE__, (n))
+# undef calloc
+# define calloc(m,n) slab_malloc(__FILE__, __LINE__, (m)*(n))
+# undef realloc
+# define realloc(p,n) slab_realloc(__FILE__, __LINE__, (p), (n))
+# undef free
+# define free(p) slab_free(__FILE__, __LINE__, (p))
+# undef strdup
+# define strdup(s) slab_strdup(__FILE__, __LINE__, (s))
+extern void *slab_malloc(const char *, unsigned int, size_t);
+extern void *slab_realloc(const char *, unsigned int, void *, size_t);
+extern char *slab_strdup(const char *, unsigned int, const char *);
+extern void slab_free(const char *, unsigned int, void *);
+# if !defined(NDEBUG)
+extern void verify(const void *ptr);
+#  define verify(x) verify(x)
+# endif
 #endif
 
 #ifndef verify
 #endif
 
 #ifndef verify
index d10c35ea9467b3fc794213d9298e93843d01fed7..443f9f4ddd5a41af8d1ddbd1d878f5abb6ce0f6f 100644 (file)
@@ -58,7 +58,7 @@
 #define FLAGS_STAMPED           0x1000 /* for users who have been stamped */
 #define FLAGS_HIDDEN_HOST       0x2000 /* user's host is masked by their account */
 #define FLAGS_REGNICK           0x4000 /* user owns their current nick */
 #define FLAGS_STAMPED           0x1000 /* for users who have been stamped */
 #define FLAGS_HIDDEN_HOST       0x2000 /* user's host is masked by their account */
 #define FLAGS_REGNICK           0x4000 /* user owns their current nick */
-#define FLAGS_REGISTERING      0x8000 /* user has issued account register command, is waiting for email cookie */
+#define FLAGS_REGISTERING       0x8000 /* user has issued account register command, is waiting for email cookie */
 
 #define IsOper(x)               ((x)->modes & FLAGS_OPER)
 #define IsService(x)            ((x)->modes & FLAGS_SERVICE)
 
 #define IsOper(x)               ((x)->modes & FLAGS_OPER)
 #define IsService(x)            ((x)->modes & FLAGS_SERVICE)
@@ -126,7 +126,7 @@ struct chanNode {
     unsigned int limit, locks;
     char key[KEYLEN + 1];
     time_t timestamp; /* creation time */
     unsigned int limit, locks;
     char key[KEYLEN + 1];
     time_t timestamp; /* creation time */
-  
+
     char topic[TOPICLEN + 1];
     char topic_nick[NICKLEN + 1];
     time_t topic_time;
     char topic[TOPICLEN + 1];
     char topic_nick[NICKLEN + 1];
     time_t topic_time;
index d214fe345e95b45d1514d991ae2d134239d65fad..e5aca29edec0b07b6df8cdc464f4a0c2002e0bd1 100644 (file)
@@ -84,7 +84,7 @@ static struct language *language_alloc(const char *name)
  * lang is a two-letter code according to ISO-639-1 (or three-letter
  * code according to ISO-639-2 for languages not in ISO-639-1), and
  * COUNTRY is the ISO 3166 country code in all upper case.
  * lang is a two-letter code according to ISO-639-1 (or three-letter
  * code according to ISO-639-2 for languages not in ISO-639-1), and
  * COUNTRY is the ISO 3166 country code in all upper case.
- * 
+ *
  * See also:
  * http://www.loc.gov/standards/iso639-2/
  * http://www.loc.gov/standards/iso639-2/langhome.html
  * See also:
  * http://www.loc.gov/standards/iso639-2/
  * http://www.loc.gov/standards/iso639-2/langhome.html
index aefadbb86496e05931bcc60b8400415ceaa7fbdd..8e2600ac0b3fd2a04bf44cc18538c9a2a4eb41c3 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -587,6 +587,10 @@ log_module(struct log_type *type, enum log_severity sev, const char *format, ...
         /* Special behavior before we start full operation */
         fprintf(stderr, "%s: %s\n", log_severity_names[sev], msgbuf);
     }
         /* Special behavior before we start full operation */
         fprintf(stderr, "%s: %s\n", log_severity_names[sev], msgbuf);
     }
+    if (sev == LOG_FATAL) {
+        assert(0 && "fatal message logged");
+        _exit(1);
+    }
 }
 
 /* audit log searching */
 }
 
 /* audit log searching */
@@ -719,7 +723,8 @@ log_entry_search(struct logSearch *discrim, entry_search_func esf, void *data)
     unsigned int matched = 0;
 
     if (discrim->type) {
     unsigned int matched = 0;
 
     if (discrim->type) {
-        struct logEntry *entry, *last;
+        volatile struct logEntry *last;
+        struct logEntry *entry;
 
         for (entry = discrim->type->log_oldest, last = NULL;
              entry;
 
         for (entry = discrim->type->log_oldest, last = NULL;
              entry;
index c16aafac1b41950a99a5b779442e5bd8d6005ca7..215edcf646cb0043e4541e734a838163b2da1014 100644 (file)
@@ -691,6 +691,12 @@ int main(int argc, char *argv[])
     FILE *file_out;
     struct sigaction sv;
 
     FILE *file_out;
     struct sigaction sv;
 
+#if WITH_MALLOC_BOEHM_GC
+    GC_find_leak = 1;
+    GC_set_warn_proc(gc_warn_proc);
+    GC_enable_incremental();
+#endif
+
     daemon = 1;
     debug = 0;
     tools_init();
     daemon = 1;
     debug = 0;
     tools_init();
@@ -816,10 +822,6 @@ int main(int argc, char *argv[])
     MAIN_LOG = log_register_type("srvx", "file:main.log");
     if (debug)
         log_debug();
     MAIN_LOG = log_register_type("srvx", "file:main.log");
     if (debug)
         log_debug();
-#if WITH_MALLOC_BOEHM_GC
-    GC_set_warn_proc(gc_warn_proc);
-    GC_enable_incremental();
-#endif
     timeq_init();
     init_structs();
     init_parse();
     timeq_init();
     init_structs();
     init_parse();
index 95feb17f3bc411bff5cbcaf7f4f810b64c0fb069..2ae4db59e59005b6c8149b079ffed66ce3aa8802 100644 (file)
@@ -145,18 +145,18 @@ static struct modcmd_flag {
     { "channel", MODCMD_REQUIRE_CHANNEL },
     { "chanuser", MODCMD_REQUIRE_CHANUSER },
     { "disabled", MODCMD_DISABLED },
     { "channel", MODCMD_REQUIRE_CHANNEL },
     { "chanuser", MODCMD_REQUIRE_CHANUSER },
     { "disabled", MODCMD_DISABLED },
+    { "helping", MODCMD_REQUIRE_HELPING },
     { "ignore_csuspend", MODCMD_IGNORE_CSUSPEND },
     { "joinable", MODCMD_REQUIRE_JOINABLE },
     { "keepbound", MODCMD_KEEP_BOUND },
     { "loghostmask", MODCMD_LOG_HOSTMASK },
     { "ignore_csuspend", MODCMD_IGNORE_CSUSPEND },
     { "joinable", MODCMD_REQUIRE_JOINABLE },
     { "keepbound", MODCMD_KEEP_BOUND },
     { "loghostmask", MODCMD_LOG_HOSTMASK },
-    { "nolog", MODCMD_NO_LOG },
     { "networkhelper", MODCMD_REQUIRE_NETWORK_HELPER },
     { "never_csuspend", MODCMD_NEVER_CSUSPEND },
     { "networkhelper", MODCMD_REQUIRE_NETWORK_HELPER },
     { "never_csuspend", MODCMD_NEVER_CSUSPEND },
+    { "nolog", MODCMD_NO_LOG },
     { "oper", MODCMD_REQUIRE_OPER },
     { "qualified", MODCMD_REQUIRE_QUALIFIED },
     { "regchan", MODCMD_REQUIRE_REGCHAN },
     { "supporthelper", MODCMD_REQUIRE_SUPPORT_HELPER },
     { "oper", MODCMD_REQUIRE_OPER },
     { "qualified", MODCMD_REQUIRE_QUALIFIED },
     { "regchan", MODCMD_REQUIRE_REGCHAN },
     { "supporthelper", MODCMD_REQUIRE_SUPPORT_HELPER },
-    { "helping", MODCMD_REQUIRE_HELPING },
     { "toy", MODCMD_TOY },
     { NULL, 0 }
 };
     { "toy", MODCMD_TOY },
     { NULL, 0 }
 };
@@ -545,7 +545,8 @@ svccmd_can_invoke(struct userNode *user, struct userNode *bot, struct svccmd *cm
         rflags |= ACTION_STAFF;
     }
     if (cmd->min_opserv_level > 0) {
         rflags |= ACTION_STAFF;
     }
     if (cmd->min_opserv_level > 0) {
-        if (!oper_has_access(user, bot, cmd->min_opserv_level, !(options & SVCCMD_NOISY))) return 0;
+        if (!oper_has_access(user, bot, cmd->min_opserv_level, !(options & SVCCMD_NOISY)))
+            return 0;
         rflags |= ACTION_STAFF;
     }
     if (cmd->req_account_flags || cmd->deny_account_flags) {
         rflags |= ACTION_STAFF;
     }
     if (cmd->req_account_flags || cmd->deny_account_flags) {
@@ -566,7 +567,7 @@ svccmd_can_invoke(struct userNode *user, struct userNode *bot, struct svccmd *cm
     /* If it's an override, return a special value. */
     if ((flags & MODCMD_REQUIRE_CHANUSER)
         && (options & SVCCMD_NOISY)
     /* If it's an override, return a special value. */
     if ((flags & MODCMD_REQUIRE_CHANUSER)
         && (options & SVCCMD_NOISY)
-        && (uData->access > 500)
+        && (!uData || (uData->access > 500))
         && (!(uData = _GetChannelUser(channel->channel_info, user->handle_info, 0, 0))
             || uData->access < cmd->min_channel_access)
         && !(flags & (MODCMD_REQUIRE_STAFF|MODCMD_REQUIRE_HELPING))) {
         && (!(uData = _GetChannelUser(channel->channel_info, user->handle_info, 0, 0))
             || uData->access < cmd->min_channel_access)
         && !(flags & (MODCMD_REQUIRE_STAFF|MODCMD_REQUIRE_HELPING))) {
@@ -1670,12 +1671,12 @@ static MODCMD_FUNC(cmd_showcommands) {
             if (flags & MODCMD_REQUIRE_HELPING)
                 access = "helping";
             else if (flags & MODCMD_REQUIRE_STAFF) {
             if (flags & MODCMD_REQUIRE_HELPING)
                 access = "helping";
             else if (flags & MODCMD_REQUIRE_STAFF) {
-                switch (flags & MODCMD_REQUIRE_STAFF) {
-                case MODCMD_REQUIRE_OPER: access = "oper"; break;
-                case MODCMD_REQUIRE_OPER | MODCMD_REQUIRE_NETWORK_HELPER:
-                case MODCMD_REQUIRE_NETWORK_HELPER: access = "net.helper"; break;
-                default: access = "staff"; break;
-                }
+                if (flags & MODCMD_REQUIRE_OPER)
+                    access = "oper";
+                else if (flags & MODCMD_REQUIRE_NETWORK_HELPER)
+                    access = "net.helper";
+                else
+                    access = "staff";
             } else
                 access = strtab(svccmd->min_channel_access);
             tbl.contents[ii+1][1+show_opserv_level] = access;
             } else
                 access = strtab(svccmd->min_channel_access);
             tbl.contents[ii+1][1+show_opserv_level] = access;
index 87845c512b9e543f9858ef95c9c06f1345e0689b..b3d19ac8032886d960cc308fb45338d08d95c8d3 100644 (file)
@@ -1896,8 +1896,7 @@ opserv_join_check(struct modeNode *mNode)
                 change.args[0].u.member = AddChannelUser(opserv, channel);
                 change.argc++;
             }
                 change.args[0].u.member = AddChannelUser(opserv, channel);
                 change.argc++;
             }
-            if (!(channel->modes & MODE_MODERATED))
-                change.modes_set |= MODE_MODERATED;
+            change.modes_set = (MODE_MODERATED | MODE_DELAYJOINS) & ~channel->modes;
             if (change.modes_set || change.argc)
                 mod_chanmode_announce(opserv, channel, &change);
             send_target_message(0, channel->name, opserv, "OSMSG_FLOOD_MODERATE");
             if (change.modes_set || change.argc)
                 mod_chanmode_announce(opserv, channel, &change);
             send_target_message(0, channel->name, opserv, "OSMSG_FLOOD_MODERATE");
index 22334026c9e412cebe6b658ef78dbcb7d942f95d..7226977f7a01cf4871212f0b99987d6d1819d096 100644 (file)
@@ -440,16 +440,17 @@ privmsg_chan_helper(struct chanNode *cn, void *data)
         mn->idle_since = now;
 
     /* Never send a NOTICE to a channel to one of the services */
         mn->idle_since = now;
 
     /* Never send a NOTICE to a channel to one of the services */
-    if (!pd->is_notice && cf->func && GetUserMode(cn, cf->service))
+    if (!pd->is_notice && cf->func
+        && ((cn->modes & MODE_REGISTERED) || GetUserMode(cn, cf->service)))
         cf->func(pd->user, cn, pd->text+1, cf->service);
 
     /* This catches *all* text sent to the channel that the services server sees */
     for (x = 0; x < ALLCHANMSG_FUNCS_MAX; x++) {
        cf = (struct chanmsg_func *)&allchanmsg_funcs[x];
        if (!cf->func)
         cf->func(pd->user, cn, pd->text+1, cf->service);
 
     /* This catches *all* text sent to the channel that the services server sees */
     for (x = 0; x < ALLCHANMSG_FUNCS_MAX; x++) {
        cf = (struct chanmsg_func *)&allchanmsg_funcs[x];
        if (!cf->func)
-         break; /* end of list */
+           break; /* end of list */
        else
        else
-       cf->func(pd->user, cn, pd->text, cf->service);
+           cf->func(pd->user, cn, pd->text, cf->service);
     }
 }
 
     }
 }
 
index f602a98a958cc99c9c6ee4b4a77ff1a7b6de2209..96d3df60122b5d635441eda741e8dc18f54cd5a8 100644 (file)
@@ -1579,6 +1579,7 @@ init_parse(void)
     dict_insert(irc_func_dict, "401", cmd_dummy); /* target left network */
     dict_insert(irc_func_dict, "403", cmd_dummy); /* no such channel */
     dict_insert(irc_func_dict, "404", cmd_dummy); /* cannot send to channel */
     dict_insert(irc_func_dict, "401", cmd_dummy); /* target left network */
     dict_insert(irc_func_dict, "403", cmd_dummy); /* no such channel */
     dict_insert(irc_func_dict, "404", cmd_dummy); /* cannot send to channel */
+    dict_insert(irc_func_dict, "439", cmd_dummy); /* target change too fast */
     dict_insert(irc_func_dict, "441", cmd_dummy); /* target isn't on that channel */
     dict_insert(irc_func_dict, "442", cmd_dummy); /* you aren't on that channel */
     dict_insert(irc_func_dict, "443", cmd_dummy); /* is already on channel (after invite?) */
     dict_insert(irc_func_dict, "441", cmd_dummy); /* target isn't on that channel */
     dict_insert(irc_func_dict, "442", cmd_dummy); /* you aren't on that channel */
     dict_insert(irc_func_dict, "443", cmd_dummy); /* is already on channel (after invite?) */
index fa446b212473853b969a1bd1fd56d7e77c4d7227..6b89f32f8d9192343c54fb24072ea5dd97145563 100644 (file)
         // How long is a channel unvisited (by masters or above) before it can be expired?
         "chan_expire_delay" "30d";
         // what !set options should we show when user calls "!set" with no arguments?
         // How long is a channel unvisited (by masters or above) before it can be expired?
         "chan_expire_delay" "30d";
         // what !set options should we show when user calls "!set" with no arguments?
-        "set_shows" ("DefaultTopic", "TopicMask", "Greeting", "UserGreeting", "Modes", "PubCmd", "InviteMe", "UserInfo", "GiveVoice", "GiveOps", "EnfOps", "EnfModes", "EnfTopic", "TopicSnarf", "Setters", "CtcpUser", "CtcpReaction", "Protect", "Toys", "DynLimit", "NoDelete");
+        "set_shows" ("DefaultTopic", "TopicMask", "Greeting", "UserGreeting", "Modes", "PubCmd", "InviteMe", "StrictOp", "AutoOp", "EnfModes", "EnfTopic", "TopicSnarf", "UserInfo", "GiveVoice", "GiveOps", "EnfOps", "Setters", "CtcpUser", "CtcpReaction", "Protect", "Toys", "DynLimit", "NoDelete");
 
         // A list of !8ball responses
         "8ball" ("Not a chance.",
 
         // A list of !8ball responses
         "8ball" ("Not a chance.",