Changeset 6654

Show
Ignore:
Timestamp:
13/05/10 17:30:03 (21 months ago)
Author:
westram
Message:
  • This patch stuffs all memory leaks in ARBDB (as far as covered by unit-tests) for DEBUG and NDEBUG version!
  • ARBDB global data (aka 'gb_local')
    • track number of opened/closed DBs
    • GBK_install_SIGSEGV_handler only once in GB_init_gb()
    • when closing last DB -> call GB_exit_gb() freeing more memory (also called atexit, including assertion failing if a DB is still open)
    • added class ARBDB_memory_manager (just calls gbm_init_mem + gbm_flush_mem)
    • GB_exit_gb flushes ARBDB_memory_manager (if all blocks were freed by gbm_free_mem, everything will be flushed)
  • fixed a few more static buffer leaks
  • gb_make_entry - alloc correct blocksizes for GB_STRING and GB_LINK
  • fixed a hack in gb_read_bin_rek_V2
    • was increasing size of memory block to avoid illegal memory access in decompress (introduced in [1003]; may occur again)
    • due to mismatch in size between gbm_get_mem and gbm_free_mem memory was never flushed even if all blocks have been freed
  • fixed memleak in gb_read_bin_rek_V2
    • when loading mapfile, previously created 'gb_main' was not freed
  • added allocation logger to admalloc.cxx (inactive - use TRACE_ALLOCS to activate it)
    • traces all allocs/frees of ARBDB managed memory
    • detects wrong usage (double free, size and index mismatch) and shows were the block was allocated
    • added new backtrace functions helpful for debugging (store stack-backtraces and print them later)
Location:
trunk/ARBDB
Files:
13 modified

Legend:

Unmodified
Added
Removed
  • trunk/ARBDB/Makefile

    r6628 r6654  
    145145ad_core.o: gb_key.h 
    146146ad_core.o: gb_local.h 
     147ad_core.o: gb_localdata.h 
    147148ad_core.o: gb_main.h 
    148149ad_core.o: gb_memory.h 
  • trunk/ARBDB/adTest.cxx

    r6640 r6654  
    172172 
    173173    if (gb_father) { 
    174         char *father_path = strdup(GB_get_db_path(gb_father)); 
    175  
    176         static char *result; // careful! used recursively 
    177         freeset(result, GBS_global_string_copy("%s/%s", father_path, GB_KEY(gbd))); 
    178         free(father_path); 
    179  
    180         return result; 
     174        const char *father_path = GB_get_db_path(gb_father); 
     175 
     176        static SmartMallocPtr(char) result;        // careful! used recursively 
     177        char *key = GB_KEY(gbd); 
     178        result    = GBS_global_string_copy("%s/%s", father_path, key ? key : "<gbmain>"); 
     179 
     180        return &*result; 
    181181    } 
    182182    return ""; 
  • trunk/ARBDB/ad_core.cxx

    r6648 r6654  
    1212#include "gb_storage.h" 
    1313#include "gb_index.h" 
     14#include "gb_localdata.h" 
    1415 
    1516// Copy all info + external data mem to an one step undo buffer 
     
    7374} 
    7475 
    75 void gb_touch_header(GBCONTAINER *gbc) 
    76 { 
     76void gb_touch_header(GBCONTAINER *gbc) { 
    7777    gbc->flags2.header_changed = 1; 
    7878    gb_touch_entry((GBDATA*)gbc, GB_NORMAL_CHANGE); 
     
    8080 
    8181 
    82 void 
    83 gb_untouch_children(GBCONTAINER * gbc) 
    84 { 
     82void gb_untouch_children(GBCONTAINER * gbc) { 
    8583    GBDATA    *gbd; 
    8684    int        index, start, end; 
     
    120118} 
    121119 
    122 void gb_untouch_me(GBDATA * gbc) 
    123 { 
     120void gb_untouch_me(GBDATA * gbc) { 
    124121    GB_DATA_LIST_HEADER(GB_FATHER(gbc)->d)[gbc->index].flags.changed = GB_UNCHANGED; 
    125122    if (GB_TYPE(gbc) == GB_DB) { 
     
    129126} 
    130127 
    131 void gb_set_update_in_server_flags(GBCONTAINER * gbc) 
    132 { 
     128void gb_set_update_in_server_flags(GBCONTAINER * gbc) { 
    133129    int             index; 
    134130    GBDATA         *gbd; 
     
    258254 
    259255    Main = (GB_MAIN_TYPE *)gbm_get_mem(sizeof(*Main), 0); 
    260     if (path) Main->path = strdup((char*)path); 
     256    if (path) Main->path   = strdup((char*)path); 
    261257    Main->key_2_index_hash = GBS_create_hash(ALLOWED_KEYS, GB_MIND_CASE); 
    262     Main->compression_mask = -1;        // allow all compressions 
     258    Main->compression_mask = -1;                    // allow all compressions 
    263259    gb_init_cache(Main); 
    264260    gb_init_undo_stack(Main); 
    265261    gb_init_ctype_table(); 
     262    gb_local->openedDBs++; 
    266263    return Main; 
    267264} 
     
    287284    free(Main->path); 
    288285    free(Main->qs.quick_save_disabled); 
    289      
     286 
    290287    gbm_free_mem((char *)Main, sizeof(*Main), 0); 
     288 
     289    gb_local->closedDBs++; 
     290    if (gb_local->closedDBs == gb_local->openedDBs) { 
     291        GB_exit_gb(); // free most memory allocated by ARBDB library 
     292    } 
    291293 
    292294    return 0; 
     
    331333GBDATA *gb_make_entry(GBCONTAINER * father, const char *key, long index_pos, GBQUARK keyq, GB_TYPES type) { 
    332334    // creates a terminal database object 
    333     GBDATA       *gbd; 
    334     long          gbm_index; 
    335     static char  *buffer = 0; 
    336     char         *p; 
    337     GB_MAIN_TYPE *Main   = GBCONTAINER_MAIN(father); 
     335    GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(father); 
    338336 
    339337    if (!keyq) keyq = gb_key_2_quark(Main, key); 
    340     gbm_index = GB_QUARK_2_GBMINDEX(Main, keyq); 
    341     gbd = (GBDATA *) gbm_get_mem(sizeof(GBDATA), gbm_index); 
     338 
     339    long    gbm_index = GB_QUARK_2_GBMINDEX(Main, keyq); 
     340    GBDATA *gbd       = (GBDATA *) gbm_get_mem(sizeof(GBDATA), gbm_index); 
     341 
    342342    GB_GBM_INDEX(gbd) = gbm_index; 
    343343    SET_GB_FATHER(gbd, father); 
    344344 
    345     switch (type) 
    346     { 
    347         case GB_STRING_SHRT:    type = GB_STRING; 
     345    switch (type) { 
     346        case GB_STRING_SHRT: 
     347            type = GB_STRING; 
     348            // fall-through 
    348349        case GB_STRING: 
    349             if (!buffer) buffer = strdup("1234"); 
    350             p = buffer; 
    351             while (!(++(*p))) { (*p)++; p++; if (!(*p)) break; } 
    352             GB_SETSMDMALLOC(gbd, 5, 5, buffer); 
     350            GB_SETSMDMALLOC(gbd, 6, 7, "<NONE>"); 
    353351            break; 
    354352        case GB_LINK: 
    355             buffer[0] = ':'; 
    356             buffer[1] = 0; 
    357             GB_SETSMDMALLOC(gbd, 0, 0, buffer); 
     353            GB_SETSMDMALLOC(gbd, 1, 2, ":"); 
    358354            break; 
    359         default:        break; 
     355        default: 
     356            break; 
    360357    } 
    361358    gbd->flags.type = type; 
  • trunk/ARBDB/ad_k_prot.h

    r6533 r6654  
    1515 
    1616/* adstring.cxx */ 
    17 void GBK_dump_backtrace(FILE *out, GB_ERROR error); 
     17class BackTraceInfo *GBK_get_backtrace(size_t skipFramesAtBottom); 
     18void GBK_dump_former_backtrace(class BackTraceInfo *trace, FILE *out, GB_CSTR message); 
     19void GBK_free_backtrace(class BackTraceInfo *trace); 
     20void GBK_dump_backtrace(FILE *out, GB_CSTR message); 
    1821void GBK_install_SIGSEGV_handler(bool dump_backtrace); 
    1922bool GBK_raises_SIGSEGV(void (*cb)(void)); 
  • trunk/ARBDB/ad_load.cxx

    r6649 r6654  
    945945            case GB_INTS: 
    946946            case GB_FLOATS: 
    947                 size = gb_read_number(in); 
    948                 memsize =  gb_read_number(in); 
     947                size    = gb_read_number(in); 
     948                memsize = gb_read_number(in); 
     949 
    949950                DEBUG_DUMP_INDENTED(deep, GBS_global_string("size=%li memsize=%li", size, memsize)); 
    950951                if (GB_CHECKINTERN(size, memsize)) { 
     
    954955                else { 
    955956                    GB_SETEXTERN(gb2); 
    956                     p = gbm_get_mem((size_t)memsize+1, GB_GBM_INDEX(gb2)); // ralf: added +1 because decompress ran out of this block 
     957                    // memsize++; // ralf: added +1 because decompress ran out of this block (cant solve like this - breaks memory management!) 
     958                    p = gbm_get_mem((size_t)memsize, GB_GBM_INDEX(gb2));  
    957959                } 
    958960                i = fread(p, 1, (size_t)memsize, in); 
     
    12001202 
    12011203                        gb_main_array[new_idx] = Main; 
     1204 
     1205                        gbm_free_mem((char*)Main->data, sizeof(GBCONTAINER), GB_QUARK_2_GBMINDEX(Main, 0)); 
     1206 
    12021207                        Main->data = newGbd; 
    12031208                        father->main_idx = new_idx; 
     
    13781383    bool           dbCreated           = false; 
    13791384 
    1380     GBK_install_SIGSEGV_handler(true); 
    1381  
    13821385    if (!opent) opentype = gb_open_all; 
    13831386    else if (strchr(opent, 'w')) opentype = gb_open_all; 
     
    14511454    } 
    14521455 
    1453     gbm_init_mem(); 
     1456    if (GB_install_pid(1)) return 0; 
     1457     
    14541458    GB_init_gb(); 
    1455  
    1456     if (GB_install_pid(1)) return 0; 
    14571459 
    14581460    Main = gb_make_gb_main_type(path); 
  • trunk/ARBDB/ad_prot.h

    r6646 r6654  
    237237char *GB_check_out_buffer(GB_CBUFFER buffer); 
    238238GB_BUFFER GB_give_other_buffer(GB_CBUFFER buffer, long size); 
     239void GB_exit_gb(void); 
    239240void GB_init_gb(void); 
    240241void GB_atclose(GBDATA *gbd, void (*fun)(GBDATA *gb_main, void *client_data), void *client_data); 
  • trunk/ARBDB/adcompr.cxx

    r6524 r6654  
    191191} 
    192192 
    193 struct gb_compress_list *gb_build_compress_list(const unsigned char *data, long short_flag, long *size) 
     193gb_compress_list *gb_build_compress_list(const unsigned char *data, long short_flag, long *size) 
    194194{ 
    195195    struct gb_compress_list *list; 
  • trunk/ARBDB/admalloc.cxx

    r6634 r6654  
    1515#include <unistd.h> 
    1616#include <climits> 
     17#include <set> 
    1718 
    1819#include "gb_storage.h" 
    1920 
    20  
    2121// #define DUMP_MEMBLKS 
     22// #define DUMP_MEMBLKS_AT_EXIT 
     23 
    2224#ifndef NDEBUG 
    23 //  #define TEST_MEMBLKS 
     25// #define TEST_MEMBLKS 
     26// #define TRACE_ALLOCS 
    2427#endif 
    2528 
     
    185188} 
    186189 
    187  
    188 void gbm_init_mem() 
    189 { 
    190     int i; 
    191     static int flag = 0; 
    192  
    193     if (flag) return; 
    194  
    195     flag = 1; 
    196     for (i=0; i<GBM_MAX_INDEX; i++) 
    197     { 
    198         memset((char *)&gbm_global[i], 0, sizeof(struct gbm_struct)); 
    199         gbm_global[i].tables[0] = 0;        // CORE zero get mem 
    200     } 
    201     gbm_global2.old_sbrk = (char *)sbrk(0); 
    202  
    203     /* init GBB: 
    204      * --------- */ 
    205  
    206     gbb_cluster[0].size  = GBB_MINSIZE; 
    207     gbb_cluster[0].first = NULL; 
    208  
    209     for (i=1; i<GBB_CLUSTERS; i++) 
    210     { 
    211         long nextSize = gbb_cluster[i-1].size * (100+GBB_INCR); 
    212  
    213         nextSize /= 100; 
    214         nextSize >>= GBB_ALIGN; 
    215         nextSize ++; 
    216         nextSize <<= GBB_ALIGN; 
    217  
    218         gbb_cluster[i].size  = nextSize; 
    219         gbb_cluster[i].first = NULL; 
    220     } 
    221  
    222     // last cluster contains ALL bigger blocks 
    223  
    224     gbb_cluster[GBB_CLUSTERS].size  = INT_MAX; 
    225     gbb_cluster[GBB_CLUSTERS].first = NULL; 
    226 } 
     190#ifdef TRACE_ALLOCS 
     191 
     192class AllocLogEntry { 
     193    char   *block; 
     194    size_t  size; 
     195    long    index; 
     196 
     197    mutable BackTraceInfo *trace; 
     198 
     199public: 
     200    AllocLogEntry(char *block_, size_t size_, long index_, bool do_trace) 
     201        : block(block_) 
     202        , size(size_) 
     203        , index(index_) 
     204        , trace(do_trace ? GBK_get_backtrace(5) : NULL) 
     205    { } 
     206    AllocLogEntry(const AllocLogEntry& other) 
     207        : block(other.block) 
     208        , size(other.size) 
     209        , index(other.index) 
     210        , trace(other.trace) 
     211    { 
     212        other.trace = NULL; 
     213    } 
     214    ~AllocLogEntry() { if (trace) GBK_free_backtrace(trace); } 
     215 
     216    size_t get_size() const { return size; } 
     217    long get_index() const { return index; } 
     218     
     219    bool operator<(const AllocLogEntry& other) const { return block < other.block; } 
     220    void dump(FILE *out, GB_CSTR message) const { GBK_dump_former_backtrace(trace, out, message); } 
     221}; 
     222 
     223typedef std::set<AllocLogEntry> AllocLogEntries; 
     224 
     225class AllocLogger { 
     226    AllocLogEntries entries; 
     227 
     228    const AllocLogEntry *existingEntry(char *block) { 
     229        AllocLogEntries::const_iterator found = entries.find(AllocLogEntry(block, 0, 0, false)); 
     230         
     231        return found == entries.end() ? NULL : &*found; 
     232    } 
     233 
     234public: 
     235    AllocLogger() { 
     236    } 
     237    ~AllocLogger() { 
     238        size_t count = entries.size(); 
     239        if (count) { 
     240            fprintf(stderr, "%zu non-freed blocks:\n", count); 
     241            AllocLogEntries::const_iterator end = entries.end(); 
     242            for (AllocLogEntries::const_iterator entry = entries.begin(); entry != end; ++entry) { 
     243                entry->dump(stderr, "block was allocated from here"); 
     244            } 
     245        } 
     246    } 
     247 
     248    void allocated(char *block, size_t size, long index) { 
     249        const AllocLogEntry *exists = existingEntry(block); 
     250        if (exists) { 
     251            GBK_dump_backtrace(stderr, "Block allocated again"); 
     252            exists->dump(stderr, "Already allocated from here"); 
     253        } 
     254        else { 
     255            entries.insert(AllocLogEntry(block, size, index, true)); 
     256        } 
     257    } 
     258    void freed(char *block, size_t size, long index) { 
     259        const AllocLogEntry *exists = existingEntry(block); 
     260        if (!exists) { 
     261            if (!gb_isMappedMemory(block)) { 
     262                gb_assert(0); 
     263                // GBK_dump_backtrace(stderr, "Tried to free unallocated block"); 
     264            } 
     265        } 
     266        else { 
     267            gb_assert(exists->get_size() == size); 
     268            gb_assert(exists->get_index() == index); 
     269            entries.erase(*exists); 
     270        } 
     271    } 
     272}; 
     273 
     274static AllocLogger allocLogger; 
     275 
     276#endif 
     277 
     278inline void free_gbm_table(gbm_table_struct *table) { 
     279    while (table) { 
     280        gbm_table_struct *next = table->next; 
     281         
     282        free(table); 
     283        table = next; 
     284    } 
     285} 
     286 
     287static bool gbm_mem_initialized = false; 
     288 
     289void gbm_flush_mem() { 
     290    gb_assert(gbm_mem_initialized); 
     291 
     292    for (int i = 0; i<GBM_MAX_INDEX; ++i) { 
     293        gbm_struct& gbm             = gbm_global[i]; 
     294        bool        have_used_items = false; 
     295 
     296        for (int t = 0; t < GBM_MAX_TABLES; t++) { 
     297            if (gbm.useditems[t]) { 
     298                have_used_items = true; 
     299                break; 
     300            } 
     301        } 
     302 
     303        if (!have_used_items) { 
     304            free_gbm_table(gbm.first); 
     305            memset((char*)&gbm, 0, sizeof(gbm)); 
     306        } 
     307    } 
     308} 
     309 
     310void gbm_init_mem() { 
     311    if (!gbm_mem_initialized) { 
     312        for (int i = 0; i<GBM_MAX_INDEX; ++i) { 
     313            memset((char *)&gbm_global[i], 0, sizeof(struct gbm_struct)); 
     314            gbm_global[i].tables[0] = 0;        // CORE zero get mem 
     315        } 
     316        gbm_global2.old_sbrk = (char *)sbrk(0); 
     317 
     318        /* init GBB: 
     319         * --------- */ 
     320 
     321        gbb_cluster[0].size  = GBB_MINSIZE; 
     322        gbb_cluster[0].first = NULL; 
     323 
     324        for (int i = 1; i<GBB_CLUSTERS; ++i) { 
     325            long nextSize = gbb_cluster[i-1].size * (100+GBB_INCR); 
     326 
     327            nextSize /= 100; 
     328            nextSize >>= GBB_ALIGN; 
     329            nextSize ++; 
     330            nextSize <<= GBB_ALIGN; 
     331 
     332            gbb_cluster[i].size  = nextSize; 
     333            gbb_cluster[i].first = NULL; 
     334        } 
     335 
     336        // last cluster contains ALL bigger blocks 
     337 
     338        gbb_cluster[GBB_CLUSTERS].size  = INT_MAX; 
     339        gbb_cluster[GBB_CLUSTERS].first = NULL; 
     340 
     341        gbm_mem_initialized = true; 
     342    } 
     343} 
     344 
     345struct ARBDB_memory_manager { 
     346    ARBDB_memory_manager() { 
     347        gb_assert(!gbm_mem_initialized); // there may be only one instance! 
     348        gbm_init_mem(); 
     349    } 
     350    ~ARBDB_memory_manager() { 
     351#if defined(DUMP_MEMBLKS_AT_EXIT) 
     352        printf("memory at exit:\n"); 
     353        gbm_debug_mem(); 
     354#endif // DUMP_MEMBLKS_AT_EXIT 
     355        gbm_flush_mem(); 
     356#if defined(DUMP_MEMBLKS_AT_EXIT) 
     357        printf("memory at exit (after flush):\n"); 
     358        gbm_debug_mem(); 
     359#endif // DUMP_MEMBLKS_AT_EXIT 
     360    } 
     361}; 
     362static ARBDB_memory_manager memman; 
    227363 
    228364void GB_memerr() 
     
    424560 
    425561        erg = gbm_get_memblk((size_t)nsize); 
    426         return erg; 
    427     } 
    428  
    429     pos = nsize >> GBM_LD_ALIGNED; 
    430     if ((gds = ggi->tables[pos])) 
    431     { 
    432         ggi->tablecnt[pos]--; 
    433         erg = (char *)gds; 
    434         if (gds->magic != GBM_MAGIC) 
     562    } 
     563    else { 
     564        pos = nsize >> GBM_LD_ALIGNED; 
     565        if ((gds = ggi->tables[pos])) 
    435566        { 
    436             printf("%lX!= %lX\n", gds->magic, (long)GBM_MAGIC); 
    437             GB_internal_error("Dangerous internal error: Inconsistent database: " 
    438                               "Do not overwrite old files with this database"); 
    439         } 
    440         ggi->tables[pos] = ggi->tables[pos]->next; 
    441     } 
    442     else 
    443     { 
    444         if (ggi->size < nsize) 
     567            ggi->tablecnt[pos]--; 
     568            erg = (char *)gds; 
     569            if (gds->magic != GBM_MAGIC) 
     570            { 
     571                printf("%lX!= %lX\n", gds->magic, (long)GBM_MAGIC); 
     572                GB_internal_error("Dangerous internal error: Inconsistent database: " 
     573                                  "Do not overwrite old files with this database"); 
     574            } 
     575            ggi->tables[pos] = ggi->tables[pos]->next; 
     576        } 
     577        else 
    445578        { 
    446             struct gbm_table_struct *gts = (struct gbm_table_struct *)GB_MEMALIGN(GBM_SYSTEM_PAGE_SIZE, GBM_TABLE_SIZE); 
    447  
    448             if (!gts) { GB_memerr(); return NULL; } 
    449  
    450             memset((char *)gts, 0, GBM_TABLE_SIZE); 
    451             ggi->gds = &gts->data[0]; 
    452             gts->next = ggi->first; // link tables 
    453             ggi->first = gts; 
    454             ggi->size = GBM_TABLE_SIZE - sizeof(void *); 
    455             ggi->allsize += GBM_TABLE_SIZE; 
    456         } 
    457         erg = (char *)ggi->gds; 
    458         ggi->gds = (struct gbm_data_struct *)(((char *)ggi->gds) + nsize); 
    459         ggi->size -= (size_t)nsize; 
    460     } 
    461  
    462     ggi->useditems[pos]++; 
    463     memset(erg, 0, nsize); 
    464  
     579            if (ggi->size < nsize) 
     580            { 
     581                struct gbm_table_struct *gts = (struct gbm_table_struct *)GB_MEMALIGN(GBM_SYSTEM_PAGE_SIZE, GBM_TABLE_SIZE); 
     582 
     583                if (!gts) { GB_memerr(); return NULL; } 
     584 
     585                memset((char *)gts, 0, GBM_TABLE_SIZE); 
     586                ggi->gds = &gts->data[0]; 
     587                gts->next = ggi->first; // link tables 
     588                ggi->first = gts; 
     589                ggi->size = GBM_TABLE_SIZE - sizeof(void *); 
     590                ggi->allsize += GBM_TABLE_SIZE; 
     591            } 
     592            erg = (char *)ggi->gds; 
     593            ggi->gds = (struct gbm_data_struct *)(((char *)ggi->gds) + nsize); 
     594            ggi->size -= (size_t)nsize; 
     595        } 
     596 
     597        ggi->useditems[pos]++; 
     598        memset(erg, 0, nsize); // act like calloc() 
     599    } 
     600 
     601#ifdef TRACE_ALLOCS 
     602    allocLogger.allocated(erg, size, index); 
     603#endif 
    465604    return erg; 
    466605} 
     
    475614    ggi = & gbm_global[index]; 
    476615    nsize = (size + (GBM_ALIGNED - 1)) & (-GBM_ALIGNED); 
     616 
     617#ifdef TRACE_ALLOCS 
     618    allocLogger.freed(data, size, index); 
     619#endif 
    477620 
    478621    if (nsize > GBM_MAX_SIZE) 
     
    533676#endif // MEMORY_TEST==0 
    534677 
    535 void gbm_debug_mem(GB_MAIN_TYPE *Main) 
    536 { 
     678void gbm_debug_mem() { 
    537679    int i; 
    538680    int index; 
     
    551693            total += i * GBM_ALIGNED * (int) ggi->useditems[i]; 
    552694 
    553             if (ggi->useditems[i] || ggi->tablecnt[i]) 
    554             { 
    555                 { 
    556                     int j; 
    557                     for (j = index; j < Main->keycnt; j+=GBM_MAX_INDEX) { 
    558                         if (Main->keys[j].key) { 
    559                             printf("%15s", Main->keys[j].key); 
    560                         } 
    561                         else { 
    562                             printf("%15s", "*** unused ****"); 
    563                         } 
    564                     } 
    565                 } 
     695            if (ggi->useditems[i] || ggi->tablecnt[i]) { 
    566696                printf("\t'I=%3i' 'Size=%3i' * 'Items %4i' = 'size %7i'    'sum=%7li'   'totalsum=%7li' :   Free %3i\n", 
    567697                       index, 
     
    574704            } 
    575705        } 
    576         if (ggi->extern_data_size) 
    577         { 
     706        if (ggi->extern_data_size) { 
    578707            index_total += ggi->extern_data_size; 
    579708            total += ggi->extern_data_size; 
    580             printf("\t\t'I=%3i' External Data Items=%3li = Sum=%3li  'sum=%7li'  'total=%7li\n", 
     709            printf("\t'I=%3i' External Data Items=%3li = Sum=%3li  'sum=%7li'  'total=%7li\n", 
    581710                   index, 
    582711                   ggi->extern_data_items, 
     
    595724    } 
    596725} 
     726 
     727// -------------------------------------------------------------------------------- 
     728 
     729#if (UNIT_TESTS == 1) && 0 
     730 
     731#include <test_unit.h> 
     732 
     733void TEST_ARBDB_memory() { // not a real unit test - just was used for debugging 
     734#define ALLOCS 69 
     735    long *blocks[ALLOCS]; 
     736 
     737#if (MEMORY_TEST == 0) 
     738    printf("Before allocations:\n"); 
     739    gbm_debug_mem(); 
     740 
     741#if 1     
     742    static int16_t non_alloc[75];                   // 150 byte 
     743    gbm_put_memblk((char*)non_alloc, sizeof(non_alloc)); 
     744 
     745    printf("Added one non-allocated block:\n"); 
     746    gbm_debug_mem(); 
     747#endif 
     748#endif 
     749 
     750    for (int pass = 1; pass <= 2; ++pass) { 
     751        long allocs = 0; 
     752 
     753        for (size_t size = 10; size<5000; size += size/3) { 
     754            for (long index = 0; index<3; ++index) { 
     755                if (pass == 1) { 
     756                    long *block = (long*)gbm_get_mem(size, index); 
     757 
     758                    block[0] = size; 
     759                    block[1] = index; 
     760 
     761                    blocks[allocs++] = block; 
     762                } 
     763                else { 
     764                    long *block = blocks[allocs++]; 
     765                    gbm_free_mem((char*)block, (size_t)block[0], block[1]); 
     766                } 
     767            } 
     768        } 
     769 
     770#if (MEMORY_TEST == 0) 
     771        if (pass == 1) { 
     772            printf("%li memory blocks allocated:\n", allocs); 
     773            gbm_debug_mem(); 
     774        } 
     775        else { 
     776            printf("Memory freed:\n"); 
     777            gbm_debug_mem(); 
     778        } 
     779        printf("Memory flushed:\n"); 
     780        gbm_flush_mem(); 
     781        gbm_debug_mem(); 
     782#endif 
     783 
     784        gb_assert(allocs == ALLOCS); 
     785    } 
     786 
     787    GBK_dump_backtrace(stderr, "test"); 
     788} 
     789 
     790 
     791#endif 
  • trunk/ARBDB/adstring.cxx

    r6640 r6654  
    167167GB_ERROR GB_await_error() { 
    168168    if (GB_error_buffer) { 
    169         static char *err = 0; 
    170         reassign(err, GB_error_buffer); 
    171         return err; 
     169        static SmartMallocPtr(char) err; 
     170        err             = GB_error_buffer; 
     171        GB_error_buffer = NULL; 
     172        return &*err; 
    172173    } 
    173174    gb_assert(0);               // please correct error handling 
     
    11131114#define MAX_BACKTRACE 66 
    11141115 
    1115 void GBK_dump_backtrace(FILE *out, GB_ERROR error) { 
    1116     void   *array[MAX_BACKTRACE]; 
    1117     size_t  size = backtrace(array, MAX_BACKTRACE); // get void*'s for all entries on the stack 
    1118  
    1119     if (!out) out = stderr; 
    1120  
    1121     // print out all the frames to out 
    1122     fprintf(out, "\n-------------------- ARB-backtrace for '%s':\n", error); 
    1123     backtrace_symbols_fd(array, size, fileno(out)); 
    1124     if (size == MAX_BACKTRACE) fputs("[stack truncated to avoid deadlock]\n", out); 
    1125     fputs("-------------------- End of backtrace\n", out); 
    1126     fflush(out); 
     1116class BackTraceInfo { 
     1117    void   **array; 
     1118    size_t  size; 
     1119public: 
     1120    BackTraceInfo(size_t skipFramesAtBottom) { 
     1121        void *tmp[MAX_BACKTRACE]; 
     1122        size = backtrace(tmp, MAX_BACKTRACE); 
     1123 
     1124        size_t ssize = skipFramesAtBottom*sizeof(*array); 
     1125        size_t msize = size*sizeof(*array) - ssize; 
     1126 
     1127        gb_assert(msize>0); 
     1128         
     1129        array = (void**)malloc(msize); 
     1130        memcpy(array, tmp+skipFramesAtBottom, msize); 
     1131    } 
     1132    ~BackTraceInfo() { free(array); } 
     1133 
     1134    void dump(FILE *out, GB_CSTR message) { 
     1135        // print out all the frames to out 
     1136        fprintf(out, "\n-------------------- ARB-backtrace '%s':\n", message); 
     1137        backtrace_symbols_fd(array, size, fileno(out)); 
     1138        if (size == MAX_BACKTRACE) fputs("[stack truncated to avoid deadlock]\n", out); 
     1139        fputs("-------------------- End of backtrace\n", out); 
     1140        fflush(out); 
     1141    } 
     1142}; 
     1143 
     1144class BackTraceInfo *GBK_get_backtrace(size_t skipFramesAtBottom) { 
     1145    return new BackTraceInfo(skipFramesAtBottom); 
     1146} 
     1147void GBK_dump_former_backtrace(class BackTraceInfo *trace, FILE *out, GB_CSTR message) { 
     1148    trace->dump(out, message); 
     1149} 
     1150void GBK_free_backtrace(class BackTraceInfo *trace) { 
     1151    delete trace; 
     1152} 
     1153 
     1154void GBK_dump_backtrace(FILE *out, GB_CSTR message) { 
     1155    BackTraceInfo trace(0); 
     1156    trace.dump(out ? out : stderr, message); 
    11271157} 
    11281158 
  • trunk/ARBDB/arbdb.cxx

    r6648 r6654  
    285285}; 
    286286 
     287void GB_exit_gb() { 
     288    if (gb_local) { 
     289        gb_assert(gb_local->openedDBs == gb_local->closedDBs); 
     290 
     291        free(gb_local->bitcompress); 
     292        gb_free_compress_tree(gb_local->bituncompress); 
     293        free(gb_local->write_buffer); 
     294 
     295        free(check_out_buffer(&gb_local->buf2)); 
     296        free(check_out_buffer(&gb_local->buf1)); 
     297 
     298        gbm_free_mem((char*)gb_local, sizeof(*gb_local), 0); 
     299        gb_local = NULL; 
     300 
     301        gbm_flush_mem(); 
     302    } 
     303} 
     304 
    287305void GB_init_gb() { 
    288306    if (!gb_local) { 
    289         gb_local = (struct gb_local_data *)gbm_get_mem(sizeof(struct gb_local_data), 0); 
     307        GBK_install_SIGSEGV_handler(true);          // never uninstalled 
     308 
     309        gbm_init_mem(); 
     310 
     311        gb_local = (gb_local_data *)gbm_get_mem(sizeof(gb_local_data), 0); 
    290312 
    291313        init_buffer(&gb_local->buf1, 4000); 
     
    300322        gb_local->bitcompress   = gb_build_compress_list(GB_BIT_compress_data, 1, &(gb_local->bc_size)); 
    301323 
     324        gb_local->openedDBs = 0; 
     325        gb_local->closedDBs = 0; 
     326 
    302327#ifdef ARBDB_SIZEDEBUG 
    303328        arbdb_stat = (long *)GB_calloc(sizeof(long), 1000); 
    304329#endif 
     330 
     331        atexit(GB_exit_gb); 
    305332    } 
    306333} 
     
    969996{ 
    970997    char *d; 
    971     long memsize[2]; 
     998    long memsize; 
    972999 
    9731000    GB_TEST_WRITE(gbd, GB_BITS, "GB_write_bits"); 
     
    9751002    gb_save_extern_data_in_ts(gbd); 
    9761003 
    977     d = gb_compress_bits(bits, size, (const unsigned char *)c_0, memsize); 
     1004    d = gb_compress_bits(bits, size, (const unsigned char *)c_0, &memsize); 
    9781005    gbd->flags.compressed_data = 1; 
    979     GB_SETSMDMALLOC(gbd, size, memsize[0], d); 
     1006    GB_SETSMDMALLOC(gbd, size, memsize, d); 
    9801007    gb_touch_entry(gbd, GB_NORMAL_CHANGE); 
    9811008    GB_DO_CALLBACKS(gbd); 
     
    25992626 
    26002627GB_ERROR GB_print_debug_information(void */*dummy_AW_root*/, GBDATA *gb_main) { 
    2601     int i; 
    26022628    GB_MAIN_TYPE *Main = GB_MAIN(gb_main); 
    26032629    GB_push_transaction(gb_main); 
    2604     for (i=0; i<Main->keycnt; i++) { 
     2630    for (int i=0; i<Main->keycnt; i++) { 
    26052631        if (Main->keys[i].key) { 
    26062632            printf("%3i %20s    nref %i\n", i, Main->keys[i].key, (int)Main->keys[i].nref); 
     
    26102636        } 
    26112637    } 
    2612     gbm_debug_mem(Main); 
     2638    gbm_debug_mem(); 
    26132639    GB_pop_transaction(gb_main); 
    26142640    return 0; 
  • trunk/ARBDB/gb_local.h

    r6636 r6654  
    4242struct gb_scandir; 
    4343struct gb_transaction_save; 
     44struct gb_compress_list; 
    4445 
    4546// ------------------- 
  • trunk/ARBDB/gb_localdata.h

    r6329 r6654  
    5555        GBDATA *gb_main; 
    5656    } gbl; 
     57 
     58    int openedDBs;  
     59    int closedDBs; 
    5760}; 
    5861 
  • trunk/ARBDB/gb_prot.h

    r6648 r6654  
    8888 
    8989/* admalloc.cxx */ 
     90void gbm_flush_mem(void); 
    9091void gbm_init_mem(void); 
    91 void gbm_debug_mem(GB_MAIN_TYPE *Main); 
     92void gbm_debug_mem(void); 
    9293 
    9394/* adoptimize.cxx */ 
     
    176177struct gb_compress_tree *gb_build_uncompress_tree(const unsigned char *data, long short_flag, char **end); 
    177178void gb_free_compress_tree(struct gb_compress_tree *tree); 
    178 struct gb_compress_list *gb_build_compress_list(const unsigned char *data, long short_flag, long *size); 
     179gb_compress_list *gb_build_compress_list(const unsigned char *data, long short_flag, long *size); 
    179180char *gb_compress_bits(const char *source, long size, const unsigned char *c_0, long *msize); 
    180181GB_BUFFER gb_uncompress_bits(const char *source, long size, char c_0, char c_1);