Logo Search packages:      
Sourcecode: tucnak2 version File versions  Download package

error.c

/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2006  Ladislav Vaiz <ok1zia@nagano.cz>
    and authors of web browser Links 0.96

    This program is free software; you can redistribute it and/or                                                        
    modify it under the terms of the GNU General Public License                                                          
    version 2 as published by the Free Software Foundation.

*/

#include "header.h"

GHashTable *mbs;
GMutex *mbs_mutex;

void do_not_optimize_here(void *p)
{
    /* stop GCC optimization - avoid bugs in it */
}

#ifdef LEAK_DEBUG
long mem_amount = 0;
long last_mem_amount = -1;
#ifdef LEAK_DEBUG_LIST
struct list_head memory_list = { &memory_list, &memory_list };
GMutex *memory_list_mutex;
#endif
#endif

static inline void force_dump(void)
{
    fprintf(stderr, "\n\033[1m%s\033[0m\n", "Forcing core dump");
    fflush(stderr);
    raise(SIGSEGV);
    exit(1);
}

void check_memory_leaks()
{
#ifdef LEAK_DEBUG
    if (mem_amount) {
        free_all_itrms();
        fprintf(stderr, "\n\033[1mMemory leak by %ld bytes\033[0m\n", mem_amount);
#ifdef LEAK_DEBUG_LIST
        fprintf(stderr, "\nList of blocks: ");
        {
            int r = 0;
            struct alloc_header *ah;
            LOCK(memory_list);
            foreach (ah, memory_list) {
                fprintf(stderr, "%s%p:%d @ %s:%d", r ? ", ": "", (char *)ah + L_D_S, ah->size, ah->file, ah->line), r = 1;
                if (ah->comment) fprintf(stderr, ":\"%s\"", ah->comment);
            }
            fprintf(stderr, "\n");
            UNLOCK(memory_list);
        }
#endif
        force_dump();
    }
#endif
}

void er(int b, char *m, va_list l)
{
    if (b) fprintf(stderr, "%c", (char)7);
    vfprintf(stderr, m, l);
    fprintf(stderr, "\n");
    sleep(1);
}

void error(char *m, ...)
{
    va_list l;
    va_start(l, m);
    er(1, m, l);
}

int errline;
char *errfile;

char errbuf[4096];

void int_error(char *m, ...)
{
    va_list l;
    free_all_itrms();
    va_start(l, m);
    sprintf(errbuf, "\033[1mINTERNAL ERROR\033[0m at %s:%d: ", errfile, errline);
    strcat(errbuf, m);
    er(1, errbuf, l);
    force_dump();
}

void debug_msg(char *m, ...)
{
    va_list l;
    free_all_itrms();
    va_start(l, m);
    sprintf(errbuf, "DEBUG MESSAGE at %s:%d: ", errfile, errline);
    strcat(errbuf, m);
    er(0, errbuf, l);
}

int debug_type=0;
char *debug_filename=NULL;
FILE *debug_file=NULL;

void init_debug(){
    mbs=g_hash_table_new(g_direct_hash, g_direct_equal);
    mbs_mutex=g_mutex_new();
#ifdef LEAK_DEBUG_LIST
    memory_list_mutex=g_mutex_new();
#endif    
    
    switch (debug_type){
        case 1:
            debug_file=fopen(debug_filename, "at");
            break;
        case 2:
            debug_file=stderr;
            break;    
    }
}

void free_debug(){
    if (!debug_file) return;
    if (debug_file!=stderr) fclose(debug_file);

    g_hash_table_destroy(mbs);
    g_mutex_free(mbs_mutex);
#ifdef LEAK_DEBUG_LIST
    g_mutex_free(memory_list_mutex);
#endif
}

void dbg(char *m, ...)
{
    va_list l;

    if (!debug_file) return;
    va_start(l, m);
    vfprintf(debug_file, m, l);
    va_end(l);
    fsync(fileno(debug_file));
}

void dbg_bcast(char *m, ...)
{
    va_list l;
    gchar *c;

    if (!cfg || !cfg->trace_bcast) return;
    va_start(l, m);
    c=g_strdup_vprintf(m, l);
    va_end(l);
    
    dbg("%s",c);
    log_adds(c);

    g_free(c);
}

void dbg_sock(char *m, ...)
{
    va_list l;
    gchar *c;

    if (!cfg || !cfg->trace_sock) return;
    va_start(l, m);
    c=g_strdup_vprintf(m, l);
    va_end(l);
    
    dbg("%s",c);
    log_adds(c);

    g_free(c);
}

void dbg_recv(char *m, ...)
{
    va_list l;
    gchar *c;

    if (!cfg || !cfg->trace_recv) return;
    va_start(l, m);
    c=g_strdup_vprintf(m, l);
    va_end(l);
    
    dbg("%s",c);
    log_adds(c);

    g_free(c);
}

