aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/testcode/lock_verify.c
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/testcode/lock_verify.c')
m---------external/unbound0
-rw-r--r--external/unbound/testcode/lock_verify.c426
2 files changed, 0 insertions, 426 deletions
diff --git a/external/unbound b/external/unbound
new file mode 160000
+Subproject 193bdc4ee3fe2b0d17e547e86512528c2614483
diff --git a/external/unbound/testcode/lock_verify.c b/external/unbound/testcode/lock_verify.c
deleted file mode 100644
index 666a7029d..000000000
--- a/external/unbound/testcode/lock_verify.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * testcode/lock_verify.c - verifier program for lock traces, checks order.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file checks the lock traces generated by checklock.c.
- * Checks if locks are consistently locked in the same order.
- * If not, this can lead to deadlock if threads execute the different
- * ordering at the same time.
- *
- */
-
-#include "config.h"
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
-#include "util/log.h"
-#include "util/rbtree.h"
-#include "util/locks.h"
-#include "util/fptr_wlist.h"
-
-/* --- data structures --- */
-struct lock_ref;
-
-/** keep track of lock id in lock-verify application
- * Also defined in smallapp/worker_cb.c for fptr_wlist encapsulation
- * breakage (the security tests break encapsulation for this test app) */
-struct order_id {
- /** the thread id that created it */
- int thr;
- /** the instance number of creation */
- int instance;
-};
-
-/** a lock */
-struct order_lock {
- /** rbnode in all tree */
- rbnode_type node;
- /** lock id */
- struct order_id id;
- /** the creation file */
- char* create_file;
- /** creation line */
- int create_line;
- /** set of all locks that are smaller than this one (locked earlier) */
- rbtree_type* smaller;
- /** during depthfirstsearch, this is a linked list of the stack
- * of locks. points to the next lock bigger than this one. */
- struct lock_ref* dfs_next;
- /** if lock has been visited (all smaller locks have been compared to
- * this lock), only need to compare this with all unvisited(bigger)
- * locks */
- int visited;
-};
-
-/** reference to a lock in a rbtree set */
-struct lock_ref {
- /** rbnode, key is an order_id ptr */
- rbnode_type node;
- /** the lock referenced */
- struct order_lock* lock;
- /** why is this ref */
- char* file;
- /** line number */
- int line;
-};
-
-/** count of errors detected */
-static int errors_detected = 0;
-/** verbose? */
-static int verb = 0;
-
-/** print program usage help */
-static void
-usage(void)
-{
- printf("lock_verify <trace files>\n");
-}
-
-/** read header entry.
- * @param in: file to read header of.
- * @return: False if it does not belong to the rest. */
-static int
-read_header(FILE* in)
-{
- time_t t;
- pid_t p;
- int thrno;
- static int have_values = 0;
- static time_t the_time;
- static pid_t the_pid;
- static int threads[256];
-
- if(fread(&t, sizeof(t), 1, in) != 1 ||
- fread(&thrno, sizeof(thrno), 1, in) != 1 ||
- fread(&p, sizeof(p), 1, in) != 1) {
- fatal_exit("fread failed");
- }
- /* check these values are sorta OK */
- if(!have_values) {
- the_time = t;
- the_pid = p;
- memset(threads, 0, 256*sizeof(int));
- if(thrno >= 256) {
- fatal_exit("Thread number too big. %d", thrno);
- }
- threads[thrno] = 1;
- have_values = 1;
- printf(" trace %d from pid %u on %s", thrno,
- (unsigned)p, ctime(&t));
- } else {
- if(the_pid != p) {
- printf(" has pid %u, not %u. Skipped.\n",
- (unsigned)p, (unsigned)the_pid);
- return 0;
- }
- if(threads[thrno])
- fatal_exit("same threadno in two files");
- threads[thrno] = 1;
- if( abs((int)(the_time - t)) > 3600)
- fatal_exit("input files from different times: %u %u",
- (unsigned)the_time, (unsigned)t);
- printf(" trace of thread %u:%d\n", (unsigned)p, thrno);
- }
- return 1;
-}
-
-/** max length of strings: filenames and function names. */
-#define STRMAX 1024
-/** read a string from file, false on error */
-static int readup_str(char** str, FILE* in)
-{
- char buf[STRMAX];
- int len = 0;
- int c;
- /* ends in zero */
- while( (c = fgetc(in)) != 0) {
- if(c == EOF)
- fatal_exit("eof in readstr, file too short");
- buf[len++] = c;
- if(len == STRMAX) {
- fatal_exit("string too long, bad file format");
- }
- }
- buf[len] = 0;
- *str = strdup(buf);
- return 1;
-}
-
-/** read creation entry */
-static void read_create(rbtree_type* all, FILE* in)
-{
- struct order_lock* o = calloc(1, sizeof(struct order_lock));
- if(!o) fatal_exit("malloc failure");
- if(fread(&o->id.thr, sizeof(int), 1, in) != 1 ||
- fread(&o->id.instance, sizeof(int), 1, in) != 1 ||
- !readup_str(&o->create_file, in) ||
- fread(&o->create_line, sizeof(int), 1, in) != 1)
- fatal_exit("fread failed");
- o->smaller = rbtree_create(order_lock_cmp);
- o->node.key = &o->id;
- if(!rbtree_insert(all, &o->node)) {
- /* already inserted */
- struct order_lock* a = (struct order_lock*)rbtree_search(all,
- &o->id);
- log_assert(a);
- a->create_file = o->create_file;
- a->create_line = o->create_line;
- free(o->smaller);
- free(o);
- o = a;
- }
- if(verb) printf("read create %u %u %s %d\n",
- (unsigned)o->id.thr, (unsigned)o->id.instance,
- o->create_file, o->create_line);
-}
-
-/** insert lock entry (empty) into list */
-static struct order_lock*
-insert_lock(rbtree_type* all, struct order_id* id)
-{
- struct order_lock* o = calloc(1, sizeof(struct order_lock));
- if(!o) fatal_exit("malloc failure");
- o->smaller = rbtree_create(order_lock_cmp);
- o->id = *id;
- o->node.key = &o->id;
- if(!rbtree_insert(all, &o->node))
- fatal_exit("insert fail should not happen");
- return o;
-}
-
-/** read lock entry */
-static void read_lock(rbtree_type* all, FILE* in, int val)
-{
- struct order_id prev_id, now_id;
- struct lock_ref* ref;
- struct order_lock* prev, *now;
- ref = (struct lock_ref*)calloc(1, sizeof(struct lock_ref));
- if(!ref) fatal_exit("malloc failure");
- prev_id.thr = val;
- if(fread(&prev_id.instance, sizeof(int), 1, in) != 1 ||
- fread(&now_id.thr, sizeof(int), 1, in) != 1 ||
- fread(&now_id.instance, sizeof(int), 1, in) != 1 ||
- !readup_str(&ref->file, in) ||
- fread(&ref->line, sizeof(int), 1, in) != 1)
- fatal_exit("fread failed");
- if(verb) printf("read lock %u %u %u %u %s %d\n",
- (unsigned)prev_id.thr, (unsigned)prev_id.instance,
- (unsigned)now_id.thr, (unsigned)now_id.instance,
- ref->file, ref->line);
- /* find the two locks involved */
- prev = (struct order_lock*)rbtree_search(all, &prev_id);
- now = (struct order_lock*)rbtree_search(all, &now_id);
- /* if not there - insert 'em */
- if(!prev) prev = insert_lock(all, &prev_id);
- if(!now) now = insert_lock(all, &now_id);
- ref->lock = prev;
- ref->node.key = &prev->id;
- if(!rbtree_insert(now->smaller, &ref->node)) {
- free(ref->file);
- free(ref);
- }
-}
-
-/** read input file */
-static void readinput(rbtree_type* all, char* file)
-{
- FILE *in = fopen(file, "r");
- int fst;
- if(!in) {
- perror(file);
- exit(1);
- }
- printf("file %s", file);
- if(!read_header(in)) {
- fclose(in);
- return;
- }
- while(fread(&fst, sizeof(fst), 1, in) == 1) {
- if(fst == -1)
- read_create(all, in);
- else read_lock(all, in, fst);
- }
- fclose(in);
-}
-
-/** print cycle message */
-static void found_cycle(struct lock_ref* visit, int level)
-{
- struct lock_ref* p;
- int i = 0;
- errors_detected++;
- printf("Found inconsistent locking order of length %d\n", level);
- printf("for lock %d %d created %s %d\n",
- visit->lock->id.thr, visit->lock->id.instance,
- visit->lock->create_file, visit->lock->create_line);
- printf("sequence is:\n");
- p = visit;
- while(p) {
- struct order_lock* next =
- p->lock->dfs_next?p->lock->dfs_next->lock:visit->lock;
- printf("[%d] is locked at line %s %d before lock %d %d\n",
- i, p->file, p->line, next->id.thr, next->id.instance);
- printf("[%d] lock %d %d is created at %s %d\n",
- i, next->id.thr, next->id.instance,
- next->create_file, next->create_line);
- i++;
- p = p->lock->dfs_next;
- if(p && p->lock == visit->lock)
- break;
- }
-}
-
-/** Detect cycle by comparing visited now with all (unvisited) bigger nodes */
-static int detect_cycle(struct lock_ref* visit, struct lock_ref* from)
-{
- struct lock_ref* p = from;
- while(p) {
- if(p->lock == visit->lock)
- return 1;
- p = p->lock->dfs_next;
- }
- return 0;
-}
-
-/** recursive function to depth first search for cycles.
- * @param visit: the lock visited at this step.
- * its dfs_next pointer gives the visited lock up in recursion.
- * same as lookfor at level 0.
- * @param level: depth of recursion. 0 is start.
- * @param from: search for matches from unvisited node upwards.
- */
-static void search_cycle(struct lock_ref* visit, int level,
- struct lock_ref* from)
-{
- struct lock_ref* ref;
- /* check for cycle */
- if(detect_cycle(visit, from) && level != 0) {
- found_cycle(visit, level);
- fatal_exit("found lock order cycle");
- }
- /* recurse */
- if(!visit->lock->visited)
- from = visit;
- if(verb > 1) fprintf(stderr, "[%d] visit lock %u %u %s %d\n", level,
- (unsigned)visit->lock->id.thr,
- (unsigned)visit->lock->id.instance,
- visit->lock->create_file, visit->lock->create_line);
- RBTREE_FOR(ref, struct lock_ref*, visit->lock->smaller) {
- ref->lock->dfs_next = visit;
- search_cycle(ref, level+1, from);
- }
- visit->lock->visited = 1;
-}
-
-/** Check ordering of one lock */
-static void check_order_lock(struct order_lock* lock)
-{
- struct lock_ref start;
- if(lock->visited) return;
-
- start.node.key = &lock->id;
- start.lock = lock;
- start.file = lock->create_file;
- start.line = lock->create_line;
-
- if(!lock->create_file)
- log_err("lock %u %u does not have create info",
- (unsigned)lock->id.thr, (unsigned)lock->id.instance);
-
- /* depth first search to find cycle with this lock at head */
- lock->dfs_next = NULL;
- search_cycle(&start, 0, &start);
-}
-
-/** Check ordering of locks */
-static void check_order(rbtree_type* all_locks)
-{
- /* check each lock */
- struct order_lock* lock;
- int i=0;
- RBTREE_FOR(lock, struct order_lock*, all_locks) {
- if(verb)
- printf("[%d/%d] Checking lock %d %d %s %d\n",
- i, (int)all_locks->count,
- lock->id.thr, lock->id.instance,
- lock->create_file, lock->create_line);
- else if (i % ((all_locks->count/75)<1?1:all_locks->count/75)
- == 0)
- fprintf(stderr, ".");
- i++;
- check_order_lock(lock);
- }
- fprintf(stderr, "\n");
-}
-
-/** main program to verify all traces passed */
-int
-main(int argc, char* argv[])
-{
- rbtree_type* all_locks;
- int i;
- time_t starttime = time(NULL);
-#ifdef USE_THREAD_DEBUG
- /* do not overwrite the ublocktrace files with the ones generated
- * by this program (i.e. when the log code creates a lock) */
- check_locking_order = 0;
-#endif
- if(argc <= 1) {
- usage();
- return 1;
- }
- log_init(NULL, 0, NULL);
- log_ident_set("lock-verify");
- /* init */
- all_locks = rbtree_create(order_lock_cmp);
- errors_detected = 0;
-
- /* read the input files */
- for(i=1; i<argc; i++) {
- readinput(all_locks, argv[i]);
- }
-
- /* check ordering */
- check_order(all_locks);
-
- /* do not free a thing, OS will do it */
- printf("checked %d locks in %d seconds with %d errors.\n",
- (int)all_locks->count, (int)(time(NULL)-starttime),
- errors_detected);
- if(errors_detected) return 1;
- return 0;
-}