Browse Source

Merge branch 'macro_free_v2_squashed'

Nick Mathewson 6 years ago
parent
commit
5ee0cccd49
100 changed files with 555 additions and 240 deletions
  1. 8 0
      changes/bug24337
  2. 0 1
      configure.ac
  3. 40 0
      doc/HACKING/CodingStandards.md
  4. 3 3
      src/common/address.c
  5. 5 8
      src/common/address.h
  6. 2 2
      src/common/aes.c
  7. 3 1
      src/common/aes.h
  8. 1 1
      src/common/buffers.c
  9. 2 1
      src/common/buffers.h
  10. 4 1
      src/common/compat.c
  11. 2 2
      src/common/compat_libevent.c
  12. 6 2
      src/common/compat_libevent.h
  13. 2 2
      src/common/compat_threads.c
  14. 4 2
      src/common/compat_threads.h
  15. 1 1
      src/common/compress.c
  16. 3 1
      src/common/compress.h
  17. 1 1
      src/common/compress_lzma.c
  18. 4 1
      src/common/compress_lzma.h
  19. 1 1
      src/common/compress_zlib.c
  20. 4 1
      src/common/compress_zlib.h
  21. 1 1
      src/common/compress_zstd.c
  22. 4 1
      src/common/compress_zstd.h
  23. 1 1
      src/common/confline.c
  24. 6 1
      src/common/confline.h
  25. 13 6
      src/common/container.c
  26. 21 6
      src/common/container.h
  27. 5 5
      src/common/crypto.c
  28. 14 5
      src/common/crypto.h
  29. 1 1
      src/common/crypto_ed25519.c
  30. 4 1
      src/common/crypto_ed25519.h
  31. 1 1
      src/common/di_ops.c
  32. 6 1
      src/common/di_ops.h
  33. 2 2
      src/common/handles.h
  34. 8 3
      src/common/log.c
  35. 1 1
      src/common/memarea.c
  36. 6 1
      src/common/memarea.h
  37. 1 1
      src/common/procmon.c
  38. 3 1
      src/common/procmon.h
  39. 5 1
      src/common/sandbox.c
  40. 1 1
      src/common/storagedir.c
  41. 4 1
      src/common/storagedir.h
  42. 1 1
      src/common/timers.c
  43. 2 1
      src/common/timers.h
  44. 2 2
      src/common/tortls.c
  45. 5 2
      src/common/tortls.h
  46. 1 1
      src/common/util.c
  47. 24 1
      src/common/util.h
  48. 4 1
      src/common/workqueue.c
  49. 24 11
      src/or/addressmap.c
  50. 5 2
      src/or/bridges.c
  51. 13 13
      src/or/channel.c
  52. 7 2
      src/or/channel.h
  53. 1 1
      src/or/circuitbuild.c
  54. 3 1
      src/or/circuitbuild.h
  55. 2 2
      src/or/circuitlist.c
  56. 2 1
      src/or/circuitlist.h
  57. 1 1
      src/or/circuitmux.c
  58. 3 1
      src/or/circuitmux.h
  59. 6 4
      src/or/config.c
  60. 9 3
      src/or/config.h
  61. 1 1
      src/or/confparse.c
  62. 6 1
      src/or/confparse.h
  63. 8 7
      src/or/connection.c
  64. 4 2
      src/or/connection.h
  65. 6 6
      src/or/connection_edge.c
  66. 4 4
      src/or/connection_or.c
  67. 5 2
      src/or/connection_or.h
  68. 1 1
      src/or/conscache.c
  69. 6 1
      src/or/conscache.h
  70. 14 3
      src/or/consdiffmgr.c
  71. 4 1
      src/or/control.c
  72. 15 4
      src/or/cpuworker.c
  73. 5 2
      src/or/dircollate.c
  74. 3 1
      src/or/dircollate.h
  75. 1 1
      src/or/directory.c
  76. 3 1
      src/or/directory.h
  77. 1 1
      src/or/dirserv.c
  78. 3 1
      src/or/dirserv.h
  79. 5 2
      src/or/dirvote.c
  80. 3 1
      src/or/dirvote.h
  81. 5 5
      src/or/dns.c
  82. 2 2
      src/or/dnsserv.c
  83. 4 4
      src/or/entrynodes.c
  84. 17 4
      src/or/entrynodes.h
  85. 1 1
      src/or/ext_orport.c
  86. 5 1
      src/or/ext_orport.h
  87. 1 1
      src/or/fp_pair.c
  88. 6 1
      src/or/fp_pair.h
  89. 4 1
      src/or/geoip.c
  90. 28 16
      src/or/hs_cache.c
  91. 4 1
      src/or/hs_circuitmap.c
  92. 1 1
      src/or/hs_common.c
  93. 3 1
      src/or/hs_common.h
  94. 5 5
      src/or/hs_descriptor.c
  95. 16 5
      src/or/hs_descriptor.h
  96. 3 3
      src/or/hs_ident.c
  97. 9 3
      src/or/hs_ident.h
  98. 6 6
      src/or/hs_service.c
  99. 14 9
      src/or/hs_service.h
  100. 4 2
      src/or/microdesc.h

+ 8 - 0
changes/bug24337

@@ -0,0 +1,8 @@
+  o Minor features (defensive programming):
+    - Most of the functions in Tor that free objects have been replaced
+      with macros that free the objects and set the corresponding pointers
+      to NULL. This change should help prevent a large class of dangling
+      pointer bugs. Closes ticket 24337.
+
+    - Where possible, the tor_free() macro now only evaluates its input once.
+      Part of ticket 24337.

+ 0 - 1
configure.ac

@@ -1991,7 +1991,6 @@ if test "x$enable_gcc_warnings_advisory" != "xno"; then
      -Winvalid-source-encoding
      -Winvalid-token-paste
      -Wknr-promoted-parameter
-     -Wlanguage-extension-token
      -Wlarge-by-value-copy
      -Wliteral-conversion
      -Wliteral-range

+ 40 - 0
doc/HACKING/CodingStandards.md

@@ -346,6 +346,46 @@ macro, as in:
 	if (BUG(ptr == NULL))
 		return -1;
 
+Allocator conventions
+---------------------
+
+By convention, any tor type with a name like `abc_t` should be allocated
+by a function named `abc_new()`.  This function should never return
+NULL.
+
+Also, a type named `abc_t` should be freed by a function named `abc_free_()`.
+Don't call this `abc_free_()` function directly -- instead, wrap it in a
+macro called `abc_free()`, using the `FREE_AND_NULL` macro:
+
+    void abc_free_(abc_t *obj);
+    #define abc_free(obj) FREE_AND_NULL(abc_t, abc_free_, (abc))
+
+This macro will free the underlying `abc_t` object, and will also set
+the object pointer to NULL.
+
+You should define all `abc_free_()` functions to accept NULL inputs:
+
+    void
+    abc_free_(abc_t *obj)
+    {
+      if (!obj)
+        return;
+      tor_free(obj->name);
+      thing_free(obj->thing);
+      tor_free(obj);
+    }
+
+If you need a free function that takes a `void *` argument (for example,
+to use it as a function callback), define it with a name like
+`abc_free_void()`:
+
+    static void
+    abc_free_void_(void *obj)
+    {
+      abc_free_(obj);
+    }
+
+
 Doxygen comment conventions
 ---------------------------
 

+ 3 - 3
src/common/address.c

@@ -1759,14 +1759,14 @@ get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr))
       break;
   } SMARTLIST_FOREACH_END(a);
 
-  free_interface_address6_list(addrs);
+  interface_address6_list_free(addrs);
   return rv;
 }
 
 /** Free a smartlist of IP addresses returned by get_interface_address6_list.
  */
 void
-free_interface_address6_list(smartlist_t *addrs)
+interface_address6_list_free_(smartlist_t *addrs)
 {
   if (addrs != NULL) {
     SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a));
@@ -1781,7 +1781,7 @@ free_interface_address6_list(smartlist_t *addrs)
  * An empty smartlist means that there are no addresses of the selected type
  * matching these criteria.
  * Returns NULL on failure.
- * Use free_interface_address6_list to free the returned list.
+ * Use interface_address6_list_free to free the returned list.
  */
 MOCK_IMPL(smartlist_t *,
 get_interface_address6_list,(int severity,

+ 5 - 8
src/common/address.h

@@ -206,7 +206,9 @@ const char * fmt_addr32(uint32_t addr);
 
 MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family,
 tor_addr_t *addr));
-void free_interface_address6_list(smartlist_t * addrs);
+void interface_address6_list_free_(smartlist_t * addrs);// XXXX
+#define interface_address6_list_free(addrs) \
+  FREE_AND_NULL(smartlist_t, interface_address6_list_free_, (addrs))
 MOCK_DECL(smartlist_t *,get_interface_address6_list,(int severity,
                                                      sa_family_t family,
                                                      int include_internal));
@@ -321,13 +323,8 @@ int addr_mask_get_bits(uint32_t mask);
 int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
 char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
 MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr));
-/** Free a smartlist of IP addresses returned by get_interface_address_list.
- */
-static inline void
-free_interface_address_list(smartlist_t *addrs)
-{
-  free_interface_address6_list(addrs);
-}
+#define interface_address_list_free(lst)\
+  interface_address6_list_free(lst)
 /** Return a smartlist of the IPv4 addresses of all interfaces on the server.
  * Excludes loopback and multicast addresses. Only includes internal addresses
  * if include_internal is true. (Note that a relay behind NAT may use an

+ 2 - 2
src/common/aes.c

@@ -110,7 +110,7 @@ aes_new_cipher(const uint8_t *key, const uint8_t *iv, int key_bits)
   return (aes_cnt_cipher_t *) cipher;
 }
 void
-aes_cipher_free(aes_cnt_cipher_t *cipher_)
+aes_cipher_free_(aes_cnt_cipher_t *cipher_)
 {
   if (!cipher_)
     return;
@@ -324,7 +324,7 @@ aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, int key_bits)
 /** Release storage held by <b>cipher</b>
  */
 void
-aes_cipher_free(aes_cnt_cipher_t *cipher)
+aes_cipher_free_(aes_cnt_cipher_t *cipher)
 {
   if (!cipher)
     return;

+ 3 - 1
src/common/aes.h

@@ -17,7 +17,9 @@ typedef struct aes_cnt_cipher aes_cnt_cipher_t;
 
 aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv,
                                  int key_bits);
-void aes_cipher_free(aes_cnt_cipher_t *cipher);
+void aes_cipher_free_(aes_cnt_cipher_t *cipher);
+#define aes_cipher_free(cipher) \
+  FREE_AND_NULL(aes_cnt_cipher_t, aes_cipher_free_, (cipher))
 void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len);
 
 int evaluate_evp_for_aes(int force_value);

+ 1 - 1
src/common/buffers.c

@@ -409,7 +409,7 @@ buf_slack(const buf_t *buf)
 
 /** Release storage held by <b>buf</b>. */
 void
-buf_free(buf_t *buf)
+buf_free_(buf_t *buf)
 {
   if (!buf)
     return;

+ 2 - 1
src/common/buffers.h

@@ -24,7 +24,8 @@ struct tor_compress_state_t;
 buf_t *buf_new(void);
 buf_t *buf_new_with_capacity(size_t size);
 size_t buf_get_default_chunk_size(const buf_t *buf);
-void buf_free(buf_t *buf);
+void buf_free_(buf_t *buf);
+#define buf_free(b) FREE_AND_NULL(buf_t, buf_free_, (b))
 void buf_clear(buf_t *buf);
 buf_t *buf_copy(const buf_t *buf);
 

+ 4 - 1
src/common/compat.c

@@ -1905,9 +1905,12 @@ tor_passwd_dup(const struct passwd *pw)
   return new_pw;
 }
 
+#define tor_passwd_free(pw) \
+  FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw))
+
 /** Helper: free one of our cached 'struct passwd' values. */
 static void
-tor_passwd_free(struct passwd *pw)
+tor_passwd_free_(struct passwd *pw)
 {
   if (!pw)
     return;

+ 2 - 2
src/common/compat_libevent.c

@@ -69,7 +69,7 @@ suppress_libevent_log_msg(const char *msg)
 
 /* Wrapper for event_free() that tolerates tor_event_free(NULL) */
 void
-tor_event_free(struct event *ev)
+tor_event_free_(struct event *ev)
 {
   if (ev == NULL)
     return;
@@ -213,7 +213,7 @@ periodic_timer_new(struct event_base *base,
 
 /** Stop and free a periodic timer */
 void
-periodic_timer_free(periodic_timer_t *timer)
+periodic_timer_free_(periodic_timer_t *timer)
 {
   if (!timer)
     return;

+ 6 - 2
src/common/compat_libevent.h

@@ -19,7 +19,9 @@ void suppress_libevent_log_msg(const char *msg);
   evdns_add_server_port_with_base(tor_libevent_get_base(), \
   (sock),(tcp),(cb),(data));
 
-void tor_event_free(struct event *ev);
+void tor_event_free_(struct event *ev);
+#define tor_event_free(ev) \
+  FREE_AND_NULL(struct event, tor_event_free_, (ev))
 
 typedef struct periodic_timer_t periodic_timer_t;
 
@@ -27,7 +29,9 @@ periodic_timer_t *periodic_timer_new(struct event_base *base,
              const struct timeval *tv,
              void (*cb)(periodic_timer_t *timer, void *data),
              void *data);
-void periodic_timer_free(periodic_timer_t *);
+void periodic_timer_free_(periodic_timer_t *);
+#define periodic_timer_free(t) \
+  FREE_AND_NULL(periodic_timer_t, periodic_timer_free_, (t))
 
 #define tor_event_base_loopexit event_base_loopexit
 #define tor_event_base_loopbreak event_base_loopbreak

+ 2 - 2
src/common/compat_threads.c

@@ -48,7 +48,7 @@ tor_mutex_new_nonrecursive(void)
 }
 /** Release all storage and system resources held by <b>m</b>. */
 void
-tor_mutex_free(tor_mutex_t *m)
+tor_mutex_free_(tor_mutex_t *m)
 {
   if (!m)
     return;
@@ -68,7 +68,7 @@ tor_cond_new(void)
 
 /** Free all storage held in <b>c</b>. */
 void
-tor_cond_free(tor_cond_t *c)
+tor_cond_free_(tor_cond_t *c)
 {
   if (!c)
     return;

+ 4 - 2
src/common/compat_threads.h

@@ -54,7 +54,8 @@ void tor_mutex_init(tor_mutex_t *m);
 void tor_mutex_init_nonrecursive(tor_mutex_t *m);
 void tor_mutex_acquire(tor_mutex_t *m);
 void tor_mutex_release(tor_mutex_t *m);
-void tor_mutex_free(tor_mutex_t *m);
+void tor_mutex_free_(tor_mutex_t *m);
+#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m))
 void tor_mutex_uninit(tor_mutex_t *m);
 unsigned long tor_get_thread_id(void);
 void tor_threads_init(void);
@@ -81,7 +82,8 @@ typedef struct tor_cond_t {
 } tor_cond_t;
 
 tor_cond_t *tor_cond_new(void);
-void tor_cond_free(tor_cond_t *cond);
+void tor_cond_free_(tor_cond_t *cond);
+#define tor_cond_free(c) FREE_AND_NULL(tor_cond_t, tor_cond_free_, (c))
 int tor_cond_init(tor_cond_t *cond);
 void tor_cond_uninit(tor_cond_t *cond);
 int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex,

+ 1 - 1
src/common/compress.c

@@ -598,7 +598,7 @@ tor_compress_process(tor_compress_state_t *state,
 
 /** Deallocate <b>state</b>. */
 void
-tor_compress_free(tor_compress_state_t *state)
+tor_compress_free_(tor_compress_state_t *state)
 {
   if (state == NULL)
     return;

+ 3 - 1
src/common/compress.h

@@ -80,7 +80,9 @@ tor_compress_output_t tor_compress_process(tor_compress_state_t *state,
                                            char **out, size_t *out_len,
                                            const char **in, size_t *in_len,
                                            int finish);
-void tor_compress_free(tor_compress_state_t *state);
+void tor_compress_free_(tor_compress_state_t *state);
+#define tor_compress_free(st) \
+  FREE_AND_NULL(tor_compress_state_t, tor_compress_free_, (st))
 
 size_t tor_compress_state_size(const tor_compress_state_t *state);
 

+ 1 - 1
src/common/compress_lzma.c

@@ -323,7 +323,7 @@ tor_lzma_compress_process(tor_lzma_compress_state_t *state,
 
 /** Deallocate <b>state</b>. */
 void
-tor_lzma_compress_free(tor_lzma_compress_state_t *state)
+tor_lzma_compress_free_(tor_lzma_compress_state_t *state)
 {
   if (state == NULL)
     return;

+ 4 - 1
src/common/compress_lzma.h

@@ -31,7 +31,10 @@ tor_lzma_compress_process(tor_lzma_compress_state_t *state,
                           const char **in, size_t *in_len,
                           int finish);
 
-void tor_lzma_compress_free(tor_lzma_compress_state_t *state);
+void tor_lzma_compress_free_(tor_lzma_compress_state_t *state);
+#define tor_lzma_compress_free(st)                      \
+  FREE_AND_NULL(tor_lzma_compress_state_t,   \
+                           tor_lzma_compress_free_, (st))
 
 size_t tor_lzma_compress_state_size(const tor_lzma_compress_state_t *state);
 

+ 1 - 1
src/common/compress_zlib.c

@@ -265,7 +265,7 @@ tor_zlib_compress_process(tor_zlib_compress_state_t *state,
 
 /** Deallocate <b>state</b>. */
 void
-tor_zlib_compress_free(tor_zlib_compress_state_t *state)
+tor_zlib_compress_free_(tor_zlib_compress_state_t *state)
 {
   if (state == NULL)
     return;

+ 4 - 1
src/common/compress_zlib.h

@@ -31,7 +31,10 @@ tor_zlib_compress_process(tor_zlib_compress_state_t *state,
                           const char **in, size_t *in_len,
                           int finish);
 
-void tor_zlib_compress_free(tor_zlib_compress_state_t *state);
+void tor_zlib_compress_free_(tor_zlib_compress_state_t *state);
+#define tor_zlib_compress_free(st)                      \
+  FREE_AND_NULL(tor_zlib_compress_state_t,   \
+                           tor_zlib_compress_free_, (st))
 
 size_t tor_zlib_compress_state_size(const tor_zlib_compress_state_t *state);
 

+ 1 - 1
src/common/compress_zstd.c

@@ -399,7 +399,7 @@ tor_zstd_compress_process(tor_zstd_compress_state_t *state,
 
 /** Deallocate <b>state</b>. */
 void
-tor_zstd_compress_free(tor_zstd_compress_state_t *state)
+tor_zstd_compress_free_(tor_zstd_compress_state_t *state)
 {
   if (state == NULL)
     return;

+ 4 - 1
src/common/compress_zstd.h

@@ -31,7 +31,10 @@ tor_zstd_compress_process(tor_zstd_compress_state_t *state,
                           const char **in, size_t *in_len,
                           int finish);
 
-void tor_zstd_compress_free(tor_zstd_compress_state_t *state);
+void tor_zstd_compress_free_(tor_zstd_compress_state_t *state);
+#define tor_zstd_compress_free(st)                      \
+  FREE_AND_NULL(tor_zstd_compress_state_t,   \
+                           tor_zstd_compress_free_, (st))
 
 size_t tor_zstd_compress_state_size(const tor_zstd_compress_state_t *state);
 

+ 1 - 1
src/common/confline.c

@@ -330,7 +330,7 @@ config_process_include(const char *path, int recursion_level, int extended,
  * Free all the configuration lines on the linked list <b>front</b>.
  */
 void
-config_free_lines(config_line_t *front)
+config_free_lines_(config_line_t *front)
 {
   config_line_t *tmp;
 

+ 6 - 1
src/common/confline.h

@@ -48,7 +48,12 @@ int config_get_lines(const char *string, config_line_t **result, int extended);
 int config_get_lines_include(const char *string, config_line_t **result,
                              int extended, int *has_include,
                              smartlist_t *opened_lst);
-void config_free_lines(config_line_t *front);
+void config_free_lines_(config_line_t *front);
+#define config_free_lines(front) \
+  do {                           \
+    config_free_lines_(front);   \
+    (front) = NULL;              \
+  } while (0)
 const char *parse_config_line_from_str_verbose(const char *line,
                                        char **key_out, char **value_out,
                                        const char **err_out);

+ 13 - 6
src/common/container.c

@@ -42,7 +42,7 @@ smartlist_new,(void))
  * list's elements.
  */
 MOCK_IMPL(void,
-smartlist_free,(smartlist_t *sl))
+smartlist_free_,(smartlist_t *sl))
 {
   if (!sl)
     return;
@@ -1163,19 +1163,26 @@ HT_GENERATE2(digest256map_impl, digest256map_entry_t, node,
              digest256map_entry_hash,
              digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_)
 
+#define strmap_entry_free(ent) \
+  FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent))
+#define digestmap_entry_free(ent) \
+  FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent))
+#define digest256map_entry_free(ent) \
+  FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent))
+
 static inline void
-strmap_entry_free(strmap_entry_t *ent)
+strmap_entry_free_(strmap_entry_t *ent)
 {
   tor_free(ent->key);
   tor_free(ent);
 }
 static inline void
-digestmap_entry_free(digestmap_entry_t *ent)
+digestmap_entry_free_(digestmap_entry_t *ent)
 {
   tor_free(ent);
 }
 static inline void
-digest256map_entry_free(digest256map_entry_t *ent)
+digest256map_entry_free_(digest256map_entry_t *ent)
 {
   tor_free(ent);
 }
@@ -1335,7 +1342,7 @@ digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key)
    * those entries.  If free_val is provided, invoked it every value in \
    * <b>map</b>. */                                                     \
   MOCK_IMPL(void,                                                       \
-  prefix##_free, (maptype *map, void (*free_val)(void*)))               \
+  prefix##_free_, (maptype *map, void (*free_val)(void*)))              \
   {                                                                     \
     prefix##_entry_t **ent, **next, *this;                              \
     if (!map)                                                           \
@@ -1525,7 +1532,7 @@ digestset_new(int max_elements)
 
 /** Free all storage held in <b>set</b>. */
 void
-digestset_free(digestset_t *set)
+digestset_free_(digestset_t *set)
 {
   if (!set)
     return;

+ 21 - 6
src/common/container.h

@@ -28,7 +28,9 @@ typedef struct smartlist_t {
 } smartlist_t;
 
 MOCK_DECL(smartlist_t *, smartlist_new, (void));
-MOCK_DECL(void, smartlist_free, (smartlist_t *sl));
+MOCK_DECL(void, smartlist_free_, (smartlist_t *sl));
+#define smartlist_free(sl) FREE_AND_NULL(smartlist_t, smartlist_free_, (sl))
+
 void smartlist_clear(smartlist_t *sl);
 void smartlist_add(smartlist_t *sl, void *element);
 void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
@@ -350,7 +352,7 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
   void* prefix##set(maptype *map, keytype key, void *val);              \
   void* prefix##get(const maptype *map, keytype key);                   \
   void* prefix##remove(maptype *map, keytype key);                      \
-  MOCK_DECL(void, prefix##free, (maptype *map, void (*free_val)(void*))); \
+  MOCK_DECL(void, prefix##free_, (maptype *map, void (*free_val)(void*))); \
   int prefix##isempty(const maptype *map);                              \
   int prefix##size(const maptype *map);                                 \
   prefix##iter_t *prefix##iter_init(maptype *map);                      \
@@ -368,6 +370,16 @@ DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_);
  * table. */
 DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
 
+#define MAP_FREE_AND_NULL(maptype, map, fn)     \
+  do {                                          \
+    maptype ## _free_((map), (fn));             \
+    (map) = NULL;                               \
+  } while (0)
+
+#define strmap_free(map, fn) MAP_FREE_AND_NULL(strmap, (map), (fn))
+#define digestmap_free(map, fn) MAP_FREE_AND_NULL(digestmap, (map), (fn))
+#define digest256map_free(map, fn) MAP_FREE_AND_NULL(digest256map, (map), (fn))
+
 #undef DECLARE_MAP_FNS
 
 /** Iterates over the key-value pairs in a map <b>map</b> in order.
@@ -528,9 +540,9 @@ void* strmap_remove_lc(strmap_t *map, const char *key);
     return (valtype*)digestmap_remove((digestmap_t*)map, key);          \
   }                                                                     \
   ATTR_UNUSED static inline void                                        \
-  prefix##f##ree(maptype *map, void (*free_val)(void*))                 \
+  prefix##f##ree_(maptype *map, void (*free_val)(void*))                \
   {                                                                     \
-    digestmap_free((digestmap_t*)map, free_val);                        \
+    digestmap_free_((digestmap_t*)map, free_val);                       \
   }                                                                     \
   ATTR_UNUSED static inline int                                         \
   prefix##isempty(maptype *map)                                         \
@@ -614,10 +626,12 @@ bitarray_expand(bitarray_t *ba,
 }
 /** Free the bit array <b>ba</b>. */
 static inline void
-bitarray_free(bitarray_t *ba)
+bitarray_free_(bitarray_t *ba)
 {
   tor_free(ba);
 }
+#define bitarray_free(ba) FREE_AND_NULL(bitarray_t, bitarray_free_, (ba))
+
 /** Set the <b>bit</b>th bit in <b>b</b> to 1. */
 static inline void
 bitarray_set(bitarray_t *b, int bit)
@@ -679,7 +693,8 @@ digestset_contains(const digestset_t *set, const char *digest)
 #undef BIT
 
 digestset_t *digestset_new(int max_elements);
-void digestset_free(digestset_t* set);
+void digestset_free_(digestset_t* set);
+#define digestset_free(set) FREE_AND_NULL(digestset_t, digestset_free_, (set))
 
 /* These functions, given an <b>array</b> of <b>n_elements</b>, return the
  * <b>nth</b> lowest element. <b>nth</b>=0 gives the lowest element;

+ 5 - 5
src/common/crypto.c

@@ -529,7 +529,7 @@ crypto_pk_new,(void))
  * are released, free the key.
  */
 void
-crypto_pk_free(crypto_pk_t *env)
+crypto_pk_free_(crypto_pk_t *env)
 {
   if (!env)
     return;
@@ -592,7 +592,7 @@ crypto_cipher_new(const char *key)
 /** Free a symmetric cipher.
  */
 void
-crypto_cipher_free(crypto_cipher_t *env)
+crypto_cipher_free_(crypto_cipher_t *env)
 {
   if (!env)
     return;
@@ -1977,7 +1977,7 @@ crypto_digest512_new(digest_algorithm_t algorithm)
 /** Deallocate a digest object.
  */
 void
-crypto_digest_free(crypto_digest_t *digest)
+crypto_digest_free_(crypto_digest_t *digest)
 {
   if (!digest)
     return;
@@ -2224,7 +2224,7 @@ crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len)
 
 /** Cleanse and deallocate a XOF object. */
 void
-crypto_xof_free(crypto_xof_t *xof)
+crypto_xof_free_(crypto_xof_t *xof)
 {
   if (!xof)
     return;
@@ -2777,7 +2777,7 @@ crypto_expand_key_material_rfc5869_sha256(
 /** Free a DH key exchange object.
  */
 void
-crypto_dh_free(crypto_dh_t *dh)
+crypto_dh_free_(crypto_dh_t *dh)
 {
   if (!dh)
     return;

+ 14 - 5
src/common/crypto.h

@@ -19,6 +19,7 @@
 #include "torint.h"
 #include "testsupport.h"
 #include "compat.h"
+#include "util.h"
 
 #include <openssl/engine.h>
 #include "keccak-tiny/keccak-tiny.h"
@@ -146,7 +147,8 @@ int crypto_global_cleanup(void);
 
 /* environment setup */
 MOCK_DECL(crypto_pk_t *,crypto_pk_new,(void));
-void crypto_pk_free(crypto_pk_t *env);
+void crypto_pk_free_(crypto_pk_t *env);
+#define crypto_pk_free(pk) FREE_AND_NULL(crypto_pk_t, crypto_pk_free_, (pk))
 
 void crypto_set_tls_dh_prime(void);
 crypto_cipher_t *crypto_cipher_new(const char *key);
@@ -155,7 +157,9 @@ crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv);
 crypto_cipher_t *crypto_cipher_new_with_iv_and_bits(const uint8_t *key,
                                                     const uint8_t *iv,
                                                     int bits);
-void crypto_cipher_free(crypto_cipher_t *env);
+void crypto_cipher_free_(crypto_cipher_t *env);
+#define crypto_cipher_free(c) \
+  FREE_AND_NULL(crypto_cipher_t, crypto_cipher_free_, (c))
 
 /* public key crypto */
 MOCK_DECL(int, crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits));
@@ -258,7 +262,9 @@ int crypto_digest_algorithm_parse_name(const char *name);
 crypto_digest_t *crypto_digest_new(void);
 crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
 crypto_digest_t *crypto_digest512_new(digest_algorithm_t algorithm);
-void crypto_digest_free(crypto_digest_t *digest);
+void crypto_digest_free_(crypto_digest_t *digest);
+#define crypto_digest_free(d) \
+  FREE_AND_NULL(crypto_digest_t, crypto_digest_free_, (d))
 void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
                              size_t len);
 void crypto_digest_get_digest(crypto_digest_t *digest,
@@ -276,7 +282,9 @@ void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out,
 crypto_xof_t *crypto_xof_new(void);
 void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len);
 void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len);
-void crypto_xof_free(crypto_xof_t *xof);
+void crypto_xof_free_(crypto_xof_t *xof);
+#define crypto_xof_free(xof) \
+  FREE_AND_NULL(crypto_xof_t, crypto_xof_free_, (xof))
 
 /* Key negotiation */
 #define DH_TYPE_CIRCUIT 1
@@ -291,7 +299,8 @@ int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out,
 ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
                              const char *pubkey, size_t pubkey_len,
                              char *secret_out, size_t secret_out_len);
-void crypto_dh_free(crypto_dh_t *dh);
+void crypto_dh_free_(crypto_dh_t *dh);
+#define crypto_dh_free(dh) FREE_AND_NULL(crypto_dh_t, crypto_dh_free_, (dh))
 
 int crypto_expand_key_material_TAP(const uint8_t *key_in,
                                    size_t key_in_len,

+ 1 - 1
src/common/crypto_ed25519.c

@@ -622,7 +622,7 @@ ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
 
 /** Release all storage held for <b>kp</b>. */
 void
-ed25519_keypair_free(ed25519_keypair_t *kp)
+ed25519_keypair_free_(ed25519_keypair_t *kp)
 {
   if (! kp)
     return;

+ 4 - 1
src/common/crypto_ed25519.h

@@ -7,6 +7,7 @@
 #include "testsupport.h"
 #include "torint.h"
 #include "crypto_curve25519.h"
+#include "util.h"
 
 #define ED25519_PUBKEY_LEN 32
 #define ED25519_SECKEY_LEN 64
@@ -117,7 +118,9 @@ int ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
                                   char **tag_out,
                                   const char *filename);
 
-void ed25519_keypair_free(ed25519_keypair_t *kp);
+void ed25519_keypair_free_(ed25519_keypair_t *kp);
+#define ed25519_keypair_free(kp) \
+  FREE_AND_NULL(ed25519_keypair_t, ed25519_keypair_free_, (kp))
 
 int ed25519_pubkey_eq(const ed25519_public_key_t *key1,
                       const ed25519_public_key_t *key2);

+ 1 - 1
src/common/di_ops.c

@@ -148,7 +148,7 @@ struct di_digest256_map_t {
 /** Release all storage held in <b>map</b>, calling free_fn on each value
  * as we go. */
 void
-dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn)
+dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn)
 {
   while (map) {
     di_digest256_map_t *victim = map;

+ 6 - 1
src/common/di_ops.h

@@ -37,7 +37,12 @@ int safe_mem_is_zero(const void *mem, size_t sz);
 typedef struct di_digest256_map_t di_digest256_map_t;
 typedef void (*dimap_free_fn)(void *);
 
-void dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn);
+void dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn);
+#define dimap_free(map, free_fn)                \
+  do {                                          \
+    dimap_free_((map), (free_fn));              \
+    (map) = NULL;                               \
+  } while (0)
 void dimap_add_entry(di_digest256_map_t **map,
                      const uint8_t *key, void *val);
 void *dimap_search(const di_digest256_map_t *map, const uint8_t *key,

+ 2 - 2
src/common/handles.h

@@ -59,7 +59,7 @@
 #define HANDLE_DECL(name, structname, linkage)                          \
   typedef struct name ## _handle_t name ## _handle_t;                   \
   linkage  name ## _handle_t *name ## _handle_new(struct structname *object); \
-  linkage void name ## _handle_free(name ## _handle_t *);               \
+  linkage void name ## _handle_free_(name ## _handle_t *);              \
   linkage struct structname *name ## _handle_get(name ## _handle_t *);  \
   linkage void name ## _handles_clear(struct structname *object);
 
@@ -113,7 +113,7 @@
   }                                                                     \
                                                                         \
   linkage void                                                          \
-  name ## _handle_free(struct name ## _handle_t *ref)                   \
+  name ## _handle_free_(struct name ## _handle_t *ref)                   \
   {                                                                     \
     if (! ref) return;                                                  \
     name ## _handle_head_t *head = ref->head;                           \

+ 8 - 3
src/common/log.c

@@ -63,7 +63,9 @@ typedef struct logfile_t {
                                     * log for each log domain? */
 } logfile_t;
 
-static void log_free(logfile_t *victim);
+static void log_free_(logfile_t *victim);
+#define log_free(lg)    \
+  FREE_AND_NULL(logfile_t, log_free_, (lg))
 
 /** Helper: map a log severity to descriptive string. */
 static inline const char *
@@ -385,9 +387,12 @@ pending_log_message_new(int severity, log_domain_mask_t domain,
   return m;
 }
 
+#define pending_log_message_free(msg) \
+  FREE_AND_NULL(pending_log_message_t, pending_log_message_free_, (msg))
+
 /** Release all storage held by <b>msg</b>. */
 static void
-pending_log_message_free(pending_log_message_t *msg)
+pending_log_message_free_(pending_log_message_t *msg)
 {
   if (!msg)
     return;
@@ -721,7 +726,7 @@ log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
 
 /** Free all storage held by <b>victim</b>. */
 static void
-log_free(logfile_t *victim)
+log_free_(logfile_t *victim)
 {
   if (!victim)
     return;

+ 1 - 1
src/common/memarea.c

@@ -153,7 +153,7 @@ memarea_new(void)
 /** Free <b>area</b>, invalidating all pointers returned from memarea_alloc()
  * and friends for this area */
 void
-memarea_drop_all(memarea_t *area)
+memarea_drop_all_(memarea_t *area)
 {
   memarea_chunk_t *chunk, *next;
   for (chunk = area->first; chunk; chunk = next) {

+ 6 - 1
src/common/memarea.h

@@ -8,7 +8,12 @@
 typedef struct memarea_t memarea_t;
 
 memarea_t *memarea_new(void);
-void memarea_drop_all(memarea_t *area);
+void memarea_drop_all_(memarea_t *area);
+#define memarea_drop_all(area) \
+  do {                                          \
+    memarea_drop_all_(area);                    \
+    (area) = NULL;                              \
+  } while (0)
 void memarea_clear(memarea_t *area);
 int memarea_owns_ptr(const memarea_t *area, const void *ptr);
 void *memarea_alloc(memarea_t *area, size_t sz);

+ 1 - 1
src/common/procmon.c

@@ -325,7 +325,7 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
 
 /** Free the process-termination monitor <b>procmon</b>. */
 void
-tor_process_monitor_free(tor_process_monitor_t *procmon)
+tor_process_monitor_free_(tor_process_monitor_t *procmon)
 {
   if (procmon == NULL)
     return;

+ 3 - 1
src/common/procmon.h

@@ -27,7 +27,9 @@ tor_process_monitor_t *tor_process_monitor_new(struct event_base *base,
                                                tor_procmon_callback_t cb,
                                                void *cb_arg,
                                                const char **msg);
-void tor_process_monitor_free(tor_process_monitor_t *procmon);
+void tor_process_monitor_free_(tor_process_monitor_t *procmon);
+#define tor_process_monitor_free(procmon) \
+  FREE_AND_NULL(tor_process_monitor_t, tor_process_monitor_free_, (procmon))
 
 #endif /* !defined(TOR_PROCMON_H) */
 

+ 5 - 1
src/common/sandbox.c

@@ -1521,8 +1521,12 @@ cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a,
   return (a->family == b->family) && 0 == strcmp(a->name, b->name);
 }
 
+#define cached_getaddrinfo_item_free(item)              \
+  FREE_AND_NULL(cached_getaddrinfo_item_t,              \
+                cached_getaddrinfo_item_free_, (item))
+
 static void
-cached_getaddrinfo_item_free(cached_getaddrinfo_item_t *item)
+cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item)
 {
   if (item == NULL)
     return;

+ 1 - 1
src/common/storagedir.c

@@ -59,7 +59,7 @@ storage_dir_new(const char *dirname, int max_files)
  * Drop all in-RAM storage for <b>d</b>.  Does not delete any files.
  */
 void
-storage_dir_free(storage_dir_t *d)
+storage_dir_free_(storage_dir_t *d)
 {
   if (d == NULL)
     return;

+ 4 - 1
src/common/storagedir.h

@@ -9,7 +9,10 @@ struct config_line_t;
 struct sandbox_cfg_elem;
 
 storage_dir_t * storage_dir_new(const char *dirname, int n_files);
-void storage_dir_free(storage_dir_t *d);
+void storage_dir_free_(storage_dir_t *d);
+#define storage_dir_free(d) \
+  FREE_AND_NULL(storage_dir_t, storage_dir_free_, (d))
+
 int storage_dir_register_with_sandbox(storage_dir_t *d,
                                       struct sandbox_cfg_elem **cfg);
 const smartlist_t *storage_dir_list(storage_dir_t *d);

+ 1 - 1
src/common/timers.c

@@ -245,7 +245,7 @@ timer_new(timer_cb_fn_t cb, void *arg)
  * scheduled.
  */
 void
-timer_free(tor_timer_t *t)
+timer_free_(tor_timer_t *t)
 {
   if (! t)
     return;

+ 2 - 1
src/common/timers.h

@@ -17,7 +17,8 @@ void timer_get_cb(const tor_timer_t *t,
                   timer_cb_fn_t *cb_out, void **arg_out);
 void timer_schedule(tor_timer_t *t, const struct timeval *delay);
 void timer_disable(tor_timer_t *t);
-void timer_free(tor_timer_t *t);
+void timer_free_(tor_timer_t *t);
+#define timer_free(t) FREE_AND_NULL(tor_timer_t, timer_free_, (t))
 
 void timers_initialize(void);
 void timers_shutdown(void);

+ 2 - 2
src/common/tortls.c

@@ -644,7 +644,7 @@ static const char CLIENT_CIPHER_LIST[] =
 
 /** Free all storage held in <b>cert</b> */
 void
-tor_x509_cert_free(tor_x509_cert_t *cert)
+tor_x509_cert_free_(tor_x509_cert_t *cert)
 {
   if (! cert)
     return;
@@ -1792,7 +1792,7 @@ tor_tls_is_server(tor_tls_t *tls)
  * underlying file descriptor.
  */
 void
-tor_tls_free(tor_tls_t *tls)
+tor_tls_free_(tor_tls_t *tls)
 {
   if (!tls)
     return;

+ 5 - 2
src/common/tortls.h

@@ -216,7 +216,8 @@ void tor_tls_set_renegotiate_callback(tor_tls_t *tls,
                                       void (*cb)(tor_tls_t *, void *arg),
                                       void *arg);
 int tor_tls_is_server(tor_tls_t *tls);
-void tor_tls_free(tor_tls_t *tls);
+void tor_tls_free_(tor_tls_t *tls);
+#define tor_tls_free(tls) FREE_AND_NULL(tor_tls_t, tor_tls_free_, (tls))
 int tor_tls_peer_has_cert(tor_tls_t *tls);
 MOCK_DECL(tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls));
 MOCK_DECL(tor_x509_cert_t *,tor_tls_get_own_cert,(tor_tls_t *tls));
@@ -263,7 +264,9 @@ void check_no_tls_errors_(const char *fname, int line);
 void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
                            int severity, int domain, const char *doing);
 
-void tor_x509_cert_free(tor_x509_cert_t *cert);
+void tor_x509_cert_free_(tor_x509_cert_t *cert);
+#define tor_x509_cert_free(c) \
+  FREE_AND_NULL(tor_x509_cert_t, tor_x509_cert_free_, (c))
 tor_x509_cert_t *tor_x509_cert_decode(const uint8_t *certificate,
                             size_t certificate_len);
 void tor_x509_cert_get_der(const tor_x509_cert_t *cert,

+ 1 - 1
src/common/util.c

@@ -4713,7 +4713,7 @@ environment_variable_names_equal(const char *s1, const char *s2)
 /** Free <b>env</b> (assuming it was produced by
  * process_environment_make). */
 void
-process_environment_free(process_environment_t *env)
+process_environment_free_(process_environment_t *env)
 {
   if (env == NULL) return;
 

+ 24 - 1
src/common/util.h

@@ -80,12 +80,22 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
  * This is a macro.  If you need a function pointer to release memory from
  * tor_malloc(), use tor_free_().
  */
+#ifdef __GNUC__
+#define tor_free(p) STMT_BEGIN                                 \
+    typeof(&(p)) tor_free__tmpvar = &(p);                      \
+    if (PREDICT_LIKELY((*tor_free__tmpvar)!=NULL)) {           \
+      raw_free(*tor_free__tmpvar);                             \
+      *tor_free__tmpvar=NULL;                                  \
+    }                                                          \
+  STMT_END
+#else
 #define tor_free(p) STMT_BEGIN                                 \
     if (PREDICT_LIKELY((p)!=NULL)) {                           \
       raw_free(p);                                             \
       (p)=NULL;                                                \
     }                                                          \
   STMT_END
+#endif
 #endif /* defined(USE_DMALLOC) */
 
 #define tor_malloc(size)       tor_malloc_(size DMALLOC_ARGS)
@@ -109,6 +119,17 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
 
 void tor_log_mallinfo(int severity);
 
+/* Helper macro: free a variable of type 'typename' using freefn, and
+ * set the variable to NULL.
+ */
+#define FREE_AND_NULL(typename, freefn, var)                            \
+  do {                                                                  \
+    /* only evaluate (var) once. */                                     \
+    typename **tmp__free__ptr ## freefn = &(var);                       \
+    freefn(*tmp__free__ptr ## freefn);                                  \
+    (*tmp__free__ptr ## freefn) = NULL;                                 \
+  } while (0)
+
 /** Macro: yield a pointer to the field at position <b>off</b> within the
  * structure <b>st</b>.  Example:
  * <pre>
@@ -423,7 +444,9 @@ struct process_environment_t {
 };
 
 process_environment_t *process_environment_make(struct smartlist_t *env_vars);
-void process_environment_free(process_environment_t *env);
+void process_environment_free_(process_environment_t *env);
+#define process_environment_free(env) \
+  FREE_AND_NULL(process_environment_t, process_environment_free_, (env))
 
 struct smartlist_t *get_current_process_environment_variables(void);
 

+ 4 - 1
src/common/workqueue.c

@@ -148,12 +148,15 @@ workqueue_entry_new(workqueue_reply_t (*fn)(void*, void*),
   return ent;
 }
 
+#define workqueue_entry_free(ent) \
+  FREE_AND_NULL(workqueue_entry_t, workqueue_entry_free_, (ent))
+
 /**
  * Release all storage held in <b>ent</b>. Call only when <b>ent</b> is not on
  * any queue.
  */
 static void
-workqueue_entry_free(workqueue_entry_t *ent)
+workqueue_entry_free_(workqueue_entry_t *ent)
 {
   if (!ent)
     return;

+ 24 - 11
src/or/addressmap.c

@@ -90,34 +90,47 @@ addressmap_init(void)
   virtaddress_reversemap = strmap_new();
 }
 
+#define addressmap_ent_free(ent)                                        \
+  FREE_AND_NULL(addressmap_entry_t, addressmap_ent_free_, (ent))
+
 /** Free the memory associated with the addressmap entry <b>_ent</b>. */
 static void
-addressmap_ent_free(void *_ent)
+addressmap_ent_free_(addressmap_entry_t *ent)
 {
-  addressmap_entry_t *ent;
-  if (!_ent)
+  if (!ent)
     return;
 
-  ent = _ent;
   tor_free(ent->new_address);
   tor_free(ent);
 }
 
+static void
+addressmap_ent_free_void(void *ent)
+{
+  addressmap_ent_free_(ent);
+}
+
+#define addressmap_virtaddress_ent_free(ent)                            \
+  FREE_AND_NULL(virtaddress_entry_t, addressmap_virtaddress_ent_free_, (ent))
+
 /** Free storage held by a virtaddress_entry_t* entry in <b>_ent</b>. */
 static void
-addressmap_virtaddress_ent_free(void *_ent)
+addressmap_virtaddress_ent_free_(virtaddress_entry_t *ent)
 {
-  virtaddress_entry_t *ent;
-  if (!_ent)
+  if (!ent)
     return;
-
-  ent = _ent;
   tor_free(ent->ipv4_address);
   tor_free(ent->ipv6_address);
   tor_free(ent->hostname_address);
   tor_free(ent);
 }
 
+static void
+addressmap_virtaddress_ent_free_void(void *ent)
+{
+  addressmap_virtaddress_ent_free_(ent);
+}
+
 /** Remove <b>address</b> (which must map to <b>ent</b>) from the
  * virtual address map. */
 static void
@@ -311,10 +324,10 @@ addressmap_clean(time_t now)
 void
 addressmap_free_all(void)
 {
-  strmap_free(addressmap, addressmap_ent_free);
+  strmap_free(addressmap, addressmap_ent_free_void);
   addressmap = NULL;
 
-  strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
+  strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free_void);
   virtaddress_reversemap = NULL;
 }
 

+ 5 - 2
src/or/bridges.c

@@ -53,7 +53,10 @@ struct bridge_info_t {
   smartlist_t *socks_args;
 };
 
-static void bridge_free(bridge_info_t *bridge);
+#define bridge_free(bridge) \
+  FREE_AND_NULL(bridge_info_t, bridge_free_, (bridge))
+
+static void bridge_free_(bridge_info_t *bridge);
 static void rewrite_node_address_for_bridge(const bridge_info_t *bridge,
                                             node_t *node);
 
@@ -101,7 +104,7 @@ clear_bridge_list(void)
 
 /** Free the bridge <b>bridge</b>. */
 static void
-bridge_free(bridge_info_t *bridge)
+bridge_free_(bridge_info_t *bridge)
 {
   if (!bridge)
     return;

+ 13 - 13
src/or/channel.c

@@ -1,3 +1,4 @@
+
 /* * Copyright (c) 2012-2017, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
@@ -162,12 +163,12 @@ HT_GENERATE2(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
 /* Functions to maintain the digest map */
 static void channel_remove_from_digest_map(channel_t *chan);
 
-static void channel_force_free(channel_t *chan);
-static void
-channel_free_list(smartlist_t *channels, int mark_for_close);
-static void
-channel_listener_free_list(smartlist_t *channels, int mark_for_close);
-static void channel_listener_force_free(channel_listener_t *chan_l);
+static void channel_force_xfree(channel_t *chan);
+static void channel_free_list(smartlist_t *channels,
+                               int mark_for_close);
+static void channel_listener_free_list(smartlist_t *channels,
+                                        int mark_for_close);
+static void channel_listener_force_xfree(channel_listener_t *chan_l);
 
 /***********************************
  * Channel state utility functions *
@@ -881,7 +882,7 @@ channel_init_listener(channel_listener_t *chan_l)
  */
 
 void
-channel_free(channel_t *chan)
+channel_free_(channel_t *chan)
 {
   if (!chan) return;
 
@@ -934,7 +935,7 @@ channel_free(channel_t *chan)
  */
 
 void
-channel_listener_free(channel_listener_t *chan_l)
+channel_listener_free_(channel_listener_t *chan_l)
 {
   if (!chan_l) return;
 
@@ -962,7 +963,7 @@ channel_listener_free(channel_listener_t *chan_l)
  */
 
 static void
-channel_force_free(channel_t *chan)
+channel_force_xfree(channel_t *chan)
 {
   tor_assert(chan);
 
@@ -1007,7 +1008,7 @@ channel_force_free(channel_t *chan)
  */
 
 static void
-channel_listener_force_free(channel_listener_t *chan_l)
+channel_listener_force_xfree(channel_listener_t *chan_l)
 {
   tor_assert(chan_l);
 
@@ -1431,7 +1432,6 @@ channel_clear_remote_end(channel_t *chan)
 /**
  * Write to a channel the given packed cell.
  *
- * Return 0 on success or -1 on error.
  *
  * Two possible errors can happen. Either the channel is not opened or the
  * lower layer (specialized channel) failed to write it. In both cases, it is
@@ -2239,7 +2239,7 @@ channel_free_list(smartlist_t *channels, int mark_for_close)
       if (!CHANNEL_CONDEMNED(curr)) {
         channel_mark_for_close(curr);
       }
-      channel_force_free(curr);
+      channel_force_xfree(curr);
     } else channel_free(curr);
   } SMARTLIST_FOREACH_END(curr);
 }
@@ -2268,7 +2268,7 @@ channel_listener_free_list(smartlist_t *listeners, int mark_for_close)
             curr->state == CHANNEL_LISTENER_STATE_ERROR)) {
         channel_listener_mark_for_close(curr);
       }
-      channel_listener_force_free(curr);
+      channel_listener_force_xfree(curr);
     } else channel_listener_free(curr);
   } SMARTLIST_FOREACH_END(curr);
 }

+ 7 - 2
src/or/channel.h

@@ -458,8 +458,11 @@ void channel_close_for_error(channel_t *chan);
 void channel_closed(channel_t *chan);
 
 /* Free a channel */
-void channel_free(channel_t *chan);
-void channel_listener_free(channel_listener_t *chan_l);
+void channel_free_(channel_t *chan);
+#define channel_free(chan) FREE_AND_NULL(channel_t, channel_free_, (chan))
+void channel_listener_free_(channel_listener_t *chan_l);
+#define channel_listener_free(chan_l) \
+  FREE_AND_NULL(channel_listener_t, channel_listener_free_, (chan_l))
 
 /* State/metadata setters */
 
@@ -634,6 +637,8 @@ int packed_cell_is_destroy(channel_t *chan,
 
 /* Declare the handle helpers */
 HANDLE_DECL(channel, channel_s,)
+#define channel_handle_free(h)    \
+  FREE_AND_NULL(channel_handle_t, channel_handle_free_, (h))
 
 #endif /* !defined(TOR_CHANNEL_H) */
 

+ 1 - 1
src/or/circuitbuild.c

@@ -2732,7 +2732,7 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
 
 /** Release storage held by an extend_info_t struct. */
 void
-extend_info_free(extend_info_t *info)
+extend_info_free_(extend_info_t *info)
 {
   if (!info)
     return;

+ 3 - 1
src/or/circuitbuild.h

@@ -58,7 +58,9 @@ extend_info_t *extend_info_new(const char *nickname,
                                const tor_addr_t *addr, uint16_t port);
 extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
 extend_info_t *extend_info_dup(extend_info_t *info);
-void extend_info_free(extend_info_t *info);
+void extend_info_free_(extend_info_t *info);
+#define extend_info_free(info) \
+  FREE_AND_NULL(extend_info_t, extend_info_free_, (info))
 int extend_info_addr_is_allowed(const tor_addr_t *addr);
 int extend_info_supports_tap(const extend_info_t* ei);
 int extend_info_supports_ntor(const extend_info_t* ei);

+ 2 - 2
src/or/circuitlist.c

@@ -923,7 +923,7 @@ circuit_clear_testing_cell_stats(circuit_t *circ)
 /** Deallocate space associated with circ.
  */
 STATIC void
-circuit_free(circuit_t *circ)
+circuit_free_(circuit_t *circ)
 {
   circid_t n_circ_id = 0;
   void *mem;
@@ -1086,7 +1086,7 @@ circuit_free_all(void)
       while (or_circ->resolving_streams) {
         edge_connection_t *next_conn;
         next_conn = or_circ->resolving_streams->next_stream;
-        connection_free(TO_CONN(or_circ->resolving_streams));
+        connection_free_(TO_CONN(or_circ->resolving_streams));
         or_circ->resolving_streams = next_conn;
       }
     }

+ 2 - 1
src/or/circuitlist.h

@@ -81,7 +81,8 @@ MOCK_DECL(void, channel_note_destroy_not_pending,
 smartlist_t *circuit_find_circuits_to_upgrade_from_guard_wait(void);
 
 #ifdef CIRCUITLIST_PRIVATE
-STATIC void circuit_free(circuit_t *circ);
+STATIC void circuit_free_(circuit_t *circ);
+#define circuit_free(circ) FREE_AND_NULL(circuit_t, circuit_free_, (circ))
 STATIC size_t n_cells_in_circ_queues(const circuit_t *c);
 STATIC uint32_t circuit_max_queued_data_age(const circuit_t *c, uint32_t now);
 STATIC uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now);

+ 1 - 1
src/or/circuitmux.c

@@ -546,7 +546,7 @@ circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
  */
 
 void
-circuitmux_free(circuitmux_t *cmux)
+circuitmux_free_(circuitmux_t *cmux)
 {
   if (!cmux) return;
 

+ 3 - 1
src/or/circuitmux.h

@@ -104,7 +104,9 @@ void circuitmux_assert_okay(circuitmux_t *cmux);
 circuitmux_t * circuitmux_alloc(void);
 void circuitmux_detach_all_circuits(circuitmux_t *cmux,
                                     smartlist_t *detached_out);
-void circuitmux_free(circuitmux_t *cmux);
+void circuitmux_free_(circuitmux_t *cmux);
+#define circuitmux_free(cmux) \
+  FREE_AND_NULL(circuitmux_t, circuitmux_free_, (cmux))
 
 /* Policy control */
 void circuitmux_clear_policy(circuitmux_t *cmux);

+ 6 - 4
src/or/config.c

@@ -782,7 +782,7 @@ static or_options_t *global_default_options = NULL;
 /** Name of most recently read torrc file. */
 static char *torrc_fname = NULL;
 /** Name of the most recently read torrc-defaults file.*/
-static char *torrc_defaults_fname;
+static char *torrc_defaults_fname = NULL;
 /** Configuration options set by command line. */
 static config_line_t *global_cmdline_options = NULL;
 /** Non-configuration options set by the command line */
@@ -926,7 +926,7 @@ get_short_version(void)
 /** Release additional memory allocated in options
  */
 STATIC void
-or_options_free(or_options_t *options)
+or_options_free_(or_options_t *options)
 {
   if (!options)
     return;
@@ -984,6 +984,8 @@ config_free_all(void)
 
   tor_free(the_short_tor_version);
   tor_free(the_tor_version);
+
+  have_parsed_cmdline = 0;
 }
 
 /** Make <b>address</b> -- a piece of information related to our operation as
@@ -5825,7 +5827,7 @@ validate_transport_socks_arguments(const smartlist_t *args)
 
 /** Deallocate a bridge_line_t structure. */
 /* private */ void
-bridge_line_free(bridge_line_t *bridge_line)
+bridge_line_free_(bridge_line_t *bridge_line)
 {
   if (!bridge_line)
     return;
@@ -6591,7 +6593,7 @@ port_cfg_new(size_t namelen)
 
 /** Free all storage held in <b>port</b> */
 STATIC void
-port_cfg_free(port_cfg_t *port)
+port_cfg_free_(port_cfg_t *port)
 {
   tor_free(port);
 }

+ 9 - 3
src/or/config.h

@@ -198,7 +198,9 @@ typedef struct bridge_line_t {
                                transport proxy. */
 } bridge_line_t;
 
-void bridge_line_free(bridge_line_t *bridge_line);
+void bridge_line_free_(bridge_line_t *bridge_line);
+#define bridge_line_free(line) \
+  FREE_AND_NULL(bridge_line_t, bridge_line_free_, (line))
 bridge_line_t *parse_bridge_line(const char *line);
 smartlist_t *get_options_from_transport_options_line(const char *line,
                                                      const char *transport);
@@ -221,8 +223,12 @@ extern struct config_format_t options_format;
 #endif
 
 STATIC port_cfg_t *port_cfg_new(size_t namelen);
-STATIC void port_cfg_free(port_cfg_t *port);
-STATIC void or_options_free(or_options_t *options);
+#define port_cfg_free(port) \
+  FREE_AND_NULL(port_cfg_t, port_cfg_free_, (port))
+STATIC void port_cfg_free_(port_cfg_t *port);
+#define or_options_free(opt) \
+  FREE_AND_NULL(or_options_t, or_options_free_, (opt))
+STATIC void or_options_free_(or_options_t *options);
 STATIC int options_validate_single_onion(or_options_t *options,
                                          char **msg);
 STATIC int options_validate(or_options_t *old_options,

+ 1 - 1
src/or/confparse.c

@@ -863,7 +863,7 @@ config_reset(const config_format_t *fmt, void *options,
 
 /** Release storage held by <b>options</b>. */
 void
-config_free(const config_format_t *fmt, void *options)
+config_free_(const config_format_t *fmt, void *options)
 {
   int i;
 

+ 6 - 1
src/or/confparse.h

@@ -177,7 +177,12 @@ typedef struct config_format_t {
 #define CAL_WARN_DEPRECATIONS (1u<<2)
 
 void *config_new(const config_format_t *fmt);
-void config_free(const config_format_t *fmt, void *options);
+void config_free_(const config_format_t *fmt, void *options);
+#define config_free(fmt, options) do {                \
+    config_free_((fmt), (options));                   \
+    (options) = NULL;                                 \
+  } while (0)
+
 config_line_t *config_get_assigned_option(const config_format_t *fmt,
                                           const void *options, const char *key,
                                           int escape_val);

+ 8 - 7
src/or/connection.c

@@ -1,4 +1,4 @@
-/* Copyright (c) 2001 Matej Pfajfar.
+ /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  * Copyright (c) 2007-2017, The Tor Project, Inc. */
@@ -499,7 +499,7 @@ conn_listener_type_supports_af_unix(int type)
  * if <b>conn</b> is an OR or OP connection.
  */
 STATIC void
-connection_free_(connection_t *conn)
+connection_free_minimal(connection_t *conn)
 {
   void *mem;
   size_t memlen;
@@ -675,7 +675,7 @@ connection_free_(connection_t *conn)
 /** Make sure <b>conn</b> isn't in any of the global conn lists; then free it.
  */
 MOCK_IMPL(void,
-connection_free,(connection_t *conn))
+connection_free_,(connection_t *conn))
 {
   if (!conn)
     return;
@@ -704,7 +704,7 @@ connection_free,(connection_t *conn))
   }
 #endif /* 1 */
   connection_unregister_events(conn);
-  connection_free_(conn);
+  connection_free_minimal(conn);
 }
 
 /**
@@ -5239,8 +5239,8 @@ proxy_type_to_string(int proxy_type)
   return NULL; /*Unreached*/
 }
 
-/** Call connection_free_() on every connection in our array, and release all
- * storage held by connection.c.
+/** Call connection_free_minimal() on every connection in our array, and
+ * release all storage held by connection.c.
  *
  * Don't do the checks in connection_free(), because they will
  * fail.
@@ -5264,7 +5264,8 @@ connection_free_all(void)
   /* Clear out our list of broken connections */
   clear_broken_connection_map(0);
 
-  SMARTLIST_FOREACH(conns, connection_t *, conn, connection_free_(conn));
+  SMARTLIST_FOREACH(conns, connection_t *, conn,
+                    connection_free_minimal(conn));
 
   if (outgoing_addrs) {
     SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t *, addr, tor_free(addr));

+ 4 - 2
src/or/connection.h

@@ -29,7 +29,9 @@ connection_t *connection_new(int type, int socket_family);
 int connection_init_accepted_conn(connection_t *conn,
                                   const listener_connection_t *listener);
 void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
-MOCK_DECL(void,connection_free,(connection_t *conn));
+MOCK_DECL(void,connection_free_,(connection_t *conn));
+#define connection_free(conn) \
+  FREE_AND_NULL(connection_t, connection_free_, (conn))
 void connection_free_all(void);
 void connection_about_to_close_connection(connection_t *conn);
 void connection_close_immediate(connection_t *conn);
@@ -267,7 +269,7 @@ connection_is_moribund(connection_t *conn)
 void connection_check_oos(int n_socks, int failed);
 
 #ifdef CONNECTION_PRIVATE
-STATIC void connection_free_(connection_t *conn);
+STATIC void connection_free_minimal(connection_t *conn);
 
 /* Used only by connection.c and test*.c */
 uint32_t bucket_millis_empty(int tokens_before, uint32_t last_empty_time,

+ 6 - 6
src/or/connection_edge.c

@@ -3331,7 +3331,7 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
     relay_send_end_cell_from_edge(conn->stream_id, circ,
                                   END_STREAM_REASON_DONE,
                                   origin_circ->cpath->prev);
-    connection_free(TO_CONN(conn));
+    connection_free_(TO_CONN(conn));
 
     /* Drop the circuit here since it might be someone deliberately
      * scanning the hidden service ports. Note that this mitigates port
@@ -3523,7 +3523,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
   if (we_are_hibernating()) {
     relay_send_end_cell_from_edge(rh.stream_id, circ,
                                   END_STREAM_REASON_HIBERNATING, NULL);
-    connection_free(TO_CONN(n_stream));
+    connection_free_(TO_CONN(n_stream));
     return 0;
   }
 
@@ -3601,7 +3601,7 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
       return 0;
     case 1: /* The result was cached; a resolved cell was sent. */
       if (!dummy_conn->base_.marked_for_close)
-        connection_free(TO_CONN(dummy_conn));
+        connection_free_(TO_CONN(dummy_conn));
       return 0;
     case 0: /* resolve added to pending list */
       assert_circuit_ok(TO_CIRCUIT(circ));
@@ -3774,8 +3774,8 @@ connection_exit_connect_dir(edge_connection_t *exitconn)
 
   if (connection_add(TO_CONN(exitconn))<0) {
     connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT);
-    connection_free(TO_CONN(exitconn));
-    connection_free(TO_CONN(dirconn));
+    connection_free_(TO_CONN(exitconn));
+    connection_free_(TO_CONN(dirconn));
     return 0;
   }
 
@@ -3787,7 +3787,7 @@ connection_exit_connect_dir(edge_connection_t *exitconn)
     connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT);
     connection_close_immediate(TO_CONN(exitconn));
     connection_mark_for_close(TO_CONN(exitconn));
-    connection_free(TO_CONN(dirconn));
+    connection_free_(TO_CONN(dirconn));
     return 0;
   }
 

+ 4 - 4
src/or/connection_or.c

@@ -505,7 +505,7 @@ var_cell_copy(const var_cell_t *src)
 
 /** Release all space held by <b>cell</b>. */
 void
-var_cell_free(var_cell_t *cell)
+var_cell_free_(var_cell_t *cell)
 {
   tor_free(cell);
 }
@@ -1263,7 +1263,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
                fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port));
     }
 
-    connection_free(TO_CONN(conn));
+    connection_free_(TO_CONN(conn));
     return NULL;
   }
 
@@ -1276,7 +1276,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
       connection_or_connect_failed(conn,
                                    errno_to_orconn_end_reason(socket_error),
                                    tor_socket_strerror(socket_error));
-      connection_free(TO_CONN(conn));
+      connection_free_(TO_CONN(conn));
       return NULL;
     case 0:
       connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT);
@@ -1870,7 +1870,7 @@ connection_init_or_handshake_state(or_connection_t *conn, int started_here)
 
 /** Free all storage held by <b>state</b>. */
 void
-or_handshake_state_free(or_handshake_state_t *state)
+or_handshake_state_free_(or_handshake_state_t *state)
 {
   if (!state)
     return;

+ 5 - 2
src/or/connection_or.h

@@ -68,7 +68,9 @@ int connection_or_client_learned_peer_id(or_connection_t *conn,
                               const ed25519_public_key_t *ed_peer_id);
 time_t connection_or_client_used(or_connection_t *conn);
 MOCK_DECL(int, connection_or_get_num_circuits, (or_connection_t *conn));
-void or_handshake_state_free(or_handshake_state_t *state);
+void or_handshake_state_free_(or_handshake_state_t *state);
+#define or_handshake_state_free(state) \
+  FREE_AND_NULL(or_handshake_state_t, or_handshake_state_free_, (state))
 void or_handshake_state_record_cell(or_connection_t *conn,
                                     or_handshake_state_t *state,
                                     const cell_t *cell,
@@ -105,7 +107,8 @@ int var_cell_pack_header(const var_cell_t *cell, char *hdr_out,
                          int wide_circ_ids);
 var_cell_t *var_cell_new(uint16_t payload_len);
 var_cell_t *var_cell_copy(const var_cell_t *src);
-void var_cell_free(var_cell_t *cell);
+void var_cell_free_(var_cell_t *cell);
+#define var_cell_free(cell) FREE_AND_NULL(var_cell_t, var_cell_free_, (cell))
 
 /* DOCDOC */
 #define MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS 4

+ 1 - 1
src/or/conscache.c

@@ -170,7 +170,7 @@ consensus_cache_clear(consensus_cache_t *cache)
  * Drop all storage held by <b>cache</b>.
  */
 void
-consensus_cache_free(consensus_cache_t *cache)
+consensus_cache_free_(consensus_cache_t *cache)
 {
   if (! cache)
     return;

+ 6 - 1
src/or/conscache.h

@@ -10,9 +10,14 @@ typedef struct consensus_cache_entry_t consensus_cache_entry_t;
 typedef struct consensus_cache_t consensus_cache_t;
 
 HANDLE_DECL(consensus_cache_entry, consensus_cache_entry_t, )
+#define consensus_cache_entry_handle_free(h)    \
+  FREE_AND_NULL(consensus_cache_entry_handle_t, \
+                consensus_cache_entry_handle_free_, (h))
 
 consensus_cache_t *consensus_cache_open(const char *subdir, int max_entries);
-void consensus_cache_free(consensus_cache_t *cache);
+void consensus_cache_free_(consensus_cache_t *cache);
+#define consensus_cache_free(cache) \
+  FREE_AND_NULL(consensus_cache_t, consensus_cache_free_, (cache))
 struct sandbox_cfg_elem;
 int consensus_cache_may_overallocate(consensus_cache_t *cache);
 int consensus_cache_register_with_sandbox(consensus_cache_t *cache,

+ 14 - 3
src/or/consdiffmgr.c

@@ -207,9 +207,12 @@ HT_PROTOTYPE(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq)
 HT_GENERATE2(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq,
              0.6, tor_reallocarray, tor_free_)
 
+#define cdm_diff_free(diff) \
+  FREE_AND_NULL(cdm_diff_t, cdm_diff_free_, (diff))
+
 /** Release all storage held in <b>diff</b>. */
 static void
-cdm_diff_free(cdm_diff_t *diff)
+cdm_diff_free_(cdm_diff_t *diff)
 {
   if (!diff)
     return;
@@ -1506,11 +1509,15 @@ consensus_diff_worker_threadfn(void *state_, void *work_)
   return WQ_RPL_REPLY;
 }
 
+#define consensus_diff_worker_job_free(job)             \
+  FREE_AND_NULL(consensus_diff_worker_job_t,            \
+                consensus_diff_worker_job_free_, (job))
+
 /**
  * Helper: release all storage held in <b>job</b>.
  */
 static void
-consensus_diff_worker_job_free(consensus_diff_worker_job_t *job)
+consensus_diff_worker_job_free_(consensus_diff_worker_job_t *job)
 {
   if (!job)
     return;
@@ -1658,11 +1665,15 @@ typedef struct consensus_compress_worker_job_t {
   compressed_result_t out[ARRAY_LENGTH(compress_consensus_with)];
 } consensus_compress_worker_job_t;
 
+#define consensus_compress_worker_job_free(job) \
+  FREE_AND_NULL(consensus_compress_worker_job_t, \
+                consensus_compress_worker_job_free_, (job))
+
 /**
  * Free all resources held in <b>job</b>
  */
 static void
-consensus_compress_worker_job_free(consensus_compress_worker_job_t *job)
+consensus_compress_worker_job_free_(consensus_compress_worker_job_t *job)
 {
   if (!job)
     return;

+ 4 - 1
src/or/control.c

@@ -785,9 +785,12 @@ queue_control_event_string,(uint16_t event, char *msg))
   }
 }
 
+#define queued_event_free(ev) \
+  FREE_AND_NULL(queued_event_t, queued_event_free_, (ev))
+
 /** Release all storage held by <b>ev</b>. */
 static void
-queued_event_free(queued_event_t *ev)
+queued_event_free_(queued_event_t *ev)
 {
   if (ev == NULL)
     return;

+ 15 - 4
src/or/cpuworker.c

@@ -48,14 +48,25 @@ worker_state_new(void *arg)
   ws->onion_keys = server_onion_keys_new();
   return ws;
 }
+
+#define worker_state_free(ws) \
+  FREE_AND_NULL(worker_state_t, worker_state_free_, (ws))
+
 static void
-worker_state_free(void *arg)
+worker_state_free_(worker_state_t *ws)
 {
-  worker_state_t *ws = arg;
+  if (!ws)
+    return;
   server_onion_keys_free(ws->onion_keys);
   tor_free(ws);
 }
 
+static void
+worker_state_free_void(void *arg)
+{
+  worker_state_free_(arg);
+}
+
 static replyqueue_t *replyqueue = NULL;
 static threadpool_t *threadpool = NULL;
 static struct event *reply_event = NULL;
@@ -102,7 +113,7 @@ cpu_init(void)
     threadpool = threadpool_new(n_threads,
                                 replyqueue,
                                 worker_state_new,
-                                worker_state_free,
+                                worker_state_free_void,
                                 NULL);
   }
   /* Total voodoo. Can we make this more sensible? */
@@ -198,7 +209,7 @@ cpuworkers_rotate_keyinfo(void)
   if (threadpool_queue_update(threadpool,
                               worker_state_new,
                               update_state_threadfn,
-                              worker_state_free,
+                              worker_state_free_void,
                               NULL)) {
     log_warn(LD_OR, "Failed to queue key update for worker threads.");
   }

+ 5 - 2
src/or/dircollate.c

@@ -41,9 +41,12 @@ typedef struct ddmap_entry_s {
   vote_routerstatus_t *vrs_lst[FLEXIBLE_ARRAY_MEMBER];
 } ddmap_entry_t;
 
+#define ddmap_entry_free(e) \
+  FREE_AND_NULL(ddmap_entry_t, ddmap_entry_free_, (e))
+
 /** Release all storage held by e. */
 static void
-ddmap_entry_free(ddmap_entry_t *e)
+ddmap_entry_free_(ddmap_entry_t *e)
 {
   tor_free(e);
 }
@@ -158,7 +161,7 @@ dircollator_new(int n_votes, int n_authorities)
 
 /** Release all storage held by <b>dc</b>. */
 void
-dircollator_free(dircollator_t *dc)
+dircollator_free_(dircollator_t *dc)
 {
   if (!dc)
     return;

+ 3 - 1
src/or/dircollate.h

@@ -18,7 +18,9 @@
 typedef struct dircollator_s dircollator_t;
 
 dircollator_t *dircollator_new(int n_votes, int n_authorities);
-void dircollator_free(dircollator_t *obj);
+void dircollator_free_(dircollator_t *obj);
+#define dircollator_free(c) \
+  FREE_AND_NULL(dircollator_t, dircollator_free_, (c))
 void dircollator_add_vote(dircollator_t *dc, networkstatus_t *v);
 
 void dircollator_collate(dircollator_t *dc, int consensus_method);

+ 1 - 1
src/or/directory.c

@@ -1102,7 +1102,7 @@ directory_request_new(uint8_t dir_purpose)
  * Release all resources held by <b>req</b>.
  */
 void
-directory_request_free(directory_request_t *req)
+directory_request_free_(directory_request_t *req)
 {
   if (req == NULL)
     return;

+ 3 - 1
src/or/directory.h

@@ -51,7 +51,9 @@ int directory_must_use_begindir(const or_options_t *options);
  */
 typedef struct directory_request_t directory_request_t;
 directory_request_t *directory_request_new(uint8_t dir_purpose);
-void directory_request_free(directory_request_t *req);
+void directory_request_free_(directory_request_t *req);
+#define directory_request_free(req) \
+  FREE_AND_NULL(directory_request_t, directory_request_free_, (req))
 void directory_request_set_or_addr_port(directory_request_t *req,
                                         const tor_addr_port_t *p);
 void directory_request_set_dir_addr_port(directory_request_t *req,

+ 1 - 1
src/or/dirserv.c

@@ -3515,7 +3515,7 @@ spooled_resource_new_from_cache_entry(consensus_cache_entry_t *entry)
 
 /** Release all storage held by <b>spooled</b>. */
 void
-spooled_resource_free(spooled_resource_t *spooled)
+spooled_resource_free_(spooled_resource_t *spooled)
 {
   if (spooled == NULL)
     return;

+ 3 - 1
src/or/dirserv.h

@@ -196,7 +196,9 @@ spooled_resource_t *spooled_resource_new(dir_spool_source_t source,
                                          size_t digestlen);
 spooled_resource_t *spooled_resource_new_from_cache_entry(
                                       struct consensus_cache_entry_t *entry);
-void spooled_resource_free(spooled_resource_t *spooled);
+void spooled_resource_free_(spooled_resource_t *spooled);
+#define spooled_resource_free(sp) \
+  FREE_AND_NULL(spooled_resource_t, spooled_resource_free_, (sp))
 void dirserv_spool_remove_missing_and_guess_size(dir_connection_t *conn,
                                                  time_t cutoff,
                                                  int compression,

+ 5 - 2
src/or/dirvote.c

@@ -2691,7 +2691,7 @@ get_detached_signatures_from_pending_consensuses(pending_consensus_t *pending,
 
 /** Release all storage held in <b>s</b>. */
 void
-ns_detached_signatures_free(ns_detached_signatures_t *s)
+ns_detached_signatures_free_(ns_detached_signatures_t *s)
 {
   if (!s)
     return;
@@ -2849,10 +2849,13 @@ get_voting_schedule(const or_options_t *options, time_t now, int severity)
   return new_voting_schedule;
 }
 
+#define voting_schedule_free(s) \
+  FREE_AND_NULL(voting_schedule_t, voting_schedule_free_, (s))
+
 /** Frees a voting_schedule_t. This should be used instead of the generic
  * tor_free. */
 static void
-voting_schedule_free(voting_schedule_t *voting_schedule_to_free)
+voting_schedule_free_(voting_schedule_t *voting_schedule_to_free)
 {
   if (!voting_schedule_to_free)
     return;

+ 3 - 1
src/or/dirvote.h

@@ -148,7 +148,9 @@ int networkstatus_add_detached_signatures(networkstatus_t *target,
                                           int severity,
                                           const char **msg_out);
 char *networkstatus_get_detached_signatures(smartlist_t *consensuses);
-void ns_detached_signatures_free(ns_detached_signatures_t *s);
+void ns_detached_signatures_free_(ns_detached_signatures_t *s);
+#define ns_detached_signatures_free(s) \
+  FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s))
 
 /* cert manipulation */
 authority_cert_t *authority_cert_dup(authority_cert_t *cert);

+ 5 - 5
src/or/dns.c

@@ -457,7 +457,7 @@ purge_expired_resolves(time_t now)
         if (!pendconn->base_.marked_for_close) {
           connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT);
           circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
-          connection_free(TO_CONN(pendconn));
+          connection_free_(TO_CONN(pendconn));
         }
         tor_free(pend);
       }
@@ -670,7 +670,7 @@ dns_resolve(edge_connection_t *exitconn)
         /* If we made the connection pending, then we freed it already in
          * dns_cancel_pending_resolve().  If we marked it for close, it'll
          * get freed from the main loop.  Otherwise, can free it now. */
-        connection_free(TO_CONN(exitconn));
+        connection_free_(TO_CONN(exitconn));
       }
       break;
     default:
@@ -1101,7 +1101,7 @@ dns_cancel_pending_resolve,(const char *address))
     if (circ)
       circuit_detach_stream(circ, pendconn);
     if (!pendconn->base_.marked_for_close)
-      connection_free(TO_CONN(pendconn));
+      connection_free_(TO_CONN(pendconn));
     resolve->pending_connections = pend->next;
     tor_free(pend);
   }
@@ -1230,7 +1230,7 @@ inform_pending_connections(cached_resolve_t *resolve)
         /* This detach must happen after we send the resolved cell. */
         circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
       }
-      connection_free(TO_CONN(pendconn));
+      connection_free_(TO_CONN(pendconn));
     } else {
       circuit_t *circ;
       if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) {
@@ -1259,7 +1259,7 @@ inform_pending_connections(cached_resolve_t *resolve)
         circ = circuit_get_by_edge_conn(pendconn);
         tor_assert(circ);
         circuit_detach_stream(circ, pendconn);
-        connection_free(TO_CONN(pendconn));
+        connection_free_(TO_CONN(pendconn));
       }
     }
     resolve->pending_connections = pend->next;

+ 2 - 2
src/or/dnsserv.c

@@ -172,7 +172,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
   if (connection_add(ENTRY_TO_CONN(entry_conn)) < 0) {
     log_warn(LD_APP, "Couldn't register dummy connection for DNS request");
     evdns_server_request_respond(req, DNS_ERR_SERVERFAILED);
-    connection_free(ENTRY_TO_CONN(entry_conn));
+    connection_free_(ENTRY_TO_CONN(entry_conn));
     return;
   }
 
@@ -249,7 +249,7 @@ dnsserv_launch_request(const char *name, int reverse,
 
   if (connection_add(TO_CONN(conn))<0) {
     log_warn(LD_APP, "Couldn't register dummy connection for RESOLVE request");
-    connection_free(TO_CONN(conn));
+    connection_free_(TO_CONN(conn));
     return -1;
   }
 

+ 4 - 4
src/or/entrynodes.c

@@ -2196,7 +2196,7 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b)
 
 /** Release all storage held in <b>restriction</b> */
 STATIC void
-entry_guard_restriction_free(entry_guard_restriction_t *rst)
+entry_guard_restriction_free_(entry_guard_restriction_t *rst)
 {
   tor_free(rst);
 }
@@ -2205,7 +2205,7 @@ entry_guard_restriction_free(entry_guard_restriction_t *rst)
  * Release all storage held in <b>state</b>.
  */
 void
-circuit_guard_state_free(circuit_guard_state_t *state)
+circuit_guard_state_free_(circuit_guard_state_t *state)
 {
   if (!state)
     return;
@@ -3108,7 +3108,7 @@ get_guard_state_for_bridge_desc_fetch(const char *digest)
 
 /** Release all storage held by <b>e</b>. */
 STATIC void
-entry_guard_free(entry_guard_t *e)
+entry_guard_free_(entry_guard_t *e)
 {
   if (!e)
     return;
@@ -3601,7 +3601,7 @@ entry_guards_get_err_str_if_dir_info_missing(int using_mds,
 
 /** Free one guard selection context */
 STATIC void
-guard_selection_free(guard_selection_t *gs)
+guard_selection_free_(guard_selection_t *gs)
 {
   if (!gs) return;
 

+ 17 - 4
src/or/entrynodes.h

@@ -356,7 +356,10 @@ typedef enum {
   GUARD_USAGE_DIRGUARD = 1
 } guard_usage_t;
 
-void circuit_guard_state_free(circuit_guard_state_t *state);
+#define circuit_guard_state_free(val) \
+  FREE_AND_NULL(circuit_guard_state_t, circuit_guard_state_free_, (val))
+
+void circuit_guard_state_free_(circuit_guard_state_t *state);
 int entry_guard_pick_for_circuit(guard_selection_t *gs,
                                  guard_usage_t usage,
                                  entry_guard_restriction_t *rst,
@@ -476,6 +479,9 @@ STATIC double get_meaningful_restriction_threshold(void);
 STATIC double get_extreme_restriction_threshold(void);
 
 HANDLE_DECL(entry_guard, entry_guard_t, STATIC)
+#define entry_guard_handle_free(h)    \
+  FREE_AND_NULL(entry_guard_handle_t, entry_guard_handle_free_, (h))
+
 STATIC guard_selection_type_t guard_selection_infer_type(
                            guard_selection_type_t type_in,
                            const char *name);
@@ -483,7 +489,9 @@ STATIC guard_selection_t *guard_selection_new(const char *name,
                                               guard_selection_type_t type);
 STATIC guard_selection_t *get_guard_selection_by_name(
           const char *name, guard_selection_type_t type, int create_if_absent);
-STATIC void guard_selection_free(guard_selection_t *gs);
+STATIC void guard_selection_free_(guard_selection_t *gs);
+#define guard_selection_free(gs) \
+  FREE_AND_NULL(guard_selection_t, guard_selection_free_, (gs))
 MOCK_DECL(STATIC int, entry_guard_is_listed,
           (guard_selection_t *gs, const entry_guard_t *guard));
 STATIC const char *choose_guard_selection(const or_options_t *options,
@@ -504,7 +512,9 @@ STATIC entry_guard_t *entry_guard_add_to_sample(guard_selection_t *gs,
 STATIC entry_guard_t *entry_guards_expand_sample(guard_selection_t *gs);
 STATIC char *entry_guard_encode_for_state(entry_guard_t *guard);
 STATIC entry_guard_t *entry_guard_parse_from_state(const char *s);
-STATIC void entry_guard_free(entry_guard_t *e);
+#define entry_guard_free(e) \
+  FREE_AND_NULL(entry_guard_t, entry_guard_free_, (e))
+STATIC void entry_guard_free_(entry_guard_t *e);
 STATIC void entry_guards_update_filtered_sets(guard_selection_t *gs);
 STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
 /**
@@ -567,7 +577,10 @@ STATIC entry_guard_restriction_t *guard_create_exit_restriction(
 
 STATIC entry_guard_restriction_t *guard_create_dirserver_md_restriction(void);
 
-STATIC void entry_guard_restriction_free(entry_guard_restriction_t *rst);
+STATIC void entry_guard_restriction_free_(entry_guard_restriction_t *rst);
+#define entry_guard_restriction_free(rst)  \
+  FREE_AND_NULL(entry_guard_restriction_t, \
+                entry_guard_restriction_free_, (rst))
 
 #endif /* defined(ENTRYNODES_PRIVATE) */
 

+ 1 - 1
src/or/ext_orport.c

@@ -40,7 +40,7 @@ ext_or_cmd_new(uint16_t len)
 
 /** Deallocate the Extended ORPort message in <b>cmd</b>. */
 void
-ext_or_cmd_free(ext_or_cmd_t *cmd)
+ext_or_cmd_free_(ext_or_cmd_t *cmd)
 {
   tor_free(cmd);
 }

+ 5 - 1
src/or/ext_orport.h

@@ -10,7 +10,11 @@
 int connection_ext_or_start_auth(or_connection_t *or_conn);
 
 ext_or_cmd_t *ext_or_cmd_new(uint16_t len);
-void ext_or_cmd_free(ext_or_cmd_t *cmd);
+
+#define ext_or_cmd_free(cmd)                            \
+  FREE_AND_NULL(ext_or_cmd_t, ext_or_cmd_free_, (cmd))
+
+void ext_or_cmd_free_(ext_or_cmd_t *cmd);
 void connection_or_set_ext_or_identifier(or_connection_t *conn);
 void connection_or_remove_from_ext_or_id_map(or_connection_t *conn);
 void connection_or_clear_ext_or_id_map(void);

+ 1 - 1
src/or/fp_pair.c

@@ -196,7 +196,7 @@ fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key)
  */
 
 void
-fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*))
+fp_pair_map_free_(fp_pair_map_t *map, void (*free_val)(void*))
 {
   fp_pair_map_entry_t **ent, **next, *this;
 

+ 6 - 1
src/or/fp_pair.h

@@ -26,7 +26,12 @@ void * fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key);
 void * fp_pair_map_get_by_digests(const fp_pair_map_t *map,
                                   const char *first, const char *second);
 void * fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key);
-void fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*));
+void fp_pair_map_free_(fp_pair_map_t *map, void (*free_val)(void*));
+#define fp_pair_map_free(map, free_val) do {            \
+    fp_pair_map_free_((map), (free_val));               \
+    (map) = NULL;                                       \
+  } while (0)
+
 int fp_pair_map_isempty(const fp_pair_map_t *map);
 int fp_pair_map_size(const fp_pair_map_t *map);
 fp_pair_map_iter_t * fp_pair_map_iter_init(fp_pair_map_t *map);

+ 4 - 1
src/or/geoip.c

@@ -527,9 +527,12 @@ HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
 HT_GENERATE2(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
              clientmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
 
+#define clientmap_entry_free(ent) \
+  FREE_AND_NULL(clientmap_entry_t, clientmap_entry_free_, ent)
+
 /** Free all storage held by <b>ent</b>. */
 static void
-clientmap_entry_free(clientmap_entry_t *ent)
+clientmap_entry_free_(clientmap_entry_t *ent)
 {
   if (!ent)
     return;

+ 28 - 16
src/or/hs_cache.c

@@ -52,9 +52,12 @@ lookup_v3_desc_as_dir(const uint8_t *key)
   return digest256map_get(hs_cache_v3_dir, key);
 }
 
+#define cache_dir_desc_free(val) \
+  FREE_AND_NULL(hs_cache_dir_descriptor_t, cache_dir_desc_free_, (val))
+
 /* Free a directory descriptor object. */
 static void
-cache_dir_desc_free(hs_cache_dir_descriptor_t *desc)
+cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc)
 {
   if (desc == NULL) {
     return;
@@ -67,10 +70,9 @@ cache_dir_desc_free(hs_cache_dir_descriptor_t *desc)
 /* Helper function: Use by the free all function using the digest256map
  * interface to cache entries. */
 static void
-cache_dir_desc_free_(void *ptr)
+cache_dir_desc_free_void(void *ptr)
 {
-  hs_cache_dir_descriptor_t *desc = ptr;
-  cache_dir_desc_free(desc);
+  cache_dir_desc_free_(ptr);
 }
 
 /* Create a new directory cache descriptor object from a encoded descriptor.
@@ -417,9 +419,12 @@ cache_client_desc_new(const char *desc_str,
   return client_desc;
 }
 
+#define cache_client_desc_free(val) \
+  FREE_AND_NULL(hs_cache_client_descriptor_t, cache_client_desc_free_, (val))
+
 /** Free memory allocated by <b>desc</b>. */
 static void
-cache_client_desc_free(hs_cache_client_descriptor_t *desc)
+cache_client_desc_free_(hs_cache_client_descriptor_t *desc)
 {
   if (desc == NULL) {
     return;
@@ -433,7 +438,7 @@ cache_client_desc_free(hs_cache_client_descriptor_t *desc)
 
 /** Helper function: Use by the free all function to clear the client cache */
 static void
-cache_client_desc_free_(void *ptr)
+cache_client_desc_free_void(void *ptr)
 {
   hs_cache_client_descriptor_t *desc = ptr;
   cache_client_desc_free(desc);
@@ -448,18 +453,21 @@ cache_intro_state_new(void)
   return state;
 }
 
+#define cache_intro_state_free(val) \
+  FREE_AND_NULL(hs_cache_intro_state_t, cache_intro_state_free_, (val))
+
 /* Free an hs_cache_intro_state_t object. */
 static void
-cache_intro_state_free(hs_cache_intro_state_t *state)
+cache_intro_state_free_(hs_cache_intro_state_t *state)
 {
   tor_free(state);
 }
 
 /* Helper function: use by the free all function. */
 static void
-cache_intro_state_free_(void *state)
+cache_intro_state_free_void(void *state)
 {
-  cache_intro_state_free(state);
+  cache_intro_state_free_(state);
 }
 
 /* Return a newly allocated and initialized hs_cache_client_intro_state_t
@@ -472,22 +480,26 @@ cache_client_intro_state_new(void)
   return cache;
 }
 
+#define cache_client_intro_state_free(val)              \
+  FREE_AND_NULL(hs_cache_client_intro_state_t,          \
+                cache_client_intro_state_free_, (val))
+
 /* Free a cache client intro state object. */
 static void
-cache_client_intro_state_free(hs_cache_client_intro_state_t *cache)
+cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache)
 {
   if (cache == NULL) {
     return;
   }
-  digest256map_free(cache->intro_points, cache_intro_state_free_);
+  digest256map_free(cache->intro_points, cache_intro_state_free_void);
   tor_free(cache);
 }
 
 /* Helper function: use by the free all function. */
 static void
-cache_client_intro_state_free_(void *entry)
+cache_client_intro_state_free_void(void *entry)
 {
-  cache_client_intro_state_free(entry);
+  cache_client_intro_state_free_(entry);
 }
 
 /* For the given service identity key service_pk and an introduction
@@ -951,14 +963,14 @@ hs_cache_init(void)
 void
 hs_cache_free_all(void)
 {
-  digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_);
+  digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_void);
   hs_cache_v3_dir = NULL;
 
-  digest256map_free(hs_cache_v3_client, cache_client_desc_free_);
+  digest256map_free(hs_cache_v3_client, cache_client_desc_free_void);
   hs_cache_v3_client = NULL;
 
   digest256map_free(hs_cache_client_intro_state,
-                    cache_client_intro_state_free_);
+                    cache_client_intro_state_free_void);
   hs_cache_client_intro_state = NULL;
 }
 

+ 4 - 1
src/or/hs_circuitmap.c

@@ -106,9 +106,12 @@ hs_token_new(hs_token_type_t type, size_t token_len,
   return hs_token;
 }
 
+#define hs_token_free(val) \
+  FREE_AND_NULL(hs_token_t, hs_token_free_, (val))
+
 /** Free memory allocated by this <b>hs_token</b>. */
 static void
-hs_token_free(hs_token_t *hs_token)
+hs_token_free_(hs_token_t *hs_token)
 {
   if (!hs_token) {
     return;

+ 1 - 1
src/or/hs_common.c

@@ -329,7 +329,7 @@ rend_data_alloc(uint32_t version)
 
 /** Free all storage associated with <b>data</b> */
 void
-rend_data_free(rend_data_t *data)
+rend_data_free_(rend_data_t *data)
 {
   if (!data) {
     return;

+ 3 - 1
src/or/hs_common.h

@@ -192,7 +192,9 @@ void hs_build_blinded_keypair(const ed25519_keypair_t *kp,
                               ed25519_keypair_t *kp_out);
 int hs_service_requires_uptime_circ(const smartlist_t *ports);
 
-void rend_data_free(rend_data_t *data);
+void rend_data_free_(rend_data_t *data);
+#define rend_data_free(data) \
+  FREE_AND_NULL(rend_data_t, rend_data_free_, (data))
 rend_data_t *rend_data_dup(const rend_data_t *data);
 rend_data_t *rend_data_client_create(const char *onion_address,
                                      const char *desc_id,

+ 5 - 5
src/or/hs_descriptor.c

@@ -2367,7 +2367,7 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc,
 
 /* Free the descriptor plaintext data object. */
 void
-hs_desc_plaintext_data_free(hs_desc_plaintext_data_t *desc)
+hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc)
 {
   desc_plaintext_data_free_contents(desc);
   tor_free(desc);
@@ -2375,7 +2375,7 @@ hs_desc_plaintext_data_free(hs_desc_plaintext_data_t *desc)
 
 /* Free the descriptor encrypted data object. */
 void
-hs_desc_encrypted_data_free(hs_desc_encrypted_data_t *desc)
+hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc)
 {
   desc_encrypted_data_free_contents(desc);
   tor_free(desc);
@@ -2383,7 +2383,7 @@ hs_desc_encrypted_data_free(hs_desc_encrypted_data_t *desc)
 
 /* Free the given descriptor object. */
 void
-hs_descriptor_free(hs_descriptor_t *desc)
+hs_descriptor_free_(hs_descriptor_t *desc)
 {
   if (!desc) {
     return;
@@ -2448,7 +2448,7 @@ hs_desc_intro_point_new(void)
 
 /* Free a descriptor intro point object. */
 void
-hs_desc_intro_point_free(hs_desc_intro_point_t *ip)
+hs_desc_intro_point_free_(hs_desc_intro_point_t *ip)
 {
   if (ip == NULL) {
     return;
@@ -2467,7 +2467,7 @@ hs_desc_intro_point_free(hs_desc_intro_point_t *ip)
 
 /* Free the given descriptor link specifier. */
 void
-hs_desc_link_specifier_free(hs_desc_link_specifier_t *ls)
+hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls)
 {
   if (ls == NULL) {
     return;

+ 16 - 5
src/or/hs_descriptor.h

@@ -208,11 +208,20 @@ hs_desc_is_supported_version(uint32_t version)
 
 /* Public API. */
 
-void hs_descriptor_free(hs_descriptor_t *desc);
-void hs_desc_plaintext_data_free(hs_desc_plaintext_data_t *desc);
-void hs_desc_encrypted_data_free(hs_desc_encrypted_data_t *desc);
+void hs_descriptor_free_(hs_descriptor_t *desc);
+#define hs_descriptor_free(desc) \
+  FREE_AND_NULL(hs_descriptor_t, hs_descriptor_free_, (desc))
+void hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc);
+#define hs_desc_plaintext_data_free(desc) \
+  FREE_AND_NULL(hs_desc_plaintext_data_t, hs_desc_plaintext_data_free_, (desc))
+void hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc);
+#define hs_desc_encrypted_data_free(desc) \
+  FREE_AND_NULL(hs_desc_encrypted_data_t, hs_desc_encrypted_data_free_, (desc))
+
+void hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls);
+#define hs_desc_link_specifier_free(ls) \
+  FREE_AND_NULL(hs_desc_link_specifier_t, hs_desc_link_specifier_free_, (ls))
 
-void hs_desc_link_specifier_free(hs_desc_link_specifier_t *ls);
 hs_desc_link_specifier_t *hs_desc_link_specifier_new(
                                   const extend_info_t *info, uint8_t type);
 void hs_descriptor_clear_intro_points(hs_descriptor_t *desc);
@@ -234,7 +243,9 @@ size_t hs_desc_obj_size(const hs_descriptor_t *data);
 size_t hs_desc_plaintext_obj_size(const hs_desc_plaintext_data_t *data);
 
 hs_desc_intro_point_t *hs_desc_intro_point_new(void);
-void hs_desc_intro_point_free(hs_desc_intro_point_t *ip);
+void hs_desc_intro_point_free_(hs_desc_intro_point_t *ip);
+#define hs_desc_intro_point_free(ip) \
+  FREE_AND_NULL(hs_desc_intro_point_t, hs_desc_intro_point_free_, (ip))
 
 link_specifier_t *hs_desc_lspec_to_trunnel(
                                    const hs_desc_link_specifier_t *spec);

+ 3 - 3
src/or/hs_ident.c

@@ -25,7 +25,7 @@ hs_ident_circuit_new(const ed25519_public_key_t *identity_pk,
 
 /* Free the given circuit identifier. */
 void
-hs_ident_circuit_free(hs_ident_circuit_t *ident)
+hs_ident_circuit_free_(hs_ident_circuit_t *ident)
 {
   if (ident == NULL) {
     return;
@@ -56,7 +56,7 @@ hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src)
 
 /* Free the given directory connection identifier. */
 void
-hs_ident_dir_conn_free(hs_ident_dir_conn_t *ident)
+hs_ident_dir_conn_free_(hs_ident_dir_conn_t *ident)
 {
   if (ident == NULL) {
     return;
@@ -93,7 +93,7 @@ hs_ident_edge_conn_new(const ed25519_public_key_t *identity_pk)
 
 /* Free the given edge connection identifier. */
 void
-hs_ident_edge_conn_free(hs_ident_edge_conn_t *ident)
+hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident)
 {
   if (ident == NULL) {
     return;

+ 9 - 3
src/or/hs_ident.h

@@ -119,12 +119,16 @@ typedef struct hs_ident_edge_conn_t {
 hs_ident_circuit_t *hs_ident_circuit_new(
                              const ed25519_public_key_t *identity_pk,
                              hs_ident_circuit_type_t circuit_type);
-void hs_ident_circuit_free(hs_ident_circuit_t *ident);
+void hs_ident_circuit_free_(hs_ident_circuit_t *ident);
+#define hs_ident_circuit_free(id) \
+  FREE_AND_NULL(hs_ident_circuit_t, hs_ident_circuit_free_, (id))
 hs_ident_circuit_t *hs_ident_circuit_dup(const hs_ident_circuit_t *src);
 
 /* Directory connection identifier API. */
 hs_ident_dir_conn_t *hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src);
-void hs_ident_dir_conn_free(hs_ident_dir_conn_t *ident);
+void hs_ident_dir_conn_free_(hs_ident_dir_conn_t *ident);
+#define hs_ident_dir_conn_free(id) \
+  FREE_AND_NULL(hs_ident_dir_conn_t, hs_ident_dir_conn_free_, (id))
 void hs_ident_dir_conn_init(const ed25519_public_key_t *identity_pk,
                             const ed25519_public_key_t *blinded_pk,
                             hs_ident_dir_conn_t *ident);
@@ -132,7 +136,9 @@ void hs_ident_dir_conn_init(const ed25519_public_key_t *identity_pk,
 /* Edge connection identifier API. */
 hs_ident_edge_conn_t *hs_ident_edge_conn_new(
                                     const ed25519_public_key_t *identity_pk);
-void hs_ident_edge_conn_free(hs_ident_edge_conn_t *ident);
+void hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident);
+#define hs_ident_edge_conn_free(id) \
+  FREE_AND_NULL(hs_ident_edge_conn_t, hs_ident_edge_conn_free_, (id))
 
 /* Validators */
 int hs_ident_intro_circ_is_valid(const hs_ident_circuit_t *ident);

+ 6 - 6
src/or/hs_service.c

@@ -353,7 +353,7 @@ service_free_all(void)
 
 /* Free a given service intro point object. */
 STATIC void
-service_intro_point_free(hs_service_intro_point_t *ip)
+service_intro_point_free_(hs_service_intro_point_t *ip)
 {
   if (!ip) {
     return;
@@ -369,9 +369,9 @@ service_intro_point_free(hs_service_intro_point_t *ip)
 /* Helper: free an hs_service_intro_point_t object. This function is used by
  * digest256map_free() which requires a void * pointer. */
 static void
-service_intro_point_free_(void *obj)
+service_intro_point_free_void(void *obj)
 {
-  service_intro_point_free(obj);
+  service_intro_point_free_(obj);
 }
 
 /* Return a newly allocated service intro point and fully initialized from the
@@ -1028,7 +1028,7 @@ load_service_keys(hs_service_t *service)
 
 /* Free a given service descriptor object and all key material is wiped. */
 STATIC void
-service_descriptor_free(hs_service_descriptor_t *desc)
+service_descriptor_free_(hs_service_descriptor_t *desc)
 {
   if (!desc) {
     return;
@@ -1037,7 +1037,7 @@ service_descriptor_free(hs_service_descriptor_t *desc)
   memwipe(&desc->signing_kp, 0, sizeof(desc->signing_kp));
   memwipe(&desc->blinded_kp, 0, sizeof(desc->blinded_kp));
   /* Cleanup all intro points. */
-  digest256map_free(desc->intro_points.map, service_intro_point_free_);
+  digest256map_free(desc->intro_points.map, service_intro_point_free_void);
   digestmap_free(desc->intro_points.failed_id, tor_free_);
   if (desc->previous_hsdirs) {
     SMARTLIST_FOREACH(desc->previous_hsdirs, char *, s, tor_free(s));
@@ -3441,7 +3441,7 @@ hs_service_new(const or_options_t *options)
  * also takes care of wiping service keys from memory. It is safe to pass a
  * NULL pointer. */
 void
-hs_service_free(hs_service_t *service)
+hs_service_free_(hs_service_t *service)
 {
   if (service == NULL) {
     return;

+ 14 - 9
src/or/hs_service.h

@@ -249,7 +249,8 @@ void hs_service_free_all(void);
 
 /* Service new/free functions. */
 hs_service_t *hs_service_new(const or_options_t *options);
-void hs_service_free(hs_service_t *service);
+void hs_service_free_(hs_service_t *service);
+#define hs_service_free(s) FREE_AND_NULL(hs_service_t, hs_service_free_, (s))
 
 unsigned int hs_service_get_num_services(void);
 void hs_service_stage_services(const smartlist_t *service_list);
@@ -289,12 +290,15 @@ void hs_service_upload_desc_to_dir(const char *encoded_desc,
 #ifdef HS_SERVICE_PRIVATE
 
 #ifdef TOR_UNIT_TESTS
-
 /* Useful getters for unit tests. */
 STATIC unsigned int get_hs_service_map_size(void);
 STATIC int get_hs_service_staging_list_size(void);
 STATIC hs_service_ht *get_hs_service_map(void);
 STATIC hs_service_t *get_first_service(void);
+STATIC hs_service_intro_point_t *service_intro_point_find_by_ident(
+                                         const hs_service_t *service,
+                                         const hs_ident_circuit_t *ident);
+#endif
 
 /* Service accessors. */
 STATIC hs_service_t *find_service(hs_service_ht *map,
@@ -305,7 +309,10 @@ STATIC int register_service(hs_service_ht *map, hs_service_t *service);
 STATIC hs_service_intro_point_t *service_intro_point_new(
                                          const extend_info_t *ei,
                                          unsigned int is_legacy);
-STATIC void service_intro_point_free(hs_service_intro_point_t *ip);
+STATIC void service_intro_point_free_(hs_service_intro_point_t *ip);
+#define service_intro_point_free(ip)                            \
+  FREE_AND_NULL(hs_service_intro_point_t,             \
+                          service_intro_point_free_, (ip))
 STATIC void service_intro_point_add(digest256map_t *map,
                                     hs_service_intro_point_t *ip);
 STATIC void service_intro_point_remove(const hs_service_t *service,
@@ -313,9 +320,6 @@ STATIC void service_intro_point_remove(const hs_service_t *service,
 STATIC hs_service_intro_point_t *service_intro_point_find(
                                  const hs_service_t *service,
                                  const ed25519_public_key_t *auth_key);
-STATIC hs_service_intro_point_t *service_intro_point_find_by_ident(
-                                         const hs_service_t *service,
-                                         const hs_ident_circuit_t *ident);
 /* Service descriptor functions. */
 STATIC hs_service_descriptor_t *service_descriptor_new(void);
 STATIC hs_service_descriptor_t *service_desc_find_by_intro(
@@ -341,7 +345,10 @@ STATIC void run_upload_descriptor_event(time_t now);
 STATIC char *
 encode_desc_rev_counter_for_state(const hs_service_descriptor_t *desc);
 
-STATIC void service_descriptor_free(hs_service_descriptor_t *desc);
+STATIC void service_descriptor_free_(hs_service_descriptor_t *desc);
+#define service_descriptor_free(d) \
+  FREE_AND_NULL(hs_service_descriptor_t, \
+                           service_descriptor_free_, (d))
 
 STATIC uint64_t
 check_state_line_for_service_rev_counter(const char *state_line,
@@ -361,8 +368,6 @@ STATIC void service_desc_schedule_upload(hs_service_descriptor_t *desc,
 STATIC int service_desc_hsdirs_changed(const hs_service_t *service,
                                 const hs_service_descriptor_t *desc);
 
-#endif /* defined(TOR_UNIT_TESTS) */
-
 #endif /* defined(HS_SERVICE_PRIVATE) */
 
 #endif /* !defined(TOR_HS_SERVICE_H) */

+ 4 - 2
src/or/microdesc.h

@@ -38,8 +38,10 @@ smartlist_t *microdesc_list_missing_digest256(networkstatus_t *ns,
                                               digest256map_t *skip);
 
 void microdesc_free_(microdesc_t *md, const char *fname, int line);
-#define microdesc_free(md) \
-  microdesc_free_((md), __FILE__, __LINE__)
+#define microdesc_free(md) do {                 \
+    microdesc_free_((md), __FILE__, __LINE__);  \
+    (md) = NULL;                                \
+  } while (0)
 void microdesc_free_all(void);
 
 void update_microdesc_downloads(time_t now);

Some files were not shown because too many files changed in this diff