From: Radosław Korzeniewski Date: Mon, 27 Aug 2018 15:17:59 +0000 (+0200) Subject: Update unittests for lockmgr.c and fix memory leak. X-Git-Tag: Release-9.4.0~72 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3d42f5b884bb378ca599fb3fe58a14bc06f07492;p=thirdparty%2Fbacula.git Update unittests for lockmgr.c and fix memory leak. --- diff --git a/.gitignore b/.gitignore index 0deaae06d9..480e26a2af 100644 --- a/.gitignore +++ b/.gitignore @@ -325,3 +325,4 @@ bacula/src/lib/fnmatch_test bacula/src/lib/sha1_test bacula/src/lib/htable_test bacula/src/lib/ini_test +bacula/src/lib/lockmgr_test diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index c62f335100..83d91ec409 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -132,10 +132,10 @@ output_test: Makefile output.c unittests.o $(RMF) output.o $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) output.c -lockmgr_test: Makefile lockmgr.c +lockmgr_test: Makefile libbac.la lockmgr.c unittests.o $(RMF) lockmgr.o - $(CXX) -D _TEST_IT $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) lockmgr.c - $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -L. -o $@ lockmgr.o $(DLIB) -lbac -lm $(LIBS) $(OPENSSL_LIBS) + $(CXX) -DTEST_PROGRAM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) lockmgr.c + $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -L. -o $@ lockmgr.o unittests.o $(DLIB) -lbac -lm $(LIBS) $(OPENSSL_LIBS) $(RMF) lockmgr.o $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) lockmgr.c diff --git a/bacula/src/lib/lockmgr.c b/bacula/src/lib/lockmgr.c index d53aec863e..53f466af82 100644 --- a/bacula/src/lib/lockmgr.c +++ b/bacula/src/lib/lockmgr.c @@ -11,7 +11,7 @@ Public License, v3.0 ("AGPLv3") and some additional permissions and terms pursuant to its AGPLv3 Section 7. - This notice must be preserved when any source code is + This notice must be preserved when any source code is conveyed and/or propagated. Bacula(R) is a registered trademark of Kern Sibbald. @@ -66,6 +66,17 @@ Pmsg4(000, _("ASSERT failed at %s:%i: %s (%s)\n"), f, l, #x, m); \ jcr[0] = 0; } +/* for lockmgr unit tests we have to clean up developer flags and asserts which breaks our tests */ +#ifdef TEST_PROGRAM +#ifdef DEVELOPER +#undef DEVELOPER +#endif +#ifdef ASSERTD +#undef ASSERTD +#define ASSERTD(x, y) +#endif +#endif + /* Inspired from http://www.cs.berkeley.edu/~kamil/teaching/sp03/041403.pdf @@ -77,8 +88,8 @@ rwlock object or the smartalloc lib. To disable LMGR, just add LOCKMGR_COMPLIANT before the inclusion of "bacula.h" - cd build/src/tools - g++ -g -c lockmgr.c -I.. -I../lib -DUSE_LOCKMGR -D_TEST_IT + cd build/src/lib + g++ -g -c lockmgr.c -I.. -I../lib -DUSE_LOCKMGR -DTEST_PROGRAM g++ -o lockmgr lockmgr.o -lbac -L../lib/.libs -lssl -lpthread */ @@ -276,7 +287,7 @@ static int32_t global_event_id=0; static int global_int_thread_id=0; /* Keep an integer for each thread */ /* Keep this number of event per thread */ -#ifdef _TEST_IT +#ifdef TEST_PROGRAM # define LMGR_THREAD_EVENT_MAX 15 #else # define LMGR_THREAD_EVENT_MAX 1024 @@ -319,10 +330,12 @@ public: const char *from, int32_t line) { char *p; + int32_t oldflags; int i = lmgr_thread_event_get_pos(event_id); - events[i].flags = LMGR_EVENT_INVALID; + oldflags = events[i].flags; p = events[i].comment; + events[i].flags = LMGR_EVENT_INVALID; events[i].comment = (char *)"*Freed*"; /* Shared between thread, just an indication about timing */ @@ -335,7 +348,7 @@ public: * to check if the memory need to be freed */ if (event_id >= LMGR_THREAD_EVENT_MAX) { - if (events[i].flags & LMGR_EVENT_FREE) { + if (oldflags & LMGR_EVENT_FREE) { free(p); } } @@ -1215,9 +1228,13 @@ int bthread_change_uid(uid_t uid, gid_t gid) return -1; } +#ifndef TEST_PROGRAM +#define TEST_PROGRAM_A +#endif -#ifdef _TEST_IT - +#ifdef TEST_PROGRAM +#include "bacula.h" +#include "unittests.h" #include "lockmgr.h" #undef P #undef V @@ -1235,6 +1252,8 @@ bthread_mutex_t mutex_p1 = BTHREAD_MUTEX_PRIORITY(1); bthread_mutex_t mutex_p2 = BTHREAD_MUTEX_PRIORITY(2); bthread_mutex_t mutex_p3 = BTHREAD_MUTEX_PRIORITY(3); static const char *my_prog; +static bool thevent1ok = false; +static bool thevent2ok = false; void *self_lock(void *temp) { @@ -1282,10 +1301,9 @@ void *mix_rwl_mutex(void *temp) return NULL; } - void *thuid(void *temp) { - char buf[512]; +// char buf[512]; // if (restrict_job_permissions("eric", "users", buf, sizeof(buf)) < 0) { if (bthread_change_uid(2, 100) == -1) { berrno be; @@ -1379,6 +1397,7 @@ void *th_prio(void *a) { } void *th_event1(void *a) { + lmgr_thread_t *self = lmgr_get_thread_info(); for (int i=0; i < 10000; i++) { if ((i % 7) == 0) { lmgr_add_event_flag("strdup test", i, LMGR_EVENT_DUP); @@ -1386,11 +1405,13 @@ void *th_event1(void *a) { lmgr_add_event("My comment", i); } } + thevent1ok = self->event_id == 10000; sleep(5); return NULL; } void *th_event2(void *a) { + lmgr_thread_t *self = lmgr_get_thread_info(); for (int i=0; i < 10000; i++) { if ((i % 2) == 0) { lmgr_add_event_flag(bstrdup("free test"), i, LMGR_EVENT_FREE); @@ -1398,48 +1419,11 @@ void *th_event2(void *a) { lmgr_add_event("My comment", i); } } + thevent2ok = self->event_id == 10000; sleep(5); return NULL; } -int err=0; -int nb=0; -void _ok(const char *file, int l, const char *op, int value, const char *label) -{ - nb++; - if (!value) { - err++; - printf("ERR %.30s %s:%i on %s\n", label, file, l, op); - } else { - printf("OK %.30s\n", label); - } -} - -#define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label) - -void _nok(const char *file, int l, const char *op, int value, const char *label) -{ - nb++; - if (value) { - err++; - printf("ERR %.30s %s:%i on !%s\n", label, file, l, op); - } else { - printf("OK %.30s\n", label); - } -} - -#define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label) - -int report() -{ - printf("Result %i/%i OK\n", nb - err, nb); - return err>0; -} - -void terminate(int sig) -{ -} - /* * TODO: * - Must detect multiple lock @@ -1448,18 +1432,18 @@ void terminate(int sig) */ int main(int argc, char **argv) { + Unittests lmgr_test("lockmgr_test", true, argc != 2); void *ret=NULL; lmgr_thread_t *self; pthread_t id1, id2, id3, id4, id5, tab[200]; bthread_mutex_t bmutex1; pthread_mutex_t pmutex2; - debug_level = 10; - my_prog = argv[0]; - init_signals(terminate); + use_undertaker = false; - lmgr_init_thread(); + my_prog = argv[0]; self = lmgr_get_thread_info(); + /* below is used for checking forced SIGSEGV in separate process */ if (argc == 2) { /* do priority check */ P(mutex_p2); /* not permited */ P(mutex_p1); @@ -1468,10 +1452,17 @@ int main(int argc, char **argv) return 0; } - pthread_create(&id5, NULL, thuid, NULL); - pthread_join(id5, NULL); - fprintf(stderr, "UID %d:%d\n", (int)getuid(), (int)getgid()); - exit(0); + /* workaround for bthread_change_uid() failure for non-root */ + if (getuid() == 0){ + /* we can change uid/git, so proceed the test */ + pthread_create(&id5, NULL, thuid, NULL); + pthread_join(id5, NULL); + Pmsg2(0, "UID %d:%d\n", (int)getuid(), (int)getgid()); + } else { + Pmsg0(0, "Skipped bthread_change_uid() for non-root\n"); + } + + Pmsg0(0, "Starting mutex priority test\n"); pthread_mutex_init(&bmutex1, NULL); bthread_mutex_set_priority(&bmutex1, 10); @@ -1484,12 +1475,14 @@ int main(int argc, char **argv) V(bmutex1); ok(self->max_priority == 0, "Check self max_priority"); + Pmsg0(0, "Starting self deadlock tests\n"); pthread_create(&id1, NULL, self_lock, NULL); sleep(2); ok(lmgr_detect_deadlock(), "Check self deadlock"); lmgr_v(&mutex1.mutex); /* a bit dirty */ pthread_join(id1, NULL); + Pmsg0(0, "Starting thread kill tests\n"); pthread_create(&id1, NULL, nolock, NULL); sleep(2); ok(bthread_kill(id1, SIGUSR2) == 0, "Kill existing thread"); @@ -1497,6 +1490,7 @@ int main(int argc, char **argv) ok(bthread_kill(id1, SIGUSR2) == -1, "Kill non-existing thread"); ok(bthread_kill(pthread_self(), SIGUSR2) == -1, "Kill self"); + Pmsg0(0, "Starting thread locks tests\n"); pthread_create(&id1, NULL, nolock, NULL); sleep(2); nok(lmgr_detect_deadlock(), "Check for nolock"); @@ -1513,7 +1507,6 @@ int main(int argc, char **argv) pthread_join(id2, NULL); pthread_join(id3, NULL); - brwlock_t wr; rwl_init(&wr); rwl_writelock(&wr); @@ -1562,16 +1555,18 @@ int main(int argc, char **argv) P(mutex6); ok(lmgr_mutex_is_locked(&mutex6) == 1, "Check if mutex is locked"); V(mutex6); - ok(lmgr_mutex_is_locked(&mutex6) == 0, "Check if mutex is locked"); + ok(lmgr_mutex_is_locked(&mutex6) == 0, "Check if mutex is unlocked"); V(mutex5); V(mutex4); + Pmsg0(0, "Starting threads deadlock tests\n"); pthread_create(&id1, NULL, th1, NULL); sleep(1); pthread_create(&id2, NULL, th2, NULL); sleep(1); ok(lmgr_detect_deadlock(), "Check for deadlock"); + Pmsg0(0, "Starting for max_priority locks tests\n"); pthread_create(&id3, NULL, th_prio, NULL); pthread_join(id3, &ret); ok(ret != 0, "Check for priority segfault"); @@ -1613,6 +1608,7 @@ int main(int argc, char **argv) V(mutex_p1); V(mutex_p2); + Pmsg0(0, "Start lmgr_add_even tests\n"); for (int i=0; i < 10000; i++) { if ((i % 7) == 0) { lmgr_add_event_flag("xxxxxxxxxxxxxxxx strdup test xxxxxxxxxxxxxxxx", i, LMGR_EVENT_DUP); @@ -1620,24 +1616,19 @@ int main(int argc, char **argv) lmgr_add_event("My comment", i); } } + ok(self->event_id == 10000, "Checking registered events in self"); pthread_create(&id4, NULL, th_event1, NULL); pthread_create(&id5, NULL, th_event2, NULL); sleep(2); - lmgr_dump(); - pthread_join(id4, NULL); pthread_join(id5, NULL); -// -// pthread_create(&id3, NULL, th3, NULL); -// -// pthread_join(id1, NULL); -// pthread_join(id2, NULL); - lmgr_cleanup_main(); - sm_check(__FILE__, __LINE__, false); + + ok(thevent1ok, "Checking registered events in thread1"); + ok(thevent2ok, "Checking registered events in thread2"); + return report(); } - -#endif +#endif /* TEST_PROGRAM */ diff --git a/bacula/src/lib/unittests.c b/bacula/src/lib/unittests.c index 9633928e2c..be9d04f8f5 100644 --- a/bacula/src/lib/unittests.c +++ b/bacula/src/lib/unittests.c @@ -99,9 +99,10 @@ void terminate(int sig) {}; /* * Initializes the application env, including lockmanager. */ -void prolog(const char *name, bool lmgr=false) +void prolog(const char *name, bool lmgr=false, bool motd=true) { - Pmsg1(-1, "==== Starting %s ... ====\n", name); + if (motd) + Pmsg1(-1, "==== Starting %s ... ====\n", name); my_name_is(0, NULL, name); init_signals(terminate); if (lmgr){ diff --git a/bacula/src/lib/unittests.h b/bacula/src/lib/unittests.h index 7da4f69b76..453822cefd 100644 --- a/bacula/src/lib/unittests.h +++ b/bacula/src/lib/unittests.h @@ -45,14 +45,17 @@ void _ok(const char *file, int l, const char *op, int value, const char *label); void _nok(const char *file, int l, const char *op, int value, const char *label); int report(); void terminate(int sig); -void prolog(const char *name, bool lmgr=false); +void prolog(const char *name, bool lmgr=false, bool motd=true); void epilog(); /* The class based approach for C++ geeks */ class Unittests { public: - Unittests(const char *name, bool lmgr=false) { prolog(name, lmgr); }; + Unittests(const char *name, bool lmgr=false, bool motd=true) + { + prolog(name, lmgr, motd); + }; ~Unittests() { epilog(); }; }; diff --git a/regress/tests/lockmgr-unittests b/regress/tests/lockmgr-unittests new file mode 100755 index 0000000000..042db7e68f --- /dev/null +++ b/regress/tests/lockmgr-unittests @@ -0,0 +1,16 @@ +#!/bin/sh +# +# Copyright (C) 2000-2015 Kern Sibbald +# License: BSD 2-Clause; see file LICENSE-FOSS +# +# Copyright (c) 2018 by Inteos sp. z o.o. +# All rights reserved. IP transfered to Bacula Systems according to agreement. +# +# This is a lockmgr unit test +# +TestName="lockmgr_test" +. scripts/functions +make -C $src/src/lib $TestName + +$src/src/lib/$TestName +exit $?