Browse code

Try to reclaim some memory if it becomes low when decoding

git-svn: trunk@998

Nigel Horne authored on 2004/10/15 02:45:55
Showing 4 changed files
... ...
@@ -16,6 +16,9 @@
16 16
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 17
  *
18 18
  * $Log: line.c,v $
19
+ * Revision 1.6  2004/10/14 17:45:55  nigelhorne
20
+ * Try to reclaim some memory if it becomes low when decoding
21
+ *
19 22
  * Revision 1.5  2004/09/30 08:58:56  nigelhorne
20 23
  * Remove empty lines
21 24
  *
... ...
@@ -33,7 +36,7 @@
33 33
  *
34 34
  */
35 35
 
36
-static	char	const	rcsid[] = "$Id: line.c,v 1.5 2004/09/30 08:58:56 nigelhorne Exp $";
36
+static	char	const	rcsid[] = "$Id: line.c,v 1.6 2004/10/14 17:45:55 nigelhorne Exp $";
37 37
 
38 38
 #if HAVE_CONFIG_H
39 39
 #include "clamav-config.h"
... ...
@@ -142,4 +145,10 @@ lineGetData(const line_t *line)
142 142
 {
143 143
 	return line ? &line[1] : NULL;
144 144
 }
145
+
146
+unsigned char
147
+lineGetRefCount(const line_t *line)
148
+{
149
+	return line[0];
150
+}
145 151
 #endif
... ...
@@ -16,6 +16,9 @@
16 16
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 17
  *
18 18
  * $Log: line.h,v $
19
+ * Revision 1.4  2004/10/14 17:45:55  nigelhorne
20
+ * Try to reclaim some memory if it becomes low when decoding
21
+ *
19 22
  * Revision 1.3  2004/08/21 11:57:57  nigelhorne
20 23
  * Use line.[ch]
21 24
  *
... ...
@@ -45,5 +48,6 @@ line_t	*lineCreate(const char *data);
45 45
 line_t	*lineLink(line_t *line);
46 46
 line_t	*lineUnlink(line_t *line);
47 47
 const	char	*lineGetData(const line_t *line);
48
+unsigned	char	lineGetRefCount(const line_t *line);
48 49
 
49 50
 #endif
... ...
@@ -17,6 +17,9 @@
17 17
  *
18 18
  * Change History:
19 19
  * $Log: message.c,v $
20
+ * Revision 1.100  2004/10/14 17:45:55  nigelhorne
21
+ * Try to reclaim some memory if it becomes low when decoding
22
+ *
20 23
  * Revision 1.99  2004/10/12 10:40:48  nigelhorne
21 24
  * Remove shadow declaration of isblank
22 25
  *
... ...
@@ -294,7 +297,7 @@
294 294
  * uuencodebegin() no longer static
295 295
  *
296 296
  */
297
-static	char	const	rcsid[] = "$Id: message.c,v 1.99 2004/10/12 10:40:48 nigelhorne Exp $";
297
+static	char	const	rcsid[] = "$Id: message.c,v 1.100 2004/10/14 17:45:55 nigelhorne Exp $";
298 298
 
299 299
 #if HAVE_CONFIG_H
300 300
 #include "clamav-config.h"
... ...
@@ -355,6 +358,7 @@ static	unsigned	char	uudecode(char c);
355 355
 static	const	char	*messageGetArgument(const message *m, int arg);
356 356
 static	void	*messageExport(message *m, const char *dir, void *(*create)(void), void (*destroy)(void *), void (*setFilename)(void *, const char *, const char *), void (*addData)(void *, const unsigned char *, size_t), void *(*exportText)(const text *, void *));
357 357
 static	int	usefulArg(const char *arg);
358
+static	void	messageDedup(message *m);
358 359
 
359 360
 /*
360 361
  * These maps are ordered in decreasing likelyhood of their appearance
... ...
@@ -1035,14 +1039,26 @@ messageAddStr(message *m, const char *data)
1035 1035
 	if(m->body_first == NULL)
1036 1036
 		m->body_last = m->body_first = (text *)cli_malloc(sizeof(text));
1037 1037
 	else {
1038
+		assert(m->body_last != NULL);
1038 1039
 		m->body_last->t_next = (text *)cli_malloc(sizeof(text));
1040
+		if(m->body_last->t_next == NULL) {
1041
+			messageDedup(m);
1042
+			m->body_last->t_next = (text *)cli_malloc(sizeof(text));
1043
+			if(m->body_last->t_next == NULL) {
1044
+				cli_errmsg("messageAddStr: out of memory\n");
1045
+				return -1;
1046
+			}
1047
+		}
1048
+
1039 1049
 		if(data && m->body_last->t_line && (strcmp(data, lineGetData(m->body_last->t_line)) == 0))
1040 1050
 			repeat = m->body_last->t_line;
1041 1051
 		m->body_last = m->body_last->t_next;
1042 1052
 	}
1043 1053
 
1044
-	if(m->body_last == NULL)
1054
+	if(m->body_last == NULL) {
1055
+		cli_errmsg("messageAddStr: out of memory\n");
1045 1056
 		return -1;
1057
+	}
1046 1058
 
1047 1059
 	m->body_last->t_next = NULL;
1048 1060
 
... ...
@@ -1052,15 +1068,14 @@ messageAddStr(message *m, const char *data)
1052 1052
 		else
1053 1053
 			m->body_last->t_line = lineCreate(data);
1054 1054
 
1055
-		if(m->body_last->t_line == NULL) {
1056
-			/*
1057
-			 * TODO: Here we could go through all the message
1058
-			 * looking for duplicate lines we can line. It'd be
1059
-			 * very slow, but it could save enough memory to
1060
-			 * continue...
1061
-			 */
1062
-			cli_errmsg("messageAddStr: out of memory\n");
1063
-			return -1;
1055
+		if((m->body_last->t_line == NULL) && (repeat == NULL)) {
1056
+			messageDedup(m);
1057
+			m->body_last->t_line = lineCreate(data);
1058
+
1059
+			if(m->body_last->t_line == NULL) {
1060
+				cli_errmsg("messageAddStr: out of memory\n");
1061
+				return -1;
1062
+			}
1064 1063
 		}
1065 1064
 		/* cli_chomp(m->body_last->t_text); */
1066 1065
 
... ...
@@ -1638,7 +1653,7 @@ fileblob *
1638 1638
 messageToFileblob(message *m, const char *dir)
1639 1639
 {
1640 1640
 	cli_dbgmsg("messageToFileblob\n");
1641
-	return messageExport(m, dir, fileblobCreate, fileblobDestroy, fileblobSetFilename, fileblobAddData, textToFileblob);
1641
+	return messageExport(m, dir, (void *)fileblobCreate, (void *)fileblobDestroy, (void *)fileblobSetFilename, (void *)fileblobAddData, (void *)textToFileblob);
1642 1642
 }
1643 1643
 
1644 1644
 /*
... ...
@@ -1648,7 +1663,7 @@ messageToFileblob(message *m, const char *dir)
1648 1648
 blob *
1649 1649
 messageToBlob(message *m)
1650 1650
 {
1651
-	return messageExport(m, NULL, blobCreate, blobDestroy, blobSetFilename, blobAddData, textToBlob);
1651
+	return messageExport(m, NULL, (void *)blobCreate, (void *)blobDestroy, (void *)blobSetFilename, (void *)blobAddData, (void *)textToBlob);
1652 1652
 }
1653 1653
 
1654 1654
 /*
... ...
@@ -2351,3 +2366,72 @@ usefulArg(const char *arg)
2351 2351
 	}
2352 2352
 	return 1;
2353 2353
 }
2354
+
2355
+/*
2356
+ * We've run out of memory. Try to recover some by
2357
+ * deduping the message
2358
+ */
2359
+static void
2360
+messageDedup(message *m)
2361
+{
2362
+	const text *t1;
2363
+	size_t saved = 0;
2364
+
2365
+	t1 = m->dedupedThisFar ? m->dedupedThisFar : m->body_first;
2366
+
2367
+	for(t1 = m->body_first; t1; t1 = t1->t_next) {
2368
+		const char *d1;
2369
+		text *t2;
2370
+		line_t *l1;
2371
+		unsigned int r1;
2372
+
2373
+		if(saved >= 100*1000)
2374
+			break;	/* that's enough */
2375
+		l1 = t1->t_line;
2376
+		if(l1 == NULL)
2377
+			continue;
2378
+		d1 = lineGetData(l1);
2379
+		if(strlen(d1) < 8)
2380
+			continue;	/* wouldn't recover many bytes */
2381
+		r1 = (unsigned int)lineGetRefCount(l1);
2382
+		if(r1 == 255)
2383
+			continue;
2384
+		/*
2385
+		 * We don't want to foul up any pointers
2386
+		 */
2387
+		if(t1 == m->encoding)
2388
+			continue;
2389
+		if(t1 == m->bounce)
2390
+			continue;
2391
+		if(t1 == m->uuencode)
2392
+			continue;
2393
+		if(t1 == m->binhex)
2394
+			continue;
2395
+		if(t1 == m->yenc)
2396
+			continue;
2397
+
2398
+		for(t2 = t1->t_next; t2; t2 = t2->t_next) {
2399
+			const char *d2;
2400
+			line_t *l2 = t2->t_line;
2401
+
2402
+			if(l2 == NULL)
2403
+				continue;
2404
+			if((r1 + (unsigned int)lineGetRefCount(l2)) > 255)
2405
+				continue;
2406
+			d2 = lineGetData(l2);
2407
+			if(d1 == d2)
2408
+				/* already linked */
2409
+				continue;
2410
+			if(strcmp(d1, d2) == 0) {
2411
+				if(lineUnlink(l2) == NULL)
2412
+					saved += strlen(d1);
2413
+				t2->t_line = lineLink(l1);
2414
+				if(t2->t_line == NULL) {
2415
+					cli_errmsg("messageDedup: out of memory\n");
2416
+					return;
2417
+				}
2418
+			}
2419
+		}
2420
+	}
2421
+	m->dedupedThisFar = t1;
2422
+}
... ...
@@ -16,6 +16,9 @@
16 16
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 17
  *
18 18
  * $Log: message.h,v $
19
+ * Revision 1.20  2004/10/14 17:45:55  nigelhorne
20
+ * Try to reclaim some memory if it becomes low when decoding
21
+ *
19 22
  * Revision 1.19  2004/09/17 13:47:19  nigelhorne
20 23
  * Handle yEnc attachments
21 24
  *
... ...
@@ -90,6 +93,7 @@ typedef struct message {
90 90
 	text	*uuencode;	/* start of a uuencoded message */
91 91
 	text	*yenc;		/* start of a yEnc message */
92 92
 	text	*encoding;	/* is the non MIME message encoded? */
93
+	text	*dedupedThisFar;
93 94
 } message;
94 95
 
95 96
 message	*messageCreate(void);