]> jfr.im git - irc/quakenet/newserv.git/blame - lib/sstring.c
Add memory protection to debug version of (old) sstring.
[irc/quakenet/newserv.git] / lib / sstring.c
CommitLineData
c86edd1d
Q
1/* sstring.h - Declaration of "static strings" functions */
2
3#define COMPILING_SSTRING
4#include "sstring.h"
5
6#include "../core/hooks.h"
103521a1 7#include "../core/nsmalloc.h"
707c5824 8#include "../core/error.h"
c86edd1d
Q
9
10#include <stdio.h>
11
12#include <assert.h>
13#include <stdlib.h>
14#define __USE_GNU
15#include <string.h>
16
cb243158
CP
17#ifndef USE_VALGRIND
18
c86edd1d
Q
19/* List of free stuff */
20sstring *freelist[SSTRING_MAXLEN+1];
21
22/* Global variables to track allocated memory */
23sstring *structmem;
24char *stringmem;
25int structfree;
26int stringfree;
27
28/* Statistics counters */
29int getcalls;
30int freecalls;
31int allocstruct;
32int allocstring;
33
34/* Internal function */
35void sstringstats(int hooknum, void *arg);
36
37void initsstring() {
38 int i;
39 for(i=0;i<=SSTRING_MAXLEN;i++)
40 freelist[i]=NULL;
41
42 structfree=0;
43 stringfree=0;
44 structmem=NULL;
45 stringmem=NULL;
46
47 /* Initialise statistics counters */
48 getcalls=0;
49 freecalls=0;
50 allocstruct=0;
51 allocstring=0;
52
53 registerhook(HOOK_CORE_STATSREQUEST,&sstringstats);
54}
55
707c5824
CP
56void finisstring() {
57 nsfreeall(POOL_SSTRING);
58}
59
c86edd1d
Q
60sstring *getsstring(const char *inputstr, int maxlen) {
61 int i;
62 sstring *retval=NULL;
63 int length;
64
65
66 /* getsstring() on a NULL pointer returns a NULL sstring.. */
67 if (inputstr==NULL) {
68 return NULL;
69 }
70
71 if (inputstr[0]=='\0') {
72 return NULL;
73 }
74
75 /* Only count calls that actually did something */
76 getcalls++;
77
78 length=strlen(inputstr)+1;
79 if (length>maxlen) {
80 length=maxlen+1;
81 }
82 assert(length<=SSTRING_MAXLEN);
83
84 /* Check to see if an approximately correct
85 * sized string is available */
86 for(i=0;i<SSTRING_SLACK;i++) {
87 if (length+i>SSTRING_MAXLEN)
88 break;
89
90 if (freelist[length+i]!=NULL) {
91 retval=freelist[length+i];
92 freelist[length+i]=retval->u.next;
93 retval->u.l.alloc=(length+i);
94 break;
95 }
96 }
97
98 /* None found, allocate a new one */
99 if (retval==NULL) {
100getstruct:
101 if (structfree < sizeof(sstring)) {
102 /* We always allocate an exact multiple of these.
103 * Therefore, if there is enough for a partial structure we broke something */
104 assert(structfree==0);
105
106 /* Allocate more RAM */
107 allocstruct++;
103521a1 108 structmem=(sstring *)nsmalloc(POOL_SSTRING,SSTRING_STRUCTALLOC);
c86edd1d
Q
109 assert(structmem!=NULL);
110 structfree=SSTRING_STRUCTALLOC;
111 }
112
113 retval=structmem;
114 structmem++;
115 structfree-=sizeof(sstring);
116
117 if (stringfree < length) {
118 /* Not enough left for what we want.
119 * Allocate the remainder of our chunk (if any)
120 * to something and immediately free it.
121 * Decrement the freecalls counter to fix the stats */
122 if (stringfree > 0) {
123 retval->content=stringmem;
124 retval->u.l.alloc=stringfree;
125 stringfree=0;
126 freecalls--;
127 freesstring(retval);
128
129 /* GOTO GOTO GOTO: We need to allocate
130 * another new struct here. Goto is the cleanest
131 * way to do this */
132 goto getstruct;
133 } else {
134 /* Grab some more string space */
135 allocstring++;
103521a1 136 stringmem=(char *)nsmalloc(POOL_SSTRING,SSTRING_DATAALLOC);
c86edd1d
Q
137 assert(stringmem!=NULL);
138 stringfree=SSTRING_DATAALLOC;
139 }
140 }
141
142 retval->content=stringmem;
143 retval->u.l.alloc=length;
144 stringfree-=length;
145 stringmem+=length;
146 }
147
148 /*
149 * At this point, retval points to a valid structure which is at
150 * least the right size and has the "alloc" value set correctly
151 */
152
153 retval->u.l.length=(length-1);
154 strncpy(retval->content,inputstr,(length-1));
155 retval->content[length-1]='\0';
156
157 return retval;
158}
159
160void freesstring(sstring *inval) {
161 int alloc;
c86edd1d
Q
162
163 /* Allow people to call this with a NULL value */
164 if (inval==NULL)
165 return;
166
167 /* Only count calls that actually did something */
168 freecalls++;
169
170 alloc=inval->u.l.alloc;
171 assert(alloc<=SSTRING_MAXLEN);
172 inval->u.next=freelist[alloc];
173 freelist[alloc]=inval;
174}
175
176void sstringstats(int hooknum, void *arg) {
177 char buf[512];
178 int i,j;
179 sstring *ssp;
c3db6f7e 180 long statslev=(long)arg;
c86edd1d
Q
181
182 if (statslev>10) {
183 for(i=0,j=0;i<=SSTRING_MAXLEN;i++) {
184 for(ssp=freelist[i];ssp;ssp=ssp->u.next)
185 j++;
186 }
187
188 snprintf(buf,512,"SString : %7d get calls, %7d free calls, %7d struct allocs, %7d string allocs, %7d strings free",getcalls,freecalls,allocstruct,allocstring,j);
189 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
190 }
191}
192
cb243158 193#else /* USE_VALGRIND */
707c5824 194
9b92f90c
CP
195#include <sys/mman.h>
196
197#define MModify(x) mprotect(x, x->s->u.l.alloc, PROT_READ|PROT_WRITE)
198#define MUnmodify(x) mprotect(x, x->s->u.l.alloc, PROT_READ)
199
707c5824
CP
200typedef struct sstringlist {
201 struct sstringlist *prev;
202 struct sstringlist *next;
203 sstring s[];
204} sstringlist;
205
206static sstringlist *head;
207
cb243158
CP
208void initsstring() {
209}
210
707c5824
CP
211void finisstring() {
212 sstringlist *s, *sn;
213
214 /* here we deliberately don't free the pointers so valgrind can tell us where they were allocated, in theory */
215
216 for(s=head;s;s=sn) {
217 sn = s->next;
9b92f90c
CP
218
219 MModify(s);
707c5824
CP
220 s->next = NULL;
221 s->prev = NULL;
222
64cb62ac 223 Error("sstring", ERR_WARNING, "sstring of length %d still allocated: %s", s->s->u.l.length, s->s->content);
707c5824
CP
224 }
225
226 head = NULL;
227}
228
cb243158 229sstring *getsstring(const char *inputstr, int maxlen) {
707c5824 230 sstringlist *s;
732d880a
CP
231 size_t len;
232 char *p;
9b92f90c 233 void *m;
732d880a
CP
234
235 if(!inputstr)
236 return NULL;
237
238 for(p=(char *)inputstr;*p&&maxlen;maxlen--,p++)
239 ; /* empty */
707c5824 240
732d880a 241 len = p - inputstr;
9b92f90c
CP
242 m=mmap((void *)0, sizeof(sstringlist) + sizeof(sstring) + len + 1, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANON, -1, 0);
243 s=(sstringlist *)m;
244
245 if(m == MAP_FAILED)
246 s->s->u.l.length = 0;
247
732d880a 248 s->s->u.l.length = len;
9b92f90c
CP
249 s->s->u.l.alloc = sizeof(sstringlist) + sizeof(sstring) + len + 1;
250 s->s->content=(char *)m + sizeof(sstringlist) + sizeof(sstring);
cb243158 251
707c5824
CP
252 memcpy(s->s->content, inputstr, len);
253 s->s->content[len] = '\0';
cb243158 254
707c5824
CP
255 s->next = head;
256 s->prev = NULL;
9b92f90c
CP
257 if(head) {
258 MModify(head);
707c5824 259 head->prev = s;
9b92f90c
CP
260 MUnmodify(head);
261 }
707c5824 262 head = s;
cb243158 263
9b92f90c 264 MUnmodify(s);
707c5824 265 return s->s;
cb243158
CP
266}
267
268void freesstring(sstring *inval) {
0e01a25a 269 sstringlist *s;
cb243158
CP
270 if(!inval)
271 return;
272
707c5824
CP
273 s = (sstringlist *)inval - 1;
274
9b92f90c 275 MModify(s);
707c5824 276 if(s->prev) {
9b92f90c 277 MModify(s->prev);
707c5824 278 s->prev->next = s->next;
9b92f90c
CP
279 MUnmodify(s->prev);
280 if(s->next) {
281 MModify(s->next);
707c5824 282 s->next->prev = s->prev;
9b92f90c
CP
283 MUnmodify(s->prev);
284 }
707c5824
CP
285 } else {
286 head = s->next;
9b92f90c
CP
287 if(head) {
288 MModify(head);
707c5824 289 head->prev = NULL;
9b92f90c
CP
290 MUnmodify(head);
291 }
707c5824
CP
292 }
293
9b92f90c 294 munmap(s, s->s->u.l.alloc);
cb243158
CP
295}
296#endif
297
c86edd1d
Q
298int sstringcompare(sstring *ss1, sstring *ss2) {
299 if (ss1->u.l.length != ss2->u.l.length)
300 return -1;
301
302 return strncmp(ss1->content, ss2->content, ss1->u.l.length);
303}
cb243158 304