Added stacktrace support with --enable-stack-trace option.
authorPekka Riikonen <priikone@silcnet.org>
Mon, 17 Jun 2002 19:54:17 +0000 (19:54 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 17 Jun 2002 19:54:17 +0000 (19:54 +0000)
Fixed some memory leaks around the tree.

25 files changed:
CHANGES
acconfig.h.pre
apps/silcd/server.c
apps/silcd/server_internal.h
apps/silcd/serverconfig.c
apps/silcd/silcd.c
configure.in.pre
lib/silccrypt/silccipher.c
lib/silccrypt/silccipher.h
lib/silccrypt/silchash.c
lib/silccrypt/silchash.h
lib/silccrypt/silchmac.c
lib/silccrypt/silchmac.h
lib/silccrypt/silcpkcs.c
lib/silccrypt/silcpkcs.h
lib/silccrypt/silcrng.c
lib/silcutil/Makefile.am
lib/silcutil/silcconfig.c
lib/silcutil/silclog.c
lib/silcutil/silclog.h
lib/silcutil/silcmemory.c
lib/silcutil/silcmemory.h
lib/silcutil/silcschedule.c
lib/silcutil/stacktrace.c [new file with mode: 0644]
lib/silcutil/stacktrace.h [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 21346a55b4eb73939e329f23717bc3f52b274774..f33435d5a1ad5e04cbafbcfe04a58bf23446e636 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,13 @@
+Mon Jun 17 21:30:55 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
+
+       * Added --enable-stack-trace option to configure.  Added
+         memory allocation stack trace support.  Added files
+         lib/silcutil/stacktrace.[ch].  Affected files are
+         lib/silcutil/silcmemory.[ch].
+
+       * Fixed memory leaks from libraries and server.  Affected
+         files around the tree.
+
 Sun Jun 16 11:49:45 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
 
        * Added SILC_MESSAGE_FLAG_UTF8 to the protocol specs and the
index 5b61eb24cd86ebbec69f8e1c9a4204d7decd7344..bd9e10dadf3addaf70b10eaf8d1c5f6129d72cd6 100644 (file)
@@ -15,6 +15,7 @@
 
 /* Debugging */
 #undef SILC_DEBUG
+#undef SILC_STACKTRACE
 
 /* Multi-thread support */
 #undef SILC_HAVE_PTHREAD
index 5cbe0bbcd3574204aafa86378d00c6680c63b520..10530e00d7d4cacffbb5f65e07290a0eb3a5b6e9 100644 (file)
@@ -77,42 +77,66 @@ int silc_server_alloc(SilcServer *new_server)
 
 void silc_server_free(SilcServer server)
 {
-  if (server) {
+  int i;
+
+  if (!server)
+    return;
+
 #ifdef SILC_SIM
+  {
     SilcSim sim;
-
+    
     while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
       silc_dlist_del(server->sim, sim);
       silc_sim_free(sim);
     }
     silc_dlist_uninit(server->sim);
+  }
 #endif
 
-    silc_server_config_unref(&server->config_ref);
-    if (server->rng)
-      silc_rng_free(server->rng);
-    if (server->pkcs)
-      silc_pkcs_free(server->pkcs);
-    if (server->public_key)
-      silc_pkcs_public_key_free(server->public_key);
-    if (server->private_key)
-      silc_pkcs_private_key_free(server->private_key);
-    if (server->pending_commands)
-      silc_dlist_uninit(server->pending_commands);
-    if (server->id_entry)
-      silc_idlist_del_server(server->local_list, server->id_entry);
-
-    silc_idcache_free(server->local_list->clients);
-    silc_idcache_free(server->local_list->servers);
-    silc_idcache_free(server->local_list->channels);
-    silc_idcache_free(server->global_list->clients);
-    silc_idcache_free(server->global_list->servers);
-    silc_idcache_free(server->global_list->channels);
-    silc_hash_table_free(server->watcher_list);
-
-    silc_free(server->sockets);
-    silc_free(server);
+  for (i = 0; i < server->config->param.connections_max; i++) {
+    if (!server->sockets[i])
+      continue;
+    silc_socket_free(server->sockets[i]);
   }
+  silc_free(server->sockets);
+
+  silc_server_config_unref(&server->config_ref);
+  if (server->rng)
+    silc_rng_free(server->rng);
+  if (server->pkcs)
+    silc_pkcs_free(server->pkcs);
+  if (server->public_key)
+    silc_pkcs_public_key_free(server->public_key);
+  if (server->private_key)
+    silc_pkcs_private_key_free(server->private_key);
+  if (server->pending_commands)
+    silc_dlist_uninit(server->pending_commands);
+  if (server->id_entry)
+    silc_idlist_del_server(server->local_list, server->id_entry);
+
+  silc_idcache_free(server->local_list->clients);
+  silc_idcache_free(server->local_list->servers);
+  silc_idcache_free(server->local_list->channels);
+  silc_idcache_free(server->global_list->clients);
+  silc_idcache_free(server->global_list->servers);
+  silc_idcache_free(server->global_list->channels);
+  silc_hash_table_free(server->watcher_list);
+
+  silc_hash_free(server->md5hash);
+  silc_hash_free(server->sha1hash);
+  silc_hmac_unregister_all();
+  silc_hash_unregister_all();
+  silc_cipher_unregister_all();
+  silc_pkcs_unregister_all();
+
+  silc_free(server->local_list);
+  silc_free(server->global_list);
+  silc_free(server->server_name);
+  silc_free(server->id_string);
+  silc_free(server->purge_i);
+  silc_free(server->purge_g);
+  silc_free(server);
 }
 
 /* Creates a new server listener. */
@@ -130,15 +154,16 @@ static bool silc_server_listen(SilcServer server, const char *server_ip,
 }
 
 /* Adds a secondary listener. */
+
 bool silc_server_init_secondary(SilcServer server)
 {
-  int sock=0, sock_list[server->config->param.connections_max];
+  int sock = 0, sock_list[server->config->param.connections_max];
   SilcSocketConnection newsocket = NULL;
   SilcServerConfigServerInfoInterface *interface;
 
   for (interface = server->config->server_info->secondary; interface; 
        interface = interface->next, sock++) {
-         
+
     if (!silc_server_listen(server,
        interface->server_ip, interface->port, &sock_list[sock]))
       goto err;
@@ -148,8 +173,8 @@ bool silc_server_init_secondary(SilcServer server)
 
     /* Add ourselves also to the socket table. The entry allocated above
        is sent as argument for fast referencing in the future. */
-    silc_socket_alloc(sock_list[sock], 
-               SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+    silc_socket_alloc(sock_list[sock],
+                     SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
     server->sockets[sock_list[sock]] = newsocket;
 
     /* Perform name and address lookups to resolve the listenning address
@@ -168,23 +193,20 @@ bool silc_server_init_secondary(SilcServer server)
         newsocket->hostname = strdup(newsocket->ip);
     }
     newsocket->port = silc_net_get_local_port(sock);
-    
+
     newsocket->user_data = (void *)server->id_entry;
     silc_schedule_task_add(server->schedule, sock_list[sock],
                         silc_server_accept_new_connection,
                         (void *)server, 0, 0,
                         SILC_TASK_FD,
                         SILC_TASK_PRI_NORMAL);
-
   }
 
   return TRUE;
-  
-err:
 
+ err:
   do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
   return FALSE;
-
 }
 
 /* Initializes the entire SILC server. This is called always before running
@@ -394,7 +416,7 @@ bool silc_server_init(SilcServer server)
      and removes the expired cache entries. */
 
   /* Clients local list */
-  purge = silc_calloc(1, sizeof(*purge));
+  server->purge_i = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->local_list->clients;
   purge->schedule = server->schedule;
   purge->timeout = 600;
@@ -404,7 +426,7 @@ bool silc_server_init(SilcServer server)
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* Clients global list */
-  purge = silc_calloc(1, sizeof(*purge));
+  server->purge_g = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->global_list->clients;
   purge->schedule = server->schedule;
   purge->timeout = 300;
index c435c77622a9a0b46207d8557c643bbdf57ce4a7..7b27b6c31def002196c4b01047712288137f9ad1 100644 (file)
@@ -129,6 +129,10 @@ struct SilcServerStruct {
   /* Pending command queue */
   SilcDList pending_commands;
 
+  /* Purge context for disconnected clients */
+  SilcIDListPurge purge_i;
+  SilcIDListPurge purge_g;
+
 #ifdef SILC_SIM
   /* SIM (SILC Module) list */
   SilcDList sim;
index d9fe747adb60d02bd2a43f4b5bb194f00c68754c..505e87622c31d8dc5803be5cb7f0ec5eea38a02f 100644 (file)
@@ -1314,6 +1314,15 @@ void silc_server_config_destroy(SilcServerConfig config)
     silc_free(config->logging_errors->file);
   if (config->logging_fatals)
     silc_free(config->logging_fatals->file);
+  silc_free(config->logging_info);
+  silc_free(config->logging_warnings);
+  silc_free(config->logging_errors);
+  silc_free(config->logging_fatals);
+
+  silc_log_set_file(SILC_LOG_INFO, NULL, 0, NULL);
+  silc_log_set_file(SILC_LOG_WARNING, NULL, 0, NULL);
+  silc_log_set_file(SILC_LOG_ERROR, NULL, 0, NULL);
+  silc_log_set_file(SILC_LOG_FATAL, NULL, 0, NULL);
 
   /* Destroy the ServerInfo struct */
   if (config->server_info) {
@@ -1338,6 +1347,7 @@ void silc_server_config_destroy(SilcServerConfig config)
     silc_free(si->pid_file);
     silc_pkcs_public_key_free(si->public_key);
     silc_pkcs_private_key_free(si->private_key);
+    silc_free(si);
   }
 
   /* Now let's destroy the lists */
index 6654ef9534ad11840646415299b839a691557a77..c1a5277e570ee2d36fe1c8e4d2edbc705e85ead2 100644 (file)
@@ -485,8 +485,15 @@ int main(int argc, char **argv)
   /* Flush the logging system */
   silc_log_flush_all();
 
+  silc_free(silcd_config_file);
+  silc_free(opt_identifier);
+  silc_free(opt_keypath);
   exit(0);
+
  fail:
+  silc_free(silcd_config_file);
+  silc_free(opt_identifier);
+  silc_free(opt_keypath);
   exit(1);
 }
 
index a118a41a95fed480ab5d7f5d7f341273e97a25f1..10d3d9937cb5e74fff83f3a6c62894e00fa47038 100644 (file)
@@ -681,6 +681,19 @@ AC_ARG_ENABLE(debug,
 esac ], CFLAGS="-O2 -g $CFLAGS"
         AC_MSG_RESULT(no))
 
+AC_MSG_CHECKING(for enabled stack tracing)
+AC_ARG_ENABLE(debug,
+[  --enable-stack-trace    Enable memory stack trace],
+[ case "${enableval}" in
+  yes) 
+    AC_MSG_RESULT(yes)
+    AC_DEFINE(SILC_STACKTRACE)
+    ;;
+  *)
+    AC_MSG_RESULT(no)
+    ;;
+esac ], AC_MSG_RESULT(no))
+
 #
 # Disable all assembler optimizations
 #
index ba13a02234d91ca6f72f96b958f4562e68247e0c..45a596e5197da563a884c2823dde7343028c74bf 100644 (file)
@@ -174,6 +174,24 @@ bool silc_cipher_register_default(void)
   return TRUE;
 }
 
+bool silc_cipher_unregister_all(void)
+{
+#ifndef SILC_EPOC
+  SilcCipherObject *entry;
+
+  if (!silc_cipher_list)
+    return FALSE;
+
+  silc_dlist_start(silc_cipher_list);
+  while ((entry = silc_dlist_get(silc_cipher_list)) != SILC_LIST_END) {
+    silc_cipher_unregister(entry);
+    if (!silc_cipher_list)
+      break;
+  }
+#endif /* SILC_EPOC */
+  return TRUE;
+}
+
 /* Allocates a new SILC cipher object. Function returns 1 on succes and 0 
    on error. The allocated cipher is returned in new_cipher argument. The
    caller must set the key to the cipher after this function has returned
index f33ef64f3f24cc9dad60bf391cdeb453dd1c428a..01a60393b3a54a3c98988c89b3b8d0ec2b6ec894 100644 (file)
@@ -120,6 +120,7 @@ SilcUInt32 silc_##cipher##_context_len()
 bool silc_cipher_register(const SilcCipherObject *cipher);
 bool silc_cipher_unregister(SilcCipherObject *cipher);
 bool silc_cipher_register_default(void);
+bool silc_cipher_unregister_all(void);
 bool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher);
 void silc_cipher_free(SilcCipher cipher);
 bool silc_cipher_is_supported(const unsigned char *name);
index ed9999a22c27425e6bd6078f7fa5e4cd1bbb6491..fcf40fede88efae86a41eeb2ae7d9b1086607d3a 100644 (file)
@@ -100,6 +100,8 @@ bool silc_hash_unregister(SilcHashObject *hash)
   while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
     if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
       silc_dlist_del(silc_hash_list, entry);
+      silc_free(entry->name);
+      silc_free(entry);
 
       if (silc_dlist_count(silc_hash_list) == 0) {
        silc_dlist_uninit(silc_hash_list);
@@ -130,6 +132,24 @@ bool silc_hash_register_default(void)
   return TRUE;
 }
 
+bool silc_hash_unregister_all(void)
+{
+#ifndef SILC_EPOC
+  SilcHashObject *entry;
+
+  if (!silc_hash_list)
+    return FALSE;
+
+  silc_dlist_start(silc_hash_list);
+  while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
+    silc_hash_unregister(entry);
+    if (!silc_hash_list)
+      break;
+  }
+#endif /* SILC_EPOC */
+  return TRUE;
+}
+
 /* Allocates a new SilcHash object. New object is returned into new_hash
    argument. */
 
index 2de31aafa248586ffeb51e3f94a3b543d463a89b..206427ebe4892bd857a3c30f6f9e0588510f0f7d 100644 (file)
@@ -168,6 +168,19 @@ bool silc_hash_unregister(SilcHashObject *hash);
  ***/
 bool silc_hash_register_default(void);
 
+/****f* silccrypt/SilcHashAPI/silc_hash_unregister_all
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_hash_unregister_all(void);
+ *
+ * DESCRIPTION
+ *
+ *    Unregisters all registered hash functions.
+ *
+ ***/
+bool silc_hash_unregister_all(void);
+
 /****f* silccrypt/SilcHashAPI/silc_hash_alloc
  *
  * SYNOPSIS
index 970cc6001d1736c90d0909d835910e2322fbc390..1cce72cd2d4d3e175ba69c308abc4db812f4bac9 100644 (file)
@@ -130,6 +130,8 @@ bool silc_hmac_unregister(SilcHmacObject *hmac)
   while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
     if (hmac == SILC_ALL_HMACS || entry == hmac) {
       silc_dlist_del(silc_hmac_list, entry);
+      silc_free(entry->name);
+      silc_free(entry);
 
       if (silc_dlist_count(silc_hmac_list) == 0) {
        silc_dlist_uninit(silc_hmac_list);
@@ -160,6 +162,24 @@ bool silc_hmac_register_default(void)
   return TRUE;
 }
 
+bool silc_hmac_unregister_all(void)
+{
+#ifndef SILC_EPOC
+  SilcHmacObject *entry;
+
+  if (!silc_hmac_list)
+    return FALSE;
+
+  silc_dlist_start(silc_hmac_list);
+  while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
+    silc_hmac_unregister(entry);
+    if (!silc_hmac_list)
+      break;
+  }
+#endif /* SILC_EPOC */
+  return TRUE;
+}
+
 /* Allocates a new SilcHmac object of name of `name'.  The `hash' may
    be provided as argument.  If provided it is used as the hash function
    of the HMAC.  If it is NULL then the hash function is allocated and
index c9b3bed046e6227cb247bf8e3fb2df9e8d136efa..290fbed134db617114a976c5a43f4144a3694f61 100644 (file)
@@ -133,6 +133,19 @@ bool silc_hmac_unregister(SilcHmacObject *hmac);
  ***/
 bool silc_hmac_register_default(void);
 
+/****f* silccrypt/SilcHMACAPI/silc_hmac_unregister_all
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_hmac_unregister_all(void);
+ *
+ * DESCRIPTION
+ *
+ *    Unregisters all registered HMACs.
+ *
+ ***/
+bool silc_hmac_unregister_all(void);
+
 /****f* silccrypt/SilcHMACAPI/silc_hmac_alloc
  *
  * SYNOPSIS
index 0fa9d29ac83867230a02392d3e24058c96647dcd..d9662663de4bae0e377b9daf27482ebd0cc4fddc 100644 (file)
@@ -110,6 +110,8 @@ bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
   while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
     if (pkcs == SILC_ALL_PKCS || entry == pkcs) {
       silc_dlist_del(silc_pkcs_list, entry);
+      silc_free(entry->name);
+      silc_free(entry);
 
       if (silc_dlist_count(silc_pkcs_list) == 0) {
        silc_dlist_uninit(silc_pkcs_list);
@@ -140,6 +142,24 @@ bool silc_pkcs_register_default(void)
   return TRUE;
 }
 
+bool silc_pkcs_unregister_all(void)
+{
+#ifndef SILC_EPOC
+  SilcPKCSObject *entry;
+
+  if (!silc_pkcs_list)
+    return FALSE;
+
+  silc_dlist_start(silc_pkcs_list);
+  while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
+    silc_pkcs_unregister(entry);
+    if (!silc_pkcs_list)
+      break;
+  }
+#endif /* SILC_EPOC */
+  return TRUE;
+}
+
 /* Allocates a new SilcPKCS object. The new allocated object is returned
    to the 'new_pkcs' argument. */
 
index 1beae91540b31d7a4288e62579102edde4b3c0b8..787424d731b36fcda8744aa4913dceea776f1537 100644 (file)
@@ -258,6 +258,7 @@ bool silc_pkcs_register(const SilcPKCSObject *pkcs);
 
 bool silc_pkcs_unregister(SilcPKCSObject *pkcs);
 bool silc_pkcs_register_default(void);
+bool silc_pkcs_unregister_all(void);
 bool silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs);
 void silc_pkcs_free(SilcPKCS pkcs);
 int silc_pkcs_is_supported(const unsigned char *name);
index 4fa86fa4f37d0066be9a3fd05af6102a8e2f2fd4..02fbbfa97fdb0ba78059b1981cf008bdcc7a6f74 100644 (file)
@@ -158,6 +158,8 @@ SilcRng silc_rng_alloc(void)
 void silc_rng_free(SilcRng rng)
 {
   if (rng) {
+    SilcRngState t, n;
+
     memset(rng->pool, 0, sizeof(rng->pool));
     memset(rng->key, 0, sizeof(rng->key));
     silc_hash_free(rng->sha1);
@@ -166,6 +168,13 @@ void silc_rng_free(SilcRng rng)
     if (rng->fd_devurandom != -1)
       close(rng->fd_devurandom);
 
+    for (t = rng->state->next; t != rng->state; ) {
+      n = t->next;
+      silc_free(t);
+      t = n;
+    }
+    silc_free(rng->state);
+
     silc_free(rng);
   }
 }
index 2b65ce0f3360726fcbf8ac52e3050f4f7a0d57d2..b91e5c5d1b60515344246704c65e6f22caf95376 100644 (file)
@@ -49,7 +49,8 @@ libsilcutil_a_SOURCES = \
        silcutil.c \
        silchashtable.c \
        silcsockconn.c  \
-       silcprotocol.c
+       silcprotocol.c  \
+       stacktrace.c
 
 if SILC_DIST_TOOLKIT
 include_HEADERS =      \
index c2f6c1b8c4268a9b3f83bec238bacd66fea1d153..8815cf7e75415f43917e94a33ce426b86c4e27f5 100644 (file)
@@ -275,10 +275,12 @@ void silc_config_close(SilcConfigFile *file)
   if (file) {
     /* XXX FIXME: this check could probably be removed later */
     SilcUInt32 my_len = (SilcUInt32) (strchr(file->base, EOF) - file->base);
-    SILC_CONFIG_DEBUG(("file=0x%x name=\"%s\" level=%d line=%lu", (SilcUInt32) file,
+    SILC_CONFIG_DEBUG(("file=0x%x name=\"%s\" level=%d line=%lu", 
+                      (SilcUInt32) file,
                        file->filename, file->level, file->line));
     if (my_len != file->len) {
-      fprintf(stderr, "FATAL ERROR: saved len and current len does not match!\n");
+      fprintf(stderr, 
+             "FATAL ERROR: saved len and current len does not match!\n");
       abort();
     }
     silc_free(file->filename);
index 040f51e0ae4e61c0d76686c3fc7d12f83ed9e17a..a28e9f4f8c15e073b7bfeb07ed8adee5c8be7c68 100644 (file)
@@ -60,7 +60,7 @@ bool silc_debug_hexdump = FALSE;
 long silc_log_flushdelay = 300;
 
 /* Regular pattern matching expression for the debug output */
-char *silc_log_debug_string = NULL;
+char silc_log_debug_string[128];
 
 /* Debug callbacks. If set, these are triggered for each specific output. */
 static SilcLogDebugCb silc_log_debug_cb = NULL;
@@ -256,7 +256,7 @@ bool silc_log_set_file(SilcLogType type, char *filename, SilcUInt32 maxsize,
   SilcLog log;
 
   log = silc_log_find_by_type(type);
-  if (!log || !scheduler)
+  if (!log)
     return FALSE;
 
   SILC_LOG_DEBUG(("Setting \"%s\" file to %s (max size=%d)",
@@ -286,15 +286,17 @@ bool silc_log_set_file(SilcLogType type, char *filename, SilcUInt32 maxsize,
     log->maxsize = maxsize;
   }
 
-  if (silc_log_scheduled)
-    return TRUE;
+  if (scheduler) {
+    if (silc_log_scheduled)
+      return TRUE;
 
-  /* add schedule hook with a short delay to make sure we'll use right delay */
-  silc_schedule_task_add(scheduler, 0, silc_log_fflush_callback,
-                        (void *) scheduler, 10, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-
-  silc_log_scheduled = TRUE;
+    /* Add schedule hook with a short delay to make sure we'll use 
+       right delay */
+    silc_schedule_task_add(scheduler, 0, silc_log_fflush_callback,
+                          (void *) scheduler, 10, 0,
+                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    silc_log_scheduled = TRUE;
+  }
 
   return TRUE;
 }
@@ -483,10 +485,12 @@ void silc_log_reset_debug_callbacks()
 
 void silc_log_set_debug_string(const char *debug_string)
 {
-  silc_free(silc_log_debug_string);
+  char *string;
   if ((strchr(debug_string, '(') && strchr(debug_string, ')')) ||
       strchr(debug_string, '$'))
-    silc_log_debug_string = strdup(debug_string);
+    string = strdup(debug_string);
   else
-    silc_log_debug_string = silc_string_regexify(debug_string);
+    string = silc_string_regexify(debug_string);
+  strncpy(silc_log_debug_string, string, strlen(string));
+  silc_free(string);
 }
index adad8ddd15476867a103feb98b3217141be37282..b91ab5cb00e2fbcc4b799efcb51ac792cd4fe436 100644 (file)
@@ -421,7 +421,8 @@ char *silc_log_get_file(SilcLogType type);
  *
  * SYNOPSIS
  *
- *    bool silc_log_set_file(SilcLogType type, char *filename, SilcUInt32 maxsize,
+ *    bool silc_log_set_file(SilcLogType type, char *filename, 
+ *                           SilcUInt32 maxsize,
  *                           SilcSchedule scheduler);
  *
  * DESCRIPTION
index eb246557b7b99e2c2a58af70d8d65b53bfe45198..e2e455a9ec90cf214fb48a48db0860fec9243c3e 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "silcincludes.h"
 
+#ifndef SILC_STACKTRACE
+
 void *silc_malloc(size_t size)
 {
   void *addr;
@@ -57,3 +59,5 @@ void *silc_memdup(const void *ptr, size_t size)
   addr[size] = '\0';
   return (void *)addr;
 }
+
+#endif /* !SILC_STACKTRACE */
index 691cc698295db0cd921877c2dd0273224dc6328c..233f38943618080124475725052af96dad449dbe 100644 (file)
@@ -35,6 +35,8 @@
 
 /* Prototypes */
 
+#ifndef SILC_STACKTRACE
+
 /****f* silcutil/SilcMemoryAPI/silc_malloc
  *
  * SYNOPSIS
@@ -117,4 +119,8 @@ void silc_free(void *ptr);
  ***/
 void *silc_memdup(const void *ptr, size_t size);
 
+#else
+#include "stacktrace.h"
+#endif /* SILC_STACKTRACE */
+
 #endif /* SILCMEMORY_H */
index db939c3ad201df748aa4f7fde12362d681245dde..6b3f34d640312dfc0d7747343aa0c6b680370bda 100644 (file)
@@ -287,6 +287,7 @@ bool silc_schedule_uninit(SilcSchedule schedule)
   silc_schedule_internal_uninit(schedule->internal);
 
   silc_mutex_free(schedule->lock);
+  silc_free(schedule);
 
   return TRUE;
 }
diff --git a/lib/silcutil/stacktrace.c b/lib/silcutil/stacktrace.c
new file mode 100644 (file)
index 0000000..eb8f245
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+
+  stacktrace.c 
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2002 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+
+#ifdef SILC_STACKTRACE
+
+static void *st_blocks = NULL;
+static unsigned long st_blocks_count = 0;
+static int dump = FALSE;
+
+#define SILC_ST_DEPTH 10
+
+/* Memory block with stack trace */
+typedef struct SilcStBlockStruct {
+  unsigned int dumpped  : 1;   /* Block is dumpped */
+  unsigned int depth    : 8;   /* Depth of stack trace */
+  unsigned int line     : 23;  /* Allocation line in program */
+  void *stack[SILC_ST_DEPTH];  /* Stack trace */
+  const char *file;            /* Allocation file in program */
+  unsigned long size;          /* Allocated memory size */
+  struct SilcStBlockStruct *next;
+  struct SilcStBlockStruct *prev;
+} *SilcStBlock;
+
+/* Get current frame pointer */
+#define SILC_ST_GET_FP(ret_fp)                 \
+do {                                           \
+  register void *cfp;                          \
+  asm volatile ("movl %%ebp, %0" : "=r" (cfp));        \
+  (ret_fp) = cfp;                              \
+} while(0);
+
+#define SILC_ST_GET_SIZE(size) ((size + sizeof(struct SilcStBlockStruct)))
+#define SILC_ST_GET_STACK(p) ((SilcStBlock)(((unsigned char *)p) -     \
+                           sizeof(struct SilcStBlockStruct)))
+#define SILC_ST_GET_PTR(p) (((unsigned char *)p) +             \
+                           sizeof(struct SilcStBlockStruct))
+
+void silc_st_stacktrace(SilcStBlock stack)
+{
+  void *fp;
+
+  if (!dump) {
+    atexit(silc_st_dump);
+    dump = TRUE;
+  }
+
+  /* Save the stack */
+  SILC_ST_GET_FP(fp);
+  for (stack->depth = 0; fp; stack->depth++) {
+    if (stack->depth == SILC_ST_DEPTH)
+      break;
+
+    /* Get program pointer and frame pointer from this frame */
+    stack->stack[stack->depth] = *((void **)(((unsigned char *)fp) + 4));
+    fp = *((void **)fp);
+  }
+}
+
+void *silc_st_malloc(size_t size, const char *file, int line)
+{
+  SilcStBlock stack = (SilcStBlock)malloc(SILC_ST_GET_SIZE(size));
+  assert(stack != NULL);
+
+  stack->dumpped = 0;
+  stack->file = file;
+  stack->line = line;
+  stack->size = size;
+  silc_st_stacktrace(stack);
+
+  stack->next = st_blocks;
+  stack->prev = NULL;
+  if (st_blocks)
+    ((SilcStBlock)st_blocks)->prev = stack;
+  st_blocks = stack;
+  st_blocks_count++;
+
+  return SILC_ST_GET_PTR(stack);
+}
+
+void *silc_st_calloc(size_t items, size_t size, const char *file, int line)
+{
+  void *addr = (void *)silc_st_malloc(items * size, file, line);
+  memset(addr, 0, items * size);
+  return addr;
+}
+
+void *silc_st_realloc(void *ptr, size_t size, const char *file, int line)
+{
+  SilcStBlock stack;
+
+  if (!ptr)
+    return silc_st_malloc(size, file, line);
+
+  stack = SILC_ST_GET_STACK(ptr);
+  if (stack->size >= size) {
+    stack->size = size;
+    return ptr;
+  } else {
+    void *addr = (void *)silc_st_malloc(size, file, line);
+    memcpy(addr, ptr, stack->size);
+    silc_st_free(ptr, file, line);
+    return addr;
+  }
+}
+
+void silc_st_free(void *ptr, const char *file, int line)
+{
+  SilcStBlock stack;
+
+  if (!ptr)
+    return;
+
+  stack = SILC_ST_GET_STACK(ptr);
+  if (stack->next)
+    stack->next->prev = stack->prev;
+  if (stack->prev)
+    stack->prev->next = stack->next;
+  else
+    st_blocks = stack->next;
+
+  st_blocks_count--;
+  free(stack);
+}
+
+void *silc_st_memdup(const void *ptr, size_t size, const char *file, int line)
+{
+  unsigned char *addr = (unsigned char *)silc_st_malloc(size + 1, file, line);
+  memcpy((void *)addr, ptr, size);
+  addr[size] = '\0';
+  return (void *)addr;
+}
+
+void *silc_st_strdup(const char *string, const char *file, int line)
+{
+  return silc_st_memdup(string, strlen(string), file, line);
+}
+
+/* Dumps the stack into file if there are leaks.  The file can be read
+   with a special stacktrace tool. */
+
+void silc_st_dump(void)
+{
+  SilcStBlock stack, s;
+  unsigned long leaks = 0, blocks, bytes;
+  FILE *fp = NULL;
+  int i;
+
+  for (stack = st_blocks; stack; stack = stack->next) {
+    bytes = blocks = 0;
+
+    if (stack->dumpped)
+      continue;
+
+    leaks++;
+
+    if (!fp) {
+      fp = fopen("stacktrace.log", "wb");
+      if (!fp)
+       fp = stderr;
+    }
+
+    for (s = stack; s; s = s->next) {
+      if (s->file == stack->file && s->line == stack->line &&
+         s->depth == stack->depth &&
+         !memcmp(s->stack, stack->stack, 
+                 (s->depth * sizeof(stack->stack[0])))) {
+       blocks++;
+       bytes += s->size;
+       s->dumpped = 1;
+      }
+    }
+
+    if (blocks) {
+      fprintf(fp, "<stacktrace>%s:%d: #blocks=%lu, bytes=%lu\n",
+             stack->file, stack->line, blocks, bytes);
+      for (i = 0; i < stack->depth; i++)
+       fprintf(fp, "<pc>%p\n", stack->stack[i]);
+    }
+  }
+
+  if (!leaks) {
+    fprintf(stderr, "\nNo memory leaks\n");
+  } else {
+    fprintf(stderr, 
+           "-----------------------------------------\n"
+           "-----------------------------------------\n"
+           " Memory leaks dumped to 'stacktrace.log'\n"
+           " Leaks: %lu leaks, %lu blocks\n"
+           "-----------------------------------------\n"
+           "-----------------------------------------\n",
+           leaks, st_blocks_count);
+  }
+
+  if (fp && fp != stderr)
+    fclose(fp);
+}
+
+#endif /* SILC_STACKTRACE */
diff --git a/lib/silcutil/stacktrace.h b/lib/silcutil/stacktrace.h
new file mode 100644 (file)
index 0000000..5c46886
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+
+  stacktrace.h 
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2002 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef STACKTRACE_H
+#define STACKTRACE_H
+
+#ifndef SILCMEMORY_H
+#error "Do not include this file directly"
+#endif
+
+#if defined(__GNUC__) && defined(__i386__)
+
+#undef strdup
+#define silc_malloc(s)      silc_st_malloc((s), __FILE__, __LINE__)
+#define silc_calloc(i, s)   silc_st_calloc((i), (s), __FILE__, __LINE__)
+#define silc_realloc(p, s)  silc_st_realloc((p), (s), __FILE__, __LINE__)
+#define silc_free(p)        silc_st_free((p), __FILE__, __LINE__)
+#define silc_memdup(p, s)   silc_st_memdup((p), (s), __FILE__, __LINE__)
+#define strdup(s)           silc_st_strdup((s), __FILE__, __LINE__)
+
+void *silc_st_malloc(size_t size, const char *file, int line);
+void *silc_st_calloc(size_t items, size_t size, const char *file, int line);
+void *silc_st_realloc(void *ptr, size_t size, const char *file, int line);
+void silc_st_free(void *ptr, const char *file, int line);
+void *silc_st_memdup(const void *ptr, size_t size, const char *file, int line);
+void *silc_st_strdup(const char *string, const char *file, int line);
+void silc_st_dump(void);
+
+#else
+#error "memory allocation stack trace not supported on this platform"
+#endif /* __GNUC__ && __i386__ */
+
+#endif /* STACKTRACE_H */