void dbg_send(char *m, ...)
{
    va_list l;
    gchar *c;

    if (!cfg || !cfg->trace_send) return;
    va_start(l, m);
    c=g_strdup_vprintf(m, l);
    va_end(l);
    
    dbg("%s",c);
    log_adds(c);

    g_free(c);
}

void dbg_qsos(char *m, ...)
{
    va_list l;
    gchar *c;

    if (!cfg || !cfg->trace_qsos) return;
    va_start(l, m);
    c=g_strdup_vprintf(m, l);
    va_end(l);
    
    dbg("%s\n",c);
#if 0    
 raise(SIGSEGV); log_adds(c);
#else
    if (ctest && ctest->logfile){
        fprintf(ctest->logfile, "%s\n", c);
    }
#endif

    g_free(c);
}




void print_str_hash(gpointer key, gpointer value, gpointer data){
    dbg("\tkey='%s' \tvalue='%s'\n", key, value);
}

void dbg_str_hash(GHashTable *hash){
    g_hash_table_foreach(hash, print_str_hash, NULL);
}

#ifdef LEAK_DEBUG

void *debug_mem_alloc(char *file, int line, size_t size)
{
    void *p;
#ifdef LEAK_DEBUG
    struct alloc_header *ah;
#endif
#ifdef LEAK_DEBUG_LIST
    gpointer orig_key, value;
#endif    
    
    if (!size) return DUMMY;
#ifdef LEAK_DEBUG
    mem_amount += size;
    size += L_D_S;
#endif
    if (!(p = xmalloc(size))) {
        error("ERROR: out of memory (malloc returned NULL)\n");
        return NULL;
    }
#ifdef LEAK_DEBUG
    ah = p;
    p = (char *)p + L_D_S;
    ah->size = size - L_D_S;
#ifdef LEAK_DEBUG_LIST
    ah->file = file;
    ah->line = line;
    ah->comment = NULL;
    LOCK(memory_list);
    add_to_list(memory_list, ah);
    UNLOCK(memory_list);

    LOCK(mbs);
    if (g_hash_table_lookup_extended(mbs, (char*)p, &orig_key, &value)){
        int cnt=(vint)value;
        if (value!=0){
            free_all_itrms();
            fprintf(stderr, " alloc: already allocated(%d): %p:%d @ %s:%d\n", cnt, p, ah->size, ah->file, ah->line);
            force_dump();
        }
    }
    g_hash_table_insert(mbs, p, (gpointer)1);
    UNLOCK(mbs);
#endif
#endif
/*    fprintf(stderr, "debuf_mem_alloc(%s:%d, %d)=%p\n", file, line, size, p);*/
    return p;
}

void debug_mem_free(char *file, int line, void *p)
{
#ifdef LEAK_DEBUG
    void *xp;
    struct alloc_header *ah;
#endif
#ifdef LEAK_DEBUG_LIST
    gpointer orig_key, value;
#endif    

    
    if (p == DUMMY) return;
    if (!p) {
        errfile = file, errline = line, int_error("mem_free(NULL)");
        return;
    }
#ifdef LEAK_DEBUG
    xp = p;
    p = (char *)p - L_D_S;
    ah = p;
#ifdef LEAK_DEBUG_LIST
    LOCK(mbs);
    if (g_hash_table_lookup_extended(mbs, xp, &orig_key, &value)){
        int cnt=(vint)value;
        if (cnt!=1){
            free_all_itrms();
            fprintf(stderr, " free: usage count is %d: %p:%d @ %s:%d\n", cnt, xp, ah->size, ah->file, ah->line);
            force_dump();
        }
        g_hash_table_remove(mbs, xp);
        g_hash_table_insert(mbs, xp, (gpointer)0);
    }
    UNLOCK(mbs);
    LOCK(memory_list);
    del_from_list(ah);
    UNLOCK(memory_list);
    if (ah->comment) free(ah->comment);
#endif
    mem_amount -= ah->size;
#endif
    /*fprintf(stderr, "debuf_mem_free(%s:%d)=%p\n", file, line, p);*/
    xfree(p);
}

void *debug_mem_realloc(char *file, int line, void *p, size_t size)
{
#ifdef LEAK_DEBUG
    struct alloc_header *ah;
#endif
#ifdef LEAK_DEBUG_LIST
    gpointer orig_key, value;
#endif    


    if (p == DUMMY) return debug_mem_alloc(file, line, size);
    if (!p) {
        errfile = file, errline = line, int_error("mem_realloc(NULL, %d)", size);
        return NULL;
    }
    if (!size) {
        debug_mem_free(file, line, p);
        return DUMMY;
    }
#ifdef LEAK_DEBUG_LIST    
    LOCK(mbs);
    if (g_hash_table_lookup_extended(mbs, p, &orig_key, &value)){
        int cnt=(vint)value;
        if (cnt!=1){
                  dbg("debug_mem_realloc: cnt=%d\n", cnt);
                  UNLOCK(mbs);
            free_all_itrms();
            fprintf(stderr, " realloc1: usage count is %d: %p @ %s:%d (allocated %s:%d)\n", cnt, p, file, line, ah->file, ah->line);
            force_dump();
        }
        g_hash_table_remove(mbs, p);
        g_hash_table_insert(mbs, p, (gpointer)0);
    }
    UNLOCK(mbs);
#endif    
    if (!(p = xrealloc((char *)p - L_D_S, size + L_D_S))) {
        error("ERROR: out of memory (realloc returned NULL)\n");
        return NULL;
    }
#ifdef LEAK_DEBUG
    ah = p;
    mem_amount += size - ah->size;
    ah->size = size;
#ifdef LEAK_DEBUG_LIST
    ah->prev->next = ah;
    ah->next->prev = ah;
    
    LOCK(mbs);
    if (g_hash_table_lookup_extended(mbs, (char*)p+L_D_S, &orig_key, &value)){
        int cnt=(vint)value;
        if (value!=0){
            free_all_itrms();
            fprintf(stderr, " realloc2: already allocated(%d): %p:%d @ %s:%d (allocated %s:%d)\n", cnt, (char *)ah + L_D_S, ah->size, file, line, ah->file, ah->line);
            force_dump();
        }
    }
    g_hash_table_insert(mbs, (char*)p+L_D_S, (gpointer)1);
    UNLOCK(mbs);
#endif
#endif
    return (char *)p + L_D_S;
}

void set_mem_comment(void *p, char *c, int l)
{
#ifdef LEAK_DEBUG_LIST
    struct alloc_header *ah = (struct alloc_header *)((char *)p - L_D_S);
    if (ah->comment) free(ah->comment);
    if ((ah->comment = malloc(l + 1))) memcpy(ah->comment, c, l), ah->comment[l] = 0;
#endif
}


void *debug_g_new0(char *file, int line, size_t len){
    gchar *c;

    c=debug_mem_alloc(file, line, len);
    if (c==DUMMY) return NULL;
    memset(c, 0, len);
    return c;
}

void *debug_g_new(char *file, int line, size_t len){
    gchar *c;

    c=debug_mem_alloc(file, line, len);
    if (c==DUMMY) return NULL;
    memset(c, 0, len);
    return c;
}

gchar *debug_g_strdup(char *file, int line, const gchar *str){
    gchar *c;
    
    if (!str) return NULL;
    c=debug_mem_alloc(file, line, strlen(str)+1);
    if (c==DUMMY) return NULL;
    strcpy(c, str);
    return c;
}

gchar *debug_g_strndup(char *file, int line, gchar *str, int len){
    gchar *c;
    int l;
    
    if (!str) return NULL;
    l=strlen(str);
    if (l>len) l=len;
    c=debug_mem_alloc(file, line, l+1);
    if (c==DUMMY) return NULL;
    strncpy(c, str, l);
    c[l]='\0';
    return c;
}

gchar *debug_g_strdup_printf(char *file, int line, gchar *fmt, ...){
    va_list l;
    int len;
    char *c;

    va_start(l, fmt);
    len=g_printf_string_upper_bound(fmt, l);
    c=debug_mem_alloc(file, line, len);
    if (c==DUMMY) return NULL;
    g_vsprintf(c, fmt, l);
    va_end(l);
    return c;
}

gchar *debug_g_strdup_vprintf(char *file, int line, gchar *fmt, va_list args){
    int len;
    char *c;

    len=g_printf_string_upper_bound(fmt, args);
    c=debug_mem_alloc(file, line, len);
    if (c==DUMMY) return NULL;
    g_vsprintf(c, fmt, args);
    return c;
}

gchar *debug_g_strconcat(char *file, int line, ...){
    va_list l;
    int len;
    char *c,*d;
    char *s;
    
    va_start(l, line);
    len=0;
    while(1){
        c=va_arg(l, char *);
        if (!c) break;
        len+=strlen(c);
    }
    va_end(l);
    s=debug_mem_alloc(file, line, len+1);
    if (s==DUMMY) return NULL;
    va_start(l, line);
    len=0;
    d=s;
    while(1){
        c=va_arg(l, char *);
        if (!c) break;
        strcpy(d, c);
        d+=strlen(c);
    }
    va_end(l);
    return s;
}
#endif


void sock_debug(int sock, char *m, ...){

    va_list l;
    FILE *f;

    return;
    
    f = fopen("tucnak.sockdbg", "at");
    if (!f) return;

    va_start(l, m);
    fprintf(f, "%5d: socket %3d ", getpid(), sock);
    vfprintf(f, m, l);
    fprintf(f,"\n");
    va_end(l);
    fclose(f);
}


Generated by  Doxygen 1.6.0   Back to index