/* sstring.h - Declaration of "static strings" functions */
#define COMPILING_SSTRING
+#define SSTRING_NEW
#include "sstring.h"
#include "../core/hooks.h"
static int freecalls;
static int allocs;
-/* Internal function */
+/* Internal functions */
static void sstringstats(int hooknum, void *arg);
+static void salloc(void);
+
+#ifndef SSTRING_MMAP
+
+#define sunprotect(x)
+#define sunprotectb(x)
+#define sprotect(x)
+
+#else
+
+#define __USE_MISC
+
+#include <sys/mman.h>
+static void *mblock;
+struct mblock_list {
+ void *block;
+ struct mblock_list *next;
+};
+
+static void *mblock_head;
+
+#define sunprotectb(x) mprotect(x, SSTRING_ALLOC, PROT_READ|PROT_WRITE);
+#define sunprotect(x) sunprotectb((x)->block);
+#define sprotect(x) mprotect((x)->block, SSTRING_ALLOC, PROT_READ);
+
+#ifndef MAP_ANON
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+
+#endif /* SSTRING_MMAP */
void initsstring() {
int i;
registerhook(HOOK_CORE_STATSREQUEST,&sstringstats);
}
+#ifndef SSTRING_MMAP
void finisstring() {
nsfreeall(POOL_SSTRING);
}
+static void salloc(void) {
+ ssmem=(char *)nsmalloc(POOL_SSTRING, SSTRING_ALLOC);
+ ssmemfree=SSTRING_ALLOC;
+}
+#endif /* SSTRING_MMAP */
+
sstring *findsstring(const char *str) {
unsigned int hash=crc32(str)%SSTRING_HASHSIZE;
sstring *ss;
for (ss=sshash[hash];ss;ss=ss->next)
- if (!strcmp(str, ss->content))
+ if (!strcmp(str, sstring_content(ss)))
return ss;
return NULL;
}
void sstring_enhash(sstring *ss) {
- unsigned int hash=crc32(ss->content)%SSTRING_HASHSIZE;
+ unsigned int hash=crc32(sstring_content(ss))%SSTRING_HASHSIZE;
ss->next=sshash[hash];
sshash[hash]=ss;
}
void sstring_dehash(sstring *ss) {
- unsigned int hash=crc32(ss->content)%SSTRING_HASHSIZE;
- sstring **ssh;
+ unsigned int hash=crc32(sstring_content(ss))%SSTRING_HASHSIZE;
+ sstring *ssh, *ssp;
- for (ssh=&(sshash[hash]); *ssh; ssh=&((*ssh)->next)) {
- if (*ssh==ss) {
- *ssh=ss->next;
+ for (ssh=sshash[hash],ssp=NULL; ssh; ssp=ssh,ssh=ssh->next) {
+ if (ssh==ss) {
+ if (!ssp) {
+ sshash[hash]=ss->next;
+ } else {
+#ifndef SSTRING_MMAP
+ ssp->next=ss->next;
+#else
+ if (ssp->block!=ss->block) {
+ sunprotect(ssp) {
+ ssp->next=ss->next;
+ } sprotect(ssp);
+ } else {
+ ssp->next=ss->next;
+ }
+#endif
+ }
return;
}
}
- Error("sstring",ERR_WARNING,"sstring_dehash(): Unable to find string (ref=%d, length=%d) in hash: %s",ss->refcount,ss->length,ss->content);
+ Error("sstring",ERR_WARNING,"sstring_dehash(): Unable to find string (ref=%lu, length=%d) in hash: %s",ss->refcount,ss->length,sstring_content(ss));
}
sstring *getsstring(const char *inputstr, int maxlen) {
int i;
sstring *retval=NULL;
- int length;
+ int length, foreignblock;
char strbuf[SSTRING_MAXLEN];
/* getsstring() on a NULL pointer returns a NULL sstring.. */
/* If it's hashed this is easy */
if ((retval=findsstring(strbuf))) {
- retval->refcount++;
+ sunprotect(retval) {
+ retval->refcount++;
+ } sprotect(retval);
+
return retval;
}
-
+
+ foreignblock=0;
/* Check to see if an approximately correct
* sized string is available */
for(i=0;i<SSTRING_SLACK;i++) {
if (freelist[length+i]!=NULL) {
retval=freelist[length+i];
freelist[length+i]=retval->next;
+ sunprotect(retval);
+ foreignblock=1;
+
retval->alloc=(length+i);
break;
}
/* Not enough for us - turn the remaining memory into a free string for later */
if (ssmemfree>sizeof(sstring)) {
retval=(sstring *)ssmem;
+ sunprotectb(mblock);
+#ifdef SSTRING_MMAP
+ retval->block=mblock;
+#endif
retval->alloc=(ssmemfree-sizeof(sstring));
retval->refcount=0;
freesstring(retval);
}
- allocs++;
- ssmem=(char *)nsmalloc(POOL_SSTRING, SSTRING_ALLOC);
- ssmemfree=SSTRING_ALLOC;
+ allocs++;
+ salloc();
+ } else {
+ sunprotectb(mblock);
}
retval=(sstring *)ssmem;
*/
retval->length=(length-1);
- strcpy(retval->content,strbuf);
+ strcpy(sstring_content(retval),strbuf);
retval->refcount=1;
-
+
+#ifdef SSTRING_MMAP
+ if(!foreignblock)
+ retval->block = mblock;
+#endif
+
sstring_enhash(retval);
-
+
+#ifdef SSTRING_COMPAT
+ retval->content = retval->__content;
+#endif
+
+ sprotect(retval);
+
return retval;
}
/* Only count calls that actually did something */
freecalls++;
+ if (inval->refcount)
+ sunprotect(inval);
+
if (inval->refcount > 1) {
inval->refcount--;
+ sprotect(inval);
return;
}
- /* If refcount==0 it wasn't hashed */
+ /* If refcount==0 it wasn't hashed, or protected */
if (inval->refcount)
sstring_dehash(inval);
-
+
alloc=inval->alloc;
assert(alloc<=SSTRING_MAXLEN);
inval->next=freelist[alloc];
freelist[alloc]=inval;
+ sprotect(inval);
}
void sstringstats(int hooknum, void *arg) {
}
}
-int sstringcompare(sstring *ss1, sstring *ss2) {
- if (ss1->length != ss2->length)
- return -1;
-
- return strncmp(ss1->content, ss2->content, ss1->length);
+#ifdef SSTRING_MMAP
+void finisstring() {
+ struct mblock_list *c, *n;
+ for (c=mblock_head;c;c=n) {
+ n=c->next;
+ munmap(c->block, SSTRING_ALLOC);
+ }
}
+static void salloc(void) {
+ struct mblock_list *n;
+ mblock=mmap((void *)0, SSTRING_ALLOC, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANON, -1, 0);
+
+ n=(struct mblock_list *)mblock;
+ n->block = mblock;
+ n->next = mblock_head;
+ mblock_head = n;
+
+ ssmem=(char *)mblock + sizeof(struct mblock_list);
+ ssmemfree=SSTRING_ALLOC-sizeof(struct mblock_list);
+}
+#endif /* SSTRING_MMAP */