Browse code

clamd/thrmgr.c: fix valgrind warning (bb #1184) unit_tests: add more valgrind tests, add a reload and a multiscan test (bb #1092)

git-svn: trunk@4175

Török Edvin authored on 2008/09/14 23:15:39
Showing 7 changed files
... ...
@@ -1,3 +1,8 @@
1
+Sun Sep 14 17:20:14 EEST 2008 (edwin)
2
+-------------------------------------
3
+  * clamd/thrmgr.c: fix valgrind warning (bb #1184)
4
+  * unit_tests: add more valgrind tests, add a reload and a multiscan test (bb #1092)
5
+
1 6
 Thu Sep 11 21:46:48 CEST 2008 (tk)
2 7
 ----------------------------------
3 8
   * libclamav/pdf.c: fix write error with specific files (bb#1181)
... ...
@@ -101,13 +101,20 @@ static void *work_queue_pop(work_queue_t *work_q)
101 101
 
102 102
 void thrmgr_destroy(threadpool_t *threadpool)
103 103
 {
104
-	if (!threadpool || (threadpool->state != POOL_VALID)) {
104
+	if (!threadpool) {
105 105
 		return;
106 106
 	}
107 107
   	if (pthread_mutex_lock(&threadpool->pool_mutex) != 0) {
108 108
    		logg("!Mutex lock failed\n");
109 109
     		exit(-1);
110 110
 	}
111
+	if(threadpool->state != POOL_VALID) {
112
+		if (pthread_mutex_unlock(&threadpool->pool_mutex) != 0) {
113
+			logg("!Mutex unlock failed\n");
114
+			exit(-1);
115
+		}
116
+		return;
117
+	}
111 118
 	threadpool->state = POOL_EXIT;
112 119
 	
113 120
 	/* wait for threads to exit */
... ...
@@ -26,7 +26,7 @@ check_clamscan.sh: $(top_builddir)/test/clam.exe
26 26
 $(top_builddir)/test/clam.exe:
27 27
 	(cd $(top_builddir)/test && $(MAKE))
28 28
 
29
-CLEANFILES=lcov.out *.gcno *.gcda *.log clamd-test.socket /tmp/clamd-test.log $(FILES) test-stderr.log clamscan.log valgrind.log clamdscan.log
29
+CLEANFILES=lcov.out *.gcno *.gcda *.log clamd-test.socket /tmp/clamd-test.log $(FILES) test-stderr.log clamscan.log valgrind-*.log clamdscan.log clamdscan-multiscan.log
30 30
 EXTRA_DIST=.split input test-clamd.conf test-freshclam.conf valgrind.supp virusaction-test.sh $(scripts)
31 31
 if ENABLE_COVERAGE
32 32
 LCOV_OUTPUT = lcov.out
... ...
@@ -1,18 +1,15 @@
1
-#!/bin/sh 
2
-#set -x
1
+#!/bin/sh  
2
+CLAMD_WRAPPER=${CLAMD_WRAPPER-}
3 3
 killclamd() {
4 4
 	test -f /tmp/clamd-test.pid || return
5 5
 	pid=`cat /tmp/clamd-test.pid`
6 6
 	kill -0 $pid && kill $pid
7
-	pippo=0
8
-	while test -f /tmp/clamd-test.pid; do
9
-		sleep 1
10
-		pippo=`expr $pippo + 1`
11
-		if test $pippo -gt 9; then
12
-			kill -KILL $pid
13
-			rm /tmp/clamd-test.pid
14
-		fi
15
-	done
7
+	timeout=10
8
+	(sleep $timeout; kill -KILL $pid) &
9
+	sleeperpid=$!
10
+	wait $pid
11
+	kill -ALRM $sleeperpid 2>/dev/null
12
+	rm -f /tmp/clamd-test.pid
16 13
 }
17 14
 die() {
18 15
 	killclamd
... ...
@@ -22,10 +19,14 @@ die() {
22 22
 run_clamd_test() {
23 23
 	conf_file=$1
24 24
 	shift
25
-	rm -f clamdscan.log
26
-	../clamd/clamd -c $conf_file || { echo "Failed to start clamd!" >&2; die 1;}
25
+	rm -f clamdscan.log clamdscan-multiscan.log
26
+	../libtool --mode=execute $CLAMD_WRAPPER ../clamd/clamd -c $conf_file || { echo "Failed to start clamd!" >&2; die 1;}
27 27
 	../clamdscan/clamdscan --version --config-file $conf_file 2>&1|grep "^ClamAV" >/dev/null || { echo "clamdscan can't get version of clamd!" >&2; die 2;}
28 28
 	../clamdscan/clamdscan --quiet --config-file $conf_file $* --log=clamdscan.log
29
+	../clamdscan/clamdscan --quiet --config-file $conf_file $* -m --log=clamdscan-multiscan.log
30
+	if test -x /bin/nc; then
31
+		echo RELOAD | nc -q 0 -n 127.0.0.1 3311
32
+	fi
29 33
 	if test $? = 2; then 
30 34
 		echo "Failed to run clamdscan!" >&2;
31 35
 		die 3;	
... ...
@@ -37,7 +38,7 @@ run_clamd_fdpass_test() {
37 37
 	conf_file=$1
38 38
 	shift
39 39
 	rm -f clamdscan.log
40
-	../clamd/clamd -c $conf_file || { echo "Failed to start clamd!" >&2; die 1;}
40
+	../libtool --mode=execute $CLAMD_WRAPPER ../clamd/clamd -c $conf_file || { echo "Failed to start clamd!" >&2; die 1;}
41 41
 	../clamdscan/clamdscan --quiet --fdpass --config-file $conf_file - <$1 --log=clamdscan.log
42 42
 	if test $? = 2; then
43 43
 		echo "Failed to run clamdscan!" >&2;
... ...
@@ -58,11 +59,17 @@ FILES=../test/clam*
58 58
 run_clamd_test $srcdir/test-clamd.conf $FILES
59 59
 NFILES=`ls -1 $FILES | wc -l`
60 60
 NINFECTED=`grep "Infected files" clamdscan.log | cut -f2 -d:|sed -e 's/ //g'`
61
+NINFECTED_MULTI=`grep "Infected files" clamdscan-multiscan.log | cut -f2 -d:|sed -e 's/ //g'`
61 62
 if test "$NFILES" -ne "0$NINFECTED"; then
62 63
 	echo "clamd did not detect all testfiles correctly!" >&2;
63 64
 	grep OK clamdscan.log >&2;
64 65
 	die 4;
65 66
 fi
67
+if test "$NFILES" -ne "0$NINFECTED_MULTI"; then
68
+	echo "clamd did not detect all testfiles correctly in multiscan mode!" >&2;
69
+	grep OK clamdscan-multiscan.log >&2;
70
+	die 4;
71
+fi
66 72
 
67 73
 # Test VirusEvent feature
68 74
 cat <$srcdir/test-clamd.conf >test-clamd-viraction.conf
... ...
@@ -6,6 +6,8 @@ PidFile /tmp/clamd-test.pid
6 6
 DatabaseDirectory test-db
7 7
 LocalSocket clamd-test.socket
8 8
 TCPAddr 127.0.0.1
9
+# using different port here to avoid conflicts with system clamd daemon
10
+TCPSocket 3311
9 11
 ExitOnOOM yes
10 12
 DetectPUA yes
11 13
 ScanPDF yes
... ...
@@ -12,3 +12,114 @@
12 12
 	obj:/lib*/libc-*.so
13 13
 	fun:__libc_freeres
14 14
 }
15
+{
16
+	helgrind-glibc27-dbg01
17
+	Helgrind:Race
18
+	fun:mythread_wrapper
19
+	fun:start_thread
20
+}
21
+{
22
+	helgrind-glibc27-dbg02
23
+	Helgrind:Race
24
+	fun:pthread_mutex_*
25
+}
26
+{
27
+	helgrind-glibc27-dbg03
28
+	Helgrind:Race
29
+	fun:pthread_create*
30
+}
31
+{
32
+	helgrind-glibc27-dbg04
33
+	Helgrind:Race
34
+	fun:pthread_create*
35
+}
36
+{
37
+	helgrind-glibc27-dbg05
38
+	Helgrind:Race
39
+	fun:__deallocate_stack
40
+	fun:start_thread
41
+}
42
+{
43
+	helgrind-glibc27-dbg05
44
+	Helgrind:Race
45
+	fun:free_stacks
46
+	fun:__deallocate_stack
47
+	fun:start_thread
48
+}
49
+{
50
+	helgrind-glibc27-dbg06
51
+	Helgrind:Race
52
+	fun:*
53
+	obj:/usr/lib/debug/libpthread-*.so
54
+}
55
+{
56
+	helgrind-glibc27-dbg06
57
+	Helgrind:Race
58
+	fun:*
59
+	obj:/lib/libpthread-*.so
60
+}
61
+{
62
+	helgrind-glibc27-dbg08
63
+	Helgrind:Race
64
+	obj:/lib/ld-*.so
65
+}
66
+{
67
+	helgrind-glibc27-dbg09
68
+	Helgrind:Race
69
+	fun:*
70
+	fun:exit
71
+}
72
+{
73
+	helgrind-glibc27-dbg10
74
+	Helgrind:Race
75
+	fun:*
76
+	fun:*
77
+	fun:exit
78
+}
79
+{
80
+	helgrind-glibc27-dbg11
81
+	Helgrind:Race
82
+	fun:*
83
+	fun:*
84
+	fun:*
85
+	fun:exit
86
+}
87
+{
88
+	helgrind-glibc27-dbg12
89
+	Helgrind:Race
90
+	fun:*
91
+	fun:*
92
+	fun:*
93
+	fun:*
94
+	fun:exit
95
+}
96
+{
97
+	helgrind-glibc27-dbg13
98
+	Helgrind:Race
99
+	fun:*
100
+	fun:*
101
+	fun:ctime_r
102
+}
103
+{
104
+	helgrind-glibc27-dbg14
105
+	Helgrind:Race
106
+	fun:_IO_link_in
107
+	fun:_IO_file_init*
108
+}
109
+# libc has a gconv_lock, but valgrind doesn't know that because it uses lll_lock
110
+# instead of pthread_mutex_lock
111
+{
112
+	helgrind-glibc27-dbg15
113
+	Helgrind:Race
114
+	fun:__gconv_release_shlib
115
+}
116
+{
117
+	helgrind-glibc27-dbg16
118
+	Helgrind:Race
119
+	fun:__gconv_find_shlib
120
+}
121
+{
122
+	helgrind-glibc27-dbg17
123
+	Helgrind:Race
124
+	fun:exit
125
+}
... ...
@@ -1,28 +1,79 @@
1 1
 #!/bin/sh
2
+# 
3
+# We don't look for 'still reachable' blocks, since clamd fork()s after loading
4
+# the DB. The parent exits without freeing the memory (but they are freed
5
+# anyway due to the exit).
6
+# To test for DB load leaks, we issue a RELOAD command, which should cause
7
+# leaks to be reported by valgrind if there are any.
8
+# 
9
+
2 10
 VALGRIND=`which ${VALGRIND-valgrind}`
3
-VALGRIND_FLAGS="--trace-children=yes --track-fds=yes --leak-check=full --show-reachable=yes --suppressions=$srcdir/valgrind.supp"
4 11
 test -n "$VALGRIND" || { echo "*** valgrind not found, skipping test"; exit 77; }
5 12
 test -x "$VALGRIND" || { echo "*** valgrind not executable, skipping test"; exit 77; }
6 13
 
7
-echo "Running valgrind"
8
-CK_FORK=no ../libtool --mode=execute $VALGRIND $VALGRIND_FLAGS ./check_clamav 2>&1 | cat >valgrind.log
9
-if grep "ERROR SUMMARY: 0 errors" valgrind.log >/dev/null; then
10
-	if grep "no leaks are possible" valgrind.log >/dev/null; then
11
-		echo "Valgrind tests successful"
12
-		exit 0;
14
+parse_valgrindlog()
15
+{
16
+	if test ! -f $1; then
17
+		echo "Logfile $1 not found. Valgrind failed to run?"
18
+		exit 2;
19
+	fi
20
+	NRUNS=`grep "ERROR SUMMARY" $1 | wc -l`
21
+	if test $NRUNS -eq `grep "ERROR SUMMARY: 0 errors" $1 | wc -l`; then
22
+		if test "$1" = "valgrind-race.log" || 
23
+			test $NRUNS -eq `grep "no leaks are possible" $1 | wc -l` ||
24
+			test `grep "lost:" $1 | grep -v "0 bytes" | wc -l` -ne 0; then 
25
+			rm -f $1;
26
+			return
27
+		else
28
+			echo "*** Valgrind test FAILED, memory LEAKS detected ***"
29
+			grep "lost:" $1 | grep -v "0 bytes"
30
+		fi
31
+	else
32
+		if test "$1" = "valgrind-race.log" ; then
33
+			echo "*** Valgrind test FAILED, DATA RACES detected ****"
34
+		else
35
+			echo "*** Valgrind test FAILED, memory ERRORS detected ****"
36
+		fi
37
+		grep "ERROR SUMMARY" $1 | grep -v "0 errors"
38
+		sed -rn '
39
+			/^[=0-9]+ +at/ {
40
+				# save current line in hold buffer
41
+				x
42
+				# print hold buffer
43
+				p
44
+				# get original line back
45
+				x
46
+			}
47
+			# store it in hold buffer
48
+			h
49
+			/^[=0-9]+ FILE DESC/ {
50
+				q
51
+			}
52
+		' <$1 | grep -v "Thread.+was created"
13 53
 	fi
14
-	echo "*** Valgrind test FAILED, memory LEAKS detected ***"
15
-else
16
-	echo "*** Valgrind test FAILED, memory ERRORS detected ****"
54
+	echo "***"
55
+	echo "*** Please submit $1 to http://bugs.clamav.net"
56
+	echo "***"
57
+}
58
+
59
+
60
+VALGRIND_FLAGS="-v --trace-children=yes --track-fds=yes --leak-check=full --suppressions=$srcdir/valgrind.supp"
61
+VALGRIND_FLAGS_RACE="-v --tool=helgrind --trace-children=yes --suppressions=$srcdir/valgrind.supp"
62
+
63
+echo "--- Running valgrind/memcheck"
64
+rm -f valgrind-check.log valgrind-clamd.log valgrind-race.log
65
+CK_FORK=no ../libtool --mode=execute $VALGRIND $VALGRIND_FLAGS ./check_clamav >valgrind-check.log 2>&1
66
+parse_valgrindlog valgrind-check.log
67
+
68
+echo "--- Running clamd under valgrind/memcheck"
69
+CLAMD_WRAPPER="$VALGRIND $VALGRIND_FLAGS" $srcdir/check_clamd.sh >valgrind-clamd.log 2>&1
70
+parse_valgrindlog valgrind-clamd.log
71
+
72
+echo "--- Running clamd under valgrind/helgrind"
73
+CLAMD_WRAPPER="$VALGRIND $VALGRIND_FLAGS_RACE" $srcdir/check_clamd.sh >valgrind-race.log 2>&1
74
+parse_valgrindlog valgrind-race.log
75
+
76
+if test -f valgrind-check.log -o -f valgrind-race.log -o -f valgrind-clamd.log; then
77
+	exit 1;
17 78
 fi
18
-echo 
19
-grep "ERROR SUMMARY" valgrind.log
20
-echo `grep "Invalid read" valgrind.log| wc -l` "invalid reads"
21
-echo `grep "Invalid write" valgrind.log| wc -l` "invalid writes"
22
-echo `grep "Invalid free" valgrind.log| wc -l` "invalid frees"
23
-echo `grep "uninitialised value" valgrind.log|wc -l` "uses of uninitialized values"
24
-grep " lost:" valgrind.log
25
-grep "still reachable:" valgrind.log
26
-grep "FILE DESCRIPTORS" valgrind.log
27
-echo 
28
-exit 1;
79
+exit 0