From a140d839758495674207285fda8252a5372062e7 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 4 Jun 2024 10:38:59 -0400 Subject: [PATCH] MT#55283 enforce hash table types in callbacks For typed hash tables, enforce the correct type in the arguments to the hashing and equality functions. Adapt existing affected callback functions and change their arguments from void* to the respective types. Add reverse casts to GHashFunc and GEqualFunc in instances where these functions are used in non-typed hash tables (that should be converted at a later point). Add convenience macro to create typed wrapper functions for hash tables that use "direct" hashing (i.e. the pointer value). Add wrappers for existing GLib functions that have generic arguments so that they can be used in typed hash tables. Change-Id: I43bb32969208f4aae49584d95c0df8353df6e2a0 --- daemon/call.c | 4 ++-- daemon/codec.c | 9 ++++----- daemon/cookie_cache.c | 4 ++-- daemon/ice.c | 35 ++++++++++++----------------------- daemon/janus.c | 15 ++++++++------- daemon/media_player.c | 4 +++- daemon/media_socket.c | 4 ++-- daemon/sdp.c | 12 ++++++++++-- daemon/statistics.c | 2 +- daemon/tcp_listener.c | 3 ++- daemon/websocket.c | 5 +++-- include/call.h | 4 +++- lib/auxlib.h | 14 ++++++++++++++ lib/codeclib.c | 2 +- lib/containers.h | 12 +++++++++++- lib/socket.c | 8 +------- lib/socket.h | 4 +--- lib/str.c | 8 ++++---- lib/str.h | 8 ++++---- 19 files changed, 88 insertions(+), 69 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 46d1b309f..bfd95e7e0 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -461,7 +461,7 @@ void kill_calls_timer(GSList *list, const char *url) { goto destroy; if (rtpe_config.fmt == XF_KAMAILIO) - dup_tags = g_hash_table_new(str_hash, str_equal); + dup_tags = g_hash_table_new((GHashFunc) str_hash, (GEqualFunc) str_equal); rwlock_lock_r(&ca->master_lock); @@ -4193,7 +4193,7 @@ struct call_monologue *__monologue_create(call_t *call) { ret->created = rtpe_now.tv_sec; ret->associated_tags = g_hash_table_new(g_direct_hash, g_direct_equal); ret->medias = medias_arr_new(); - ret->media_ids = g_hash_table_new(str_hash, str_equal); + ret->media_ids = g_hash_table_new((GHashFunc) str_hash, (GEqualFunc) str_equal); ret->ssrc_hash = create_ssrc_hash_call(); ret->sdp_attr_print = sdp_insert_monologue_attributes; diff --git a/daemon/codec.c b/daemon/codec.c index 7e0cabf96..21629e91c 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1043,12 +1043,10 @@ static void __codec_rtcp_timer(struct call_media *receiver) { // XXX unify with media player into a generic RTCP player } -static unsigned int __codec_handler_hash(const void *p) { - const struct codec_handler *h = p; +static unsigned int __codec_handler_hash(const struct codec_handler *h) { return h->source_pt.payload_type ^ GPOINTER_TO_UINT(h->sink); } -static int __codec_handler_eq(const void *a, const void *b) { - const struct codec_handler *h = a, *j = b; +static int __codec_handler_eq(const struct codec_handler *h, const struct codec_handler *j) { return h->source_pt.payload_type == j->source_pt.payload_type && h->sink == j->sink; } @@ -4826,7 +4824,8 @@ void codec_tracker_update(struct codec_store *cs, struct codec_store *orig_cs) { // build our tables GHashTable *all_clockrates = g_hash_table_new(g_direct_hash, g_direct_equal); - GHashTable *all_supp_codecs = g_hash_table_new_full(str_case_hash, str_case_equal, free, + GHashTable *all_supp_codecs = g_hash_table_new_full((GHashFunc) str_case_hash, + (GEqualFunc) str_case_equal, free, (GDestroyNotify) g_hash_table_destroy); for (__auto_type l = cs->codec_prefs.head; l; l = l->next) __insert_codec_tracker(all_clockrates, all_supp_codecs, sct, l); diff --git a/daemon/cookie_cache.c b/daemon/cookie_cache.c index 5a10bb9f2..b3c773d2b 100644 --- a/daemon/cookie_cache.c +++ b/daemon/cookie_cache.c @@ -9,8 +9,8 @@ #include "str.h" INLINE void cookie_cache_state_init(struct cookie_cache_state *s) { - s->in_use = g_hash_table_new(str_hash, str_equal); - s->cookies = g_hash_table_new_full(str_hash, str_equal, free, cache_entry_free); + s->in_use = g_hash_table_new((GHashFunc) str_hash, (GEqualFunc) str_equal); + s->cookies = g_hash_table_new_full((GHashFunc) str_hash, (GEqualFunc) str_equal, free, cache_entry_free); } INLINE void cookie_cache_state_cleanup(struct cookie_cache_state *s) { g_hash_table_destroy(s->cookies); diff --git a/daemon/ice.c b/daemon/ice.c index a33b79cac..87a07cd79 100644 --- a/daemon/ice.c +++ b/daemon/ice.c @@ -87,8 +87,8 @@ const char * const ice_type_strings[] = { -static unsigned int frag_key_hash(const void *A); -static int frag_key_eq(const void *A, const void *B); +static unsigned int frag_key_hash(const struct fragment_key *A); +static int frag_key_eq(const struct fragment_key *A, const struct fragment_key *B); static void fragment_key_free(struct fragment_key *); TYPED_GQUEUE(fragment, struct sdp_fragment) @@ -133,13 +133,10 @@ static void ice_update_media_streams(struct call_monologue *ml, sdp_streams_q *s } -static unsigned int frag_key_hash(const void *A) { - const struct fragment_key *a = A; +static unsigned int frag_key_hash(const struct fragment_key *a) { return str_hash(&a->call_id) ^ str_hash(&a->from_tag); } -static int frag_key_eq(const void *A, const void *B) { - const struct fragment_key *a = A; - const struct fragment_key *b = B; +static int frag_key_eq(const struct fragment_key *a, const struct fragment_key *b) { return str_equal(&a->call_id, &b->call_id) && str_equal(&a->from_tag, &b->from_tag); } @@ -346,39 +343,31 @@ static struct ice_candidate_pair *__pair_candidate(stream_fd *sfd, struct ice_ag return pair; } -static unsigned int __pair_hash(const void *p) { - const struct ice_candidate_pair *pair = p; +static unsigned int __pair_hash(const struct ice_candidate_pair *pair) { return g_direct_hash(pair->local_intf) ^ g_direct_hash(pair->remote_candidate); } -static int __pair_equal(const void *a, const void *b) { - const struct ice_candidate_pair *A = a, *B = b; +static int __pair_equal(const struct ice_candidate_pair *A, const struct ice_candidate_pair *B) { return A->local_intf == B->local_intf && A->remote_candidate == B->remote_candidate; } -static unsigned int __cand_hash(const void *p) { - const struct ice_candidate *cand = p; +static unsigned int __cand_hash(const struct ice_candidate *cand) { return endpoint_hash(&cand->endpoint) ^ cand->component_id; } -static int __cand_equal(const void *a, const void *b) { - const struct ice_candidate *A = a, *B = b; +static int __cand_equal(const struct ice_candidate *A, const struct ice_candidate *B) { return endpoint_eq(&A->endpoint, &B->endpoint) && A->component_id == B->component_id; } -static unsigned int __found_hash(const void *p) { - const struct ice_candidate *cand = p; +static unsigned int __found_hash(const struct ice_candidate *cand) { return str_hash(&cand->foundation) ^ cand->component_id; } -static int __found_equal(const void *a, const void *b) { - const struct ice_candidate *A = a, *B = b; +static int __found_equal(const struct ice_candidate *A, const struct ice_candidate *B) { return str_equal(&A->foundation, &B->foundation) && A->component_id == B->component_id; } -static unsigned int __trans_hash(const void *p) { - const uint32_t *tp = p; +static unsigned int __trans_hash(const uint32_t *tp) { return tp[0] ^ tp[1] ^ tp[2]; } -static int __trans_equal(const void *a, const void *b) { - const uint32_t *A = a, *B = b; +static int __trans_equal(const uint32_t *A, const uint32_t *B) { return A[0] == B[0] && A[1] == B[1] && A[2] == B[2]; } static int __pair_prio_cmp(const void *a, const void *b) { diff --git a/daemon/janus.c b/daemon/janus.c index 116a5536e..f3e1c7ca2 100644 --- a/daemon/janus.c +++ b/daemon/janus.c @@ -14,9 +14,10 @@ #include "ice.h" #include "log_funcs.h" -TYPED_GHASHTABLE(janus_handles_set, uint64_t, void, g_int64_hash, g_int64_equal, NULL, NULL) +TYPED_GHASHTABLE(janus_handles_set, uint64_t, void, int64_hash, int64_eq, NULL, NULL) +TYPED_DIRECT_FUNCS(websocket_conn_direct_hash, websocket_conn_direct_eq, struct websocket_conn) TYPED_GHASHTABLE(janus_websockets_ht, struct websocket_conn, struct websocket_conn, - g_direct_hash, g_direct_equal, NULL, NULL) + websocket_conn_direct_hash, websocket_conn_direct_eq, NULL, NULL) struct janus_session { // "login" session struct obj obj; @@ -27,7 +28,7 @@ struct janus_session { // "login" session janus_handles_set handles; // handle ID -> 0x1. handle ID owned by janus_handles }; -TYPED_GHASHTABLE(janus_sessions_ht, uint64_t, struct janus_session, g_int64_hash, g_int64_equal, NULL, NULL) +TYPED_GHASHTABLE(janus_sessions_ht, uint64_t, struct janus_session, int64_hash, int64_eq, NULL, NULL) struct janus_handle { // corresponds to a conference participant @@ -36,10 +37,10 @@ struct janus_handle { // corresponds to a conference participant uint64_t room; }; -TYPED_GHASHTABLE(janus_handles_ht, uint64_t, struct janus_handle, g_int64_hash, g_int64_equal, NULL, NULL) +TYPED_GHASHTABLE(janus_handles_ht, uint64_t, struct janus_handle, int64_hash, int64_eq, NULL, NULL) -TYPED_GHASHTABLE(janus_feeds_ht, uint64_t, uint64_t, g_int64_hash, g_int64_equal, g_free, g_free) +TYPED_GHASHTABLE(janus_feeds_ht, uint64_t, uint64_t, int64_hash, int64_eq, g_free, g_free) struct janus_room { uint64_t id; @@ -51,10 +52,10 @@ struct janus_room { janus_feeds_ht feeds; // feed ID -> handle ID }; -TYPED_GHASHTABLE(janus_rooms_ht, uint64_t, struct janus_room, g_int64_hash, g_int64_equal, NULL, NULL) +TYPED_GHASHTABLE(janus_rooms_ht, uint64_t, struct janus_room, int64_hash, int64_eq, NULL, NULL) -TYPED_GHASHTABLE(janus_tokens_ht, char, time_t, g_str_hash, g_str_equal, g_free, g_free) +TYPED_GHASHTABLE(janus_tokens_ht, char, time_t, c_str_hash, c_str_equal, g_free, g_free) static mutex_t janus_lock; diff --git a/daemon/media_player.c b/daemon/media_player.c index 195472b31..a6b745dc4 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -47,7 +47,9 @@ struct media_player_cache_index { struct media_player_content_index index; rtp_payload_type dst_pt; }; -TYPED_GHASHTABLE(media_player_ht, struct media_player, struct media_player, g_direct_hash, g_direct_equal, NULL, NULL) // XXX ref counting players +TYPED_DIRECT_FUNCS(media_player_direct_hash, media_player_direct_eq, struct media_player) +TYPED_GHASHTABLE(media_player_ht, struct media_player, struct media_player, media_player_direct_hash, + media_player_direct_eq, NULL, NULL) // XXX ref counting players struct media_player_cache_entry { volatile bool finished; // "unfinished" elements, only used while decoding is active: diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 2eee5e6b2..c979626a3 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -422,7 +422,7 @@ static GQueue __preferred_lists_for_family[__SF_LAST]; GQueue all_local_interfaces = G_QUEUE_INIT; -TYPED_GHASHTABLE(local_sockets_ht, endpoint_t, stream_fd, endpoint_t_hash, endpoint_t_eq, NULL, stream_fd_put) +TYPED_GHASHTABLE(local_sockets_ht, endpoint_t, stream_fd, endpoint_hash, endpoint_eq, NULL, stream_fd_put) static rwlock_t local_media_socket_endpoints_lock; static local_sockets_ht local_media_socket_endpoints; @@ -776,7 +776,7 @@ static void __interface_append(struct intf_config *ifa, sockfamily_t *fam, bool lif->name = ifa->name; lif->name_base = ifa->name_base; lif->preferred_family = fam; - lif->rr_specs = g_hash_table_new(str_hash, str_equal); + lif->rr_specs = g_hash_table_new((GHashFunc) str_hash, (GEqualFunc) str_equal); g_hash_table_insert(__logical_intf_name_family_hash, lif, lif); if (ifa->local_address.addr.family == fam) { q = __interface_list_for_family(fam); diff --git a/daemon/sdp.c b/daemon/sdp.c index 39a802afa..09f2f2ce2 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -77,9 +77,17 @@ struct sdp_connection { unsigned int parsed:1; }; +INLINE unsigned int attr_id_hash(const enum attr_id *e) { + int i = *e; + return g_int_hash(&i); +} +INLINE gboolean attr_id_eq(const enum attr_id *a, const enum attr_id *b) { + return *a == *b; +} + TYPED_GQUEUE(attributes, struct sdp_attribute) -TYPED_GHASHTABLE(attr_id_ht, enum attr_id, struct sdp_attribute, g_int_hash, g_int_equal, NULL, NULL) -TYPED_GHASHTABLE(attr_list_ht, enum attr_id, attributes_q, g_int_hash, g_int_equal, NULL, g_queue_free) +TYPED_GHASHTABLE(attr_id_ht, enum attr_id, struct sdp_attribute, attr_id_hash, attr_id_eq, NULL, NULL) +TYPED_GHASHTABLE(attr_list_ht, enum attr_id, attributes_q, attr_id_hash, attr_id_eq, NULL, g_queue_free) TYPED_GHASHTABLE_LOOKUP_INSERT(attr_list_ht, NULL, attributes_q_new) struct sdp_attributes { diff --git a/daemon/statistics.c b/daemon/statistics.c index e168548f9..68e6e8e6d 100644 --- a/daemon/statistics.c +++ b/daemon/statistics.c @@ -942,7 +942,7 @@ static void codec_stats_free(struct codec_stats *stats_entry) { g_slice_free1(sizeof(*stats_entry), stats_entry); } -TYPED_GHASHTABLE_IMPL(codec_stats_ht, g_str_hash, g_str_equal, NULL, codec_stats_free) +TYPED_GHASHTABLE_IMPL(codec_stats_ht, c_str_hash, c_str_equal, NULL, codec_stats_free) void statistics_init(void) { gettimeofday(&rtpe_started, NULL); diff --git a/daemon/tcp_listener.c b/daemon/tcp_listener.c index 0f009718c..8fe42259a 100644 --- a/daemon/tcp_listener.c +++ b/daemon/tcp_listener.c @@ -26,7 +26,8 @@ struct streambuf_callback { struct obj *parent; }; -TYPED_GHASHTABLE_IMPL(tcp_streams_ht, g_direct_hash, g_direct_equal, NULL, NULL) +TYPED_DIRECT_FUNCS(tcp_direct_hash, tcp_direct_eq, struct streambuf_stream) +TYPED_GHASHTABLE_IMPL(tcp_streams_ht, tcp_direct_hash, tcp_direct_eq, NULL, NULL) static void tcp_listener_incoming(int fd, void *p) { diff --git a/daemon/websocket.c b/daemon/websocket.c index 973051818..363054506 100644 --- a/daemon/websocket.c +++ b/daemon/websocket.c @@ -26,8 +26,9 @@ struct websocket_output { ssize_t content_length; }; +TYPED_DIRECT_FUNCS(janus_session_hash, janus_session_eq, struct janus_session) TYPED_GHASHTABLE(janus_sessions_ht, struct janus_session, struct janus_session, - g_direct_hash, g_direct_equal, NULL, NULL) + janus_session_hash, janus_session_eq, NULL, NULL) TYPED_GQUEUE(websocket_message, struct websocket_message) TYPED_GQUEUE(websocket_output, struct websocket_output) @@ -383,7 +384,7 @@ static const char *websocket_http_ping(struct websocket_message *wm) { } -TYPED_GHASHTABLE(metric_types_ht, char, void, g_str_hash, g_str_equal, NULL, NULL) +TYPED_GHASHTABLE(metric_types_ht, char, void, c_str_hash, c_str_equal, NULL, NULL) static const char *websocket_http_metrics(struct websocket_message *wm) { ilogs(http, LOG_DEBUG, "Respoding to GET /metrics"); diff --git a/include/call.h b/include/call.h index 062840310..66effcf0b 100644 --- a/include/call.h +++ b/include/call.h @@ -348,7 +348,9 @@ TYPED_GHASHTABLE(codecs_ht, void, rtp_payload_type, g_direct_hash, g_direct_equa TYPED_GHASHTABLE(codec_names_ht, str, GQueue, str_case_hash, str_case_equal, str_free, g_queue_free) TYPED_GHASHTABLE_LOOKUP_INSERT(codec_names_ht, str_free, g_queue_new) TYPED_GQUEUE(subscription, struct media_subscription) -TYPED_GHASHTABLE(subscription_ht, struct call_media, subscription_list, g_direct_hash, g_direct_equal, NULL, NULL) +TYPED_DIRECT_FUNCS(media_direct_hash, media_direct_eq, struct call_media) +TYPED_GHASHTABLE(subscription_ht, struct call_media, subscription_list, media_direct_hash, media_direct_eq, + NULL, NULL) struct codec_store { diff --git a/lib/auxlib.h b/lib/auxlib.h index e7d63b754..ce0cd6be0 100644 --- a/lib/auxlib.h +++ b/lib/auxlib.h @@ -97,6 +97,13 @@ INLINE void random_string(unsigned char *buf, int len) { (void) ret; } +INLINE unsigned int c_str_hash(const char *s) { + return g_str_hash(s); +} +INLINE gboolean c_str_equal(const char *a, const char *b) { + return g_str_equal(a, b); +} + /*** MUTEX ABSTRACTION ***/ @@ -464,6 +471,13 @@ INLINE pid_t gettid(void) { } #endif +INLINE unsigned int int64_hash(const uint64_t *s) { + return g_int64_hash(s); +} +INLINE gboolean int64_eq(const uint64_t *a, const uint64_t *b) { + return *a == *b; +} + /*** TAINT FUNCTIONS ***/ diff --git a/lib/codeclib.c b/lib/codeclib.c index 8fcf96f90..9bf9a8387 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -1581,7 +1581,7 @@ void codeclib_init(int print) { avformat_network_init(); av_log_set_callback(avlog_ilog); - codecs_ht = g_hash_table_new(str_case_hash, str_case_equal); + codecs_ht = g_hash_table_new((GHashFunc) str_case_hash, (GEqualFunc) str_case_equal); codecs_ht_by_av = g_hash_table_new(g_direct_hash, g_direct_equal); cc_init(); diff --git a/lib/containers.h b/lib/containers.h index 827f31d38..dec4880fa 100644 --- a/lib/containers.h +++ b/lib/containers.h @@ -106,7 +106,9 @@ #define TYPED_GHASHTABLE_IMPL(type_name, hash_func, eq_func, key_free_func, value_free_func) \ static inline type_name type_name##_new(void) { \ - GHashTable *ht = g_hash_table_new_full(hash_func, eq_func, \ + unsigned int (*__hash_func)(__typeof__(((type_name *)0)->__ckey)) = hash_func; \ + gboolean (*__eq_func)(__typeof__(((type_name *)0)->__ckey), __typeof__(((type_name *)0)->__ckey)) = eq_func; \ + GHashTable *ht = g_hash_table_new_full((GHashFunc) __hash_func, (GEqualFunc) __eq_func, \ (GDestroyNotify) key_free_func, \ (GDestroyNotify) value_free_func); \ return (type_name) { ht }; \ @@ -132,6 +134,14 @@ return r; \ } +#define TYPED_DIRECT_FUNCS(hash_name, eq_name, type) \ + static inline unsigned int hash_name(const type *a) { \ + return g_direct_hash(a); \ + } \ + static inline gboolean eq_name(const type *a, const type *b) { \ + return a == b; \ + } + #define TYPED_GQUEUE(type_name, contained_type) \ typedef union type_name##_slist type_name##_slist; \ diff --git a/lib/socket.c b/lib/socket.c index 382be607e..9d44ddfd1 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -542,15 +542,9 @@ gint sockaddr_t_eq(gconstpointer a, gconstpointer b) { unsigned int endpoint_hash(const endpoint_t *a) { return sockaddr_hash(&a->address) ^ a->port; } -bool endpoint_eq(const endpoint_t *a, const endpoint_t *b) { +gboolean endpoint_eq(const endpoint_t *a, const endpoint_t *b) { return sockaddr_eq(&a->address, &b->address) && a->port == b->port; } -guint endpoint_t_hash(gconstpointer a) { - return endpoint_hash(a); -} -gint endpoint_t_eq(gconstpointer a, const void *b) { - return endpoint_eq(a, b); -} diff --git a/lib/socket.h b/lib/socket.h index 927d27fd6..e5bd0da57 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -294,9 +294,7 @@ guint sockaddr_t_hash(gconstpointer); // for glib gint sockaddr_t_eq(gconstpointer, gconstpointer); // true/false, for glib unsigned int endpoint_hash(const endpoint_t *); -bool endpoint_eq(const endpoint_t *, const endpoint_t *); /* true/false */ -guint endpoint_t_hash(gconstpointer); // for glib -gint endpoint_t_eq(gconstpointer, gconstpointer); // true/false, for glib +gboolean endpoint_eq(const endpoint_t *, const endpoint_t *); /* true/false */ INLINE sockfamily_t *get_socket_family_enum(enum socket_families i) { if (i >= __SF_LAST) diff --git a/lib/str.c b/lib/str.c index c4183b116..e41e36599 100644 --- a/lib/str.c +++ b/lib/str.c @@ -4,7 +4,7 @@ #include /* adapted from g_str_hash() from glib */ -guint str_hash(gconstpointer ss) { +guint str_hash(const str *ss) { const str *s = ss; guint ret = 5381; str it = *s; @@ -18,11 +18,11 @@ guint str_hash(gconstpointer ss) { return ret; } -gboolean str_equal(gconstpointer a, gconstpointer b) { +gboolean str_equal(const str *a, const str *b) { return str_cmp_str((str *) a, (str *) b) == 0; } -guint str_case_hash(gconstpointer ss) { +guint str_case_hash(const str *ss) { const str *s = ss; guint ret = 5381; str it = *s; @@ -36,7 +36,7 @@ guint str_case_hash(gconstpointer ss) { return ret; } -gboolean str_case_equal(gconstpointer a, gconstpointer b) { +gboolean str_case_equal(const str *a, const str *b) { return str_casecmp_str((str *) a, (str *) b) == 0; } diff --git a/lib/str.h b/lib/str.h index 6a0c68b2e..a749ff2d3 100644 --- a/lib/str.h +++ b/lib/str.h @@ -178,10 +178,10 @@ INLINE GString *g_string_new_str(void); INLINE str *g_string_free_str(GString *gs); /* for GHashTables */ -guint str_hash(gconstpointer s); -gboolean str_equal(gconstpointer a, gconstpointer b); -guint str_case_hash(gconstpointer s); -gboolean str_case_equal(gconstpointer a, gconstpointer b); +guint str_hash(const str *s); +gboolean str_equal(const str *a, const str *b); +guint str_case_hash(const str *s); +gboolean str_case_equal(const str *a, const str *b); TYPED_GHASHTABLE(str_case_ht, str, str, str_case_hash, str_case_equal, free, NULL) TYPED_GHASHTABLE(str_case_value_ht, str, str, str_case_hash, str_case_equal, free, free)