diff options
-rw-r--r-- | apps/app_mixmonitor.c | 2 | ||||
-rw-r--r-- | bridges/bridge_softmix.c | 1 | ||||
-rw-r--r-- | include/asterisk/utils.h | 8 | ||||
-rw-r--r-- | main/cli.c | 27 | ||||
-rw-r--r-- | main/db.c | 8 | ||||
-rw-r--r-- | main/format_cap.c | 9 | ||||
-rw-r--r-- | main/json.c | 2 | ||||
-rw-r--r-- | main/message.c | 14 | ||||
-rw-r--r-- | main/pbx.c | 18 | ||||
-rw-r--r-- | main/rtp_engine.c | 24 | ||||
-rw-r--r-- | main/stasis.c | 19 | ||||
-rw-r--r-- | main/stasis_channels.c | 4 | ||||
-rw-r--r-- | main/tcptls.c | 5 | ||||
-rw-r--r-- | main/utils.c | 8 | ||||
-rw-r--r-- | res/ari/resource_bridges.c | 1 | ||||
-rw-r--r-- | res/ari/resource_events.c | 4 | ||||
-rw-r--r-- | res/res_pjproject.c | 7 | ||||
-rw-r--r-- | res/res_pjsip/config_transport.c | 5 | ||||
-rw-r--r-- | res/res_pjsip/location.c | 5 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 2 | ||||
-rw-r--r-- | res/res_xmpp.c | 7 | ||||
-rw-r--r-- | res/stasis/app.c | 16 | ||||
-rw-r--r-- | tests/test_sorcery_memory_cache_thrash.c | 6 |
23 files changed, 133 insertions, 69 deletions
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index 2922e0cd3..bb47cfc34 100644 --- a/apps/app_mixmonitor.c +++ b/apps/app_mixmonitor.c @@ -813,6 +813,8 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) { ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n"); + ast_free(mixmonitor_ds); + return -1; } ast_mutex_init(&mixmonitor_ds->lock); diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 9197df6fb..f490967e2 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -502,7 +502,6 @@ static int append_source_streams(struct ast_stream_topology *dest, if (ast_asprintf(&stream_clone_name, "%s_%s_%s", SOFTBRIDGE_VIDEO_DEST_PREFIX, channel_name, ast_stream_get_name(stream)) < 0) { - ast_free(stream_clone_name); return -1; } diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 423d73b26..0a12b1d8a 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -622,7 +622,13 @@ int __ast_vasprintf(char **ret, const char *fmt, va_list ap, const char *file, i DEBUG_CHAOS_RETURN(DEBUG_CHAOS_ALLOC_CHANCE, -1); - if ((res = vasprintf(ret, fmt, ap)) == -1) { + res = vasprintf(ret, fmt, ap); + if (res < 0) { + /* + * *ret is undefined so set to NULL to ensure it is + * initialized to something useful. + */ + *ret = NULL; MALLOC_FAILURE_MSG; } diff --git a/main/cli.c b/main/cli.c index 0896181b0..5c16e8b7a 100644 --- a/main/cli.c +++ b/main/cli.c @@ -1362,31 +1362,6 @@ static char *handle_commandnummatches(struct ast_cli_entry *e, int cmd, struct a return CLI_SUCCESS; } -static char *handle_commandcomplete(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -{ - char *buf; - switch (cmd) { - case CLI_INIT: - e->command = "_command complete"; - e->usage = - "Usage: _command complete \"<line>\" text state\n" - " This function is used internally to help with command completion and should.\n" - " never be called by the user directly.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - if (a->argc != 5) - return CLI_SHOWUSAGE; - buf = __ast_cli_generator(a->argv[2], a->argv[3], atoi(a->argv[4]), 0); - if (buf) { - ast_cli(a->fd, "%s", buf); - ast_free(buf); - } else - ast_cli(a->fd, "NULL\n"); - return CLI_SUCCESS; -} - struct channel_set_debug_args { int fd; int is_off; @@ -1817,8 +1792,6 @@ static char *handle_cli_wait_fullybooted(struct ast_cli_entry *e, int cmd, struc static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); static struct ast_cli_entry cli_cli[] = { - /* Deprecated, but preferred command is now consolidated (and already has a deprecated command for it). */ - AST_CLI_DEFINE(handle_commandcomplete, "Command complete"), AST_CLI_DEFINE(handle_commandnummatches, "Returns number of command matches"), AST_CLI_DEFINE(handle_commandmatchesarray, "Returns command matches array"), @@ -191,9 +191,11 @@ static int convert_bdb_to_sqlite3(void) char *cmd; int res; - ast_asprintf(&cmd, "%s/astdb2sqlite3 '%s'\n", ast_config_AST_SBIN_DIR, ast_config_AST_DB); - res = ast_safe_system(cmd); - ast_free(cmd); + res = ast_asprintf(&cmd, "%s/astdb2sqlite3 '%s'\n", ast_config_AST_SBIN_DIR, ast_config_AST_DB); + if (0 <= res) { + res = ast_safe_system(cmd); + ast_free(cmd); + } return res; } diff --git a/main/format_cap.c b/main/format_cap.c index b0897c001..d71ccdbaa 100644 --- a/main/format_cap.c +++ b/main/format_cap.c @@ -160,13 +160,16 @@ static inline int format_cap_framed_init(struct format_cap_framed *framed, struc } list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format)); + /* This takes the allocation reference */ + if (AST_VECTOR_APPEND(&cap->preference_order, framed)) { + ao2_ref(framed, -1); + return -1; + } + /* Order doesn't matter for formats, so insert at the head for performance reasons */ ao2_ref(framed, +1); AST_LIST_INSERT_HEAD(list, framed, entry); - /* This takes the allocation reference */ - AST_VECTOR_APPEND(&cap->preference_order, framed); - cap->framing = MIN(cap->framing, framing ? framing : ast_format_get_default_ms(format)); return 0; diff --git a/main/json.c b/main/json.c index 9004978b4..56df7f401 100644 --- a/main/json.c +++ b/main/json.c @@ -460,7 +460,7 @@ struct ast_json *ast_json_vstringf(const char *format, va_list args) if (format) { int err = ast_vasprintf(&str, format, args); - if (err > 0) { + if (err >= 0) { ret = json_string(str); ast_free(str); } diff --git a/main/message.c b/main/message.c index fcdf705fe..ac7965ea7 100644 --- a/main/message.c +++ b/main/message.c @@ -1362,7 +1362,12 @@ int ast_msg_tech_register(const struct ast_msg_tech *tech) return -1; } - AST_VECTOR_APPEND(&msg_techs, tech); + if (AST_VECTOR_APPEND(&msg_techs, tech)) { + ast_log(LOG_ERROR, "Failed to register message technology for '%s'\n", + tech->name); + ast_rwlock_unlock(&msg_techs_lock); + return -1; + } ast_verb(3, "Message technology '%s' registered.\n", tech->name); ast_rwlock_unlock(&msg_techs_lock); @@ -1417,7 +1422,12 @@ int ast_msg_handler_register(const struct ast_msg_handler *handler) return -1; } - AST_VECTOR_APPEND(&msg_handlers, handler); + if (AST_VECTOR_APPEND(&msg_handlers, handler)) { + ast_log(LOG_ERROR, "Failed to register message handler for '%s'\n", + handler->name); + ast_rwlock_unlock(&msg_handlers_lock); + return -1; + } ast_verb(2, "Message handler '%s' registered.\n", handler->name); ast_rwlock_unlock(&msg_handlers_lock); diff --git a/main/pbx.c b/main/pbx.c index 2366b72b0..b5602b55c 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -6692,7 +6692,11 @@ int ast_context_add_include2(struct ast_context *con, const char *value, } /* ... include new context into context list, unlock, return */ - AST_VECTOR_APPEND(&con->includes, new_include); + if (AST_VECTOR_APPEND(&con->includes, new_include)) { + include_free(new_include); + ast_unlock_context(con); + return -1; + } ast_verb(3, "Including context '%s' in context '%s'\n", ast_get_include_name(new_include), ast_get_context_name(con)); @@ -6754,7 +6758,11 @@ int ast_context_add_switch2(struct ast_context *con, const char *value, } /* ... sw new context into context list, unlock, return */ - AST_VECTOR_APPEND(&con->alts, new_sw); + if (AST_VECTOR_APPEND(&con->alts, new_sw)) { + sw_free(new_sw); + ast_unlock_context(con); + return -1; + } ast_verb(3, "Including switch '%s/%s' in context '%s'\n", ast_get_switch_name(new_sw), ast_get_switch_data(new_sw), ast_get_context_name(con)); @@ -6842,7 +6850,11 @@ int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const return -1; } } - AST_VECTOR_APPEND(&con->ignorepats, ignorepat); + if (AST_VECTOR_APPEND(&con->ignorepats, ignorepat)) { + ignorepat_free(ignorepat); + ast_unlock_context(con); + return -1; + } ast_unlock_context(con); return 0; diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 0aed8e97c..2431ffc0c 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -802,7 +802,10 @@ static void rtp_codecs_payload_replace_rx(struct ast_rtp_codecs *codecs, int pay ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_rx, payload), "cleaning up rx mapping vector element about to be replaced"); } - AST_VECTOR_REPLACE(&codecs->payload_mapping_rx, payload, new_type); + if (AST_VECTOR_REPLACE(&codecs->payload_mapping_rx, payload, new_type)) { + ao2_ref(new_type, -1); + return; + } payload_mapping_rx_clear_primary(codecs, new_type); } @@ -924,7 +927,10 @@ static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_r ao2_t_cleanup(AST_VECTOR_GET(&dest->payload_mapping_tx, idx), "cleaning up tx mapping vector element about to be replaced"); } - AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, type); + if (AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, type)) { + ao2_ref(type, -1); + continue; + } if (instance && instance->engine && instance->engine->payload_set) { ao2_lock(instance); @@ -1038,9 +1044,10 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload), "cleaning up replaced tx payload type"); } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type); - if (instance && instance->engine && instance->engine->payload_set) { + if (AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type)) { + ao2_ref(new_type, -1); + } else if (instance && instance->engine && instance->engine->payload_set) { ao2_lock(instance); instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); ao2_unlock(instance); @@ -1116,9 +1123,10 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt), "cleaning up replaced tx payload type"); } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type); - if (instance && instance->engine && instance->engine->payload_set) { + if (AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type)) { + ao2_ref(new_type, -1); + } else if (instance && instance->engine && instance->engine->payload_set) { ao2_lock(instance); instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); ao2_unlock(instance); @@ -1215,7 +1223,9 @@ int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int pay if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload)); } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type); + if (AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type)) { + ao2_ref(type, -1); + } } else { ao2_ref(type, -1); } diff --git a/main/stasis.c b/main/stasis.c index a82e938f4..186d88fdd 100644 --- a/main/stasis.c +++ b/main/stasis.c @@ -908,7 +908,7 @@ struct stasis_forward *stasis_forward_all(struct stasis_topic *from_topic, { int res; size_t idx; - RAII_VAR(struct stasis_forward *, forward, NULL, ao2_cleanup); + struct stasis_forward *forward; if (!from_topic || !to_topic) { return NULL; @@ -921,7 +921,7 @@ struct stasis_forward *stasis_forward_all(struct stasis_topic *from_topic, /* Forwards to ourselves are implicit. */ if (to_topic == from_topic) { - return ao2_bump(forward); + return forward; } forward->from_topic = ao2_bump(from_topic); @@ -932,6 +932,7 @@ struct stasis_forward *stasis_forward_all(struct stasis_topic *from_topic, if (res != 0) { ao2_unlock(from_topic); ao2_unlock(to_topic); + ao2_ref(forward, -1); return NULL; } @@ -941,7 +942,7 @@ struct stasis_forward *stasis_forward_all(struct stasis_topic *from_topic, ao2_unlock(from_topic); ao2_unlock(to_topic); - return ao2_bump(forward); + return forward; } static void subscription_change_dtor(void *obj) @@ -1239,10 +1240,9 @@ struct ast_multi_object_blob *ast_multi_object_blob_create(struct ast_json *blob void ast_multi_object_blob_add(struct ast_multi_object_blob *multi, enum stasis_user_multi_object_snapshot_type type, void *object) { - if (!multi || !object) { - return; + if (!multi || !object || AST_VECTOR_APPEND(&multi->snapshots[type], object)) { + ao2_cleanup(object); } - AST_VECTOR_APPEND(&multi->snapshots[type],object); } /*! \brief Publish single channel user event (for app_userevent compatibility) */ @@ -1342,7 +1342,7 @@ static struct ast_str *multi_object_blob_to_ami(void *obj) for (type = 0; type < STASIS_UMOS_MAX; ++type) { for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) { - char *name = ""; + char *name = NULL; void *snapshot = AST_VECTOR_GET(&multi->snapshots[type], i); ami_snapshot = NULL; @@ -1352,11 +1352,11 @@ static struct ast_str *multi_object_blob_to_ami(void *obj) switch (type) { case STASIS_UMOS_CHANNEL: - ami_snapshot = ast_manager_build_channel_state_string_prefix(snapshot, name); + ami_snapshot = ast_manager_build_channel_state_string_prefix(snapshot, name ?: ""); break; case STASIS_UMOS_BRIDGE: - ami_snapshot = ast_manager_build_bridge_state_string_prefix(snapshot, name); + ami_snapshot = ast_manager_build_bridge_state_string_prefix(snapshot, name ?: ""); break; case STASIS_UMOS_ENDPOINT: @@ -1367,6 +1367,7 @@ static struct ast_str *multi_object_blob_to_ami(void *obj) ast_str_append(&ami_str, 0, "%s", ast_str_buffer(ami_snapshot)); ast_free(ami_snapshot); } + ast_free(name); } } diff --git a/main/stasis_channels.c b/main/stasis_channels.c index dd71b8651..b81dbe599 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -891,7 +891,7 @@ struct ast_json *ast_channel_snapshot_to_json( const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize) { - RAII_VAR(struct ast_json *, json_chan, NULL, ast_json_unref); + struct ast_json *json_chan; if (snapshot == NULL || (sanitize && sanitize->channel_snapshot @@ -924,7 +924,7 @@ struct ast_json *ast_channel_snapshot_to_json( ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars)); } - return ast_json_ref(json_chan); + return json_chan; } int ast_channel_snapshot_cep_equal( diff --git a/main/tcptls.c b/main/tcptls.c index 4a95f72ef..a6d0538af 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -316,7 +316,10 @@ static void __ssl_setup_certs(struct ast_tls_config *cfg, const size_t cert_file static int __ssl_setup(struct ast_tls_config *cfg, int client) { #ifndef DO_SSL - cfg->enabled = 0; + if (cfg->enabled) { + ast_log(LOG_NOTICE, "Configured without OpenSSL Development Headers"); + cfg->enabled = 0; + } return 0; #else int disable_ssl = 0; diff --git a/main/utils.c b/main/utils.c index a73bf9d42..c553207b6 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2340,7 +2340,13 @@ int __ast_asprintf(const char *file, int lineno, const char *func, char **ret, c va_list ap; va_start(ap, fmt); - if ((res = vasprintf(ret, fmt, ap)) == -1) { + res = vasprintf(ret, fmt, ap); + if (res < 0) { + /* + * *ret is undefined so set to NULL to ensure it is + * initialized to something useful. + */ + *ret = NULL; MALLOC_FAILURE_MSG; } va_end(ap); diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index aab78ce18..cd289aa12 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -392,7 +392,6 @@ static int ari_bridges_play_helper(const char **args_media, if (ast_asprintf(playback_url, "/playbacks/%s", stasis_app_playback_get_id(playback)) == -1) { - playback_url = NULL; ast_ari_response_alloc_failed(response); return -1; } diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c index 4be5d0223..992c562a7 100644 --- a/res/ari/resource_events.c +++ b/res/ari/resource_events.c @@ -108,7 +108,9 @@ static void stasis_app_message_handler( msg_application); } else if (!session->ws_session) { /* If the websocket is NULL, the message goes to the queue */ - AST_VECTOR_APPEND(&session->message_queue, message); + if (!AST_VECTOR_APPEND(&session->message_queue, message)) { + ast_json_ref(message); + } ast_log(LOG_WARNING, "Queued '%s' message for Stasis app '%s'; websocket is not ready\n", msg_type, diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 46c82aa9e..86b2502e5 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -227,11 +227,16 @@ static void log_forwarder(int level, const char *data, int len) static void capture_buildopts_cb(int level, const char *data, int len) { + char *dup; + if (strstr(data, "Teluu") || strstr(data, "Dumping")) { return; } - AST_VECTOR_ADD_SORTED(&buildopts, ast_strdup(ast_skip_blanks(data)), strcmp); + dup = ast_strdup(ast_skip_blanks(data)); + if (AST_VECTOR_ADD_SORTED(&buildopts, dup, strcmp)) { + ast_free(dup); + } } #pragma GCC diagnostic ignored "-Wformat-nonliteral" diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 0c804b82a..2f29456ab 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -683,6 +683,11 @@ static int transport_tls_file_handler(const struct aco_option *opt, struct ast_v return -1; } + if (ast_strlen_zero(var->value)) { + /* Ignore empty options */ + return 0; + } + if (!ast_file_is_readable(var->value)) { ast_log(LOG_ERROR, "Transport: %s: %s %s is either missing or not readable\n", ast_sorcery_object_get_id(obj), var->name, var->value); diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 9945c7c10..0d7b3da31 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1219,6 +1219,11 @@ static int contact_apply_handler(const struct ast_sorcery *sorcery, void *object struct ast_sip_contact_status *status; struct ast_sip_contact *contact = object; + if (ast_strlen_zero(contact->uri)) { + ast_log(LOG_ERROR, "A URI on dynamic contact '%s' is empty\n", + ast_sorcery_object_get_id(contact)); + return -1; + } status = ast_res_pjsip_find_or_create_contact_status(contact); ao2_cleanup(status); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index a6afe5e53..168d86989 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -508,6 +508,8 @@ int ast_sip_auth_vector_init(struct ast_sip_auth_vector *auths, const char *valu goto failure; } if (AST_VECTOR_APPEND(auths, val)) { + ast_free(val); + goto failure; } } diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 8a06a6c35..f683557a5 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -3909,8 +3909,11 @@ static int fetch_access_token(struct ast_xmpp_client_config *cfg) struct ast_json_error error; RAII_VAR(struct ast_json *, jobj, NULL, ast_json_unref); - ast_asprintf(&cmd, "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)", - url, cfg->oauth_clientid, cfg->oauth_secret, cfg->refresh_token); + if (ast_asprintf(&cmd, + "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)", + url, cfg->oauth_clientid, cfg->oauth_secret, cfg->refresh_token) < 0) { + return -1; + } ast_debug(2, "Performing OAuth 2.0 authentication for client '%s' using command: %s\n", cfg->name, cmd); diff --git a/res/stasis/app.c b/res/stasis/app.c index b0bcf3c42..0b44bf3c6 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -871,9 +871,21 @@ int stasis_app_get_debug(struct stasis_app *app) int stasis_app_get_debug_by_name(const char *app_name) { - RAII_VAR(struct stasis_app *, app, stasis_app_get_by_name(app_name), ao2_cleanup); + int debug_enabled = 0; - return (app ? app->debug : 0) || global_debug; + if (global_debug) { + debug_enabled = 1; + } else { + struct stasis_app *app = stasis_app_get_by_name(app_name); + + if (app) { + if (app->debug) { + debug_enabled = 1; + } + ao2_ref(app, -1); + } + } + return debug_enabled; } void stasis_app_set_global_debug(int debug) diff --git a/tests/test_sorcery_memory_cache_thrash.c b/tests/test_sorcery_memory_cache_thrash.c index c0d25feb3..dfe7a7c81 100644 --- a/tests/test_sorcery_memory_cache_thrash.c +++ b/tests/test_sorcery_memory_cache_thrash.c @@ -218,7 +218,11 @@ static struct sorcery_memory_cache_thrash *sorcery_memory_cache_thrash_create(co /* This purposely holds no ref as the main thrash structure does */ thread->sorcery = thrash->sorcery; - AST_VECTOR_APPEND(&thrash->threads, thread); + if (AST_VECTOR_APPEND(&thrash->threads, thread)) { + ast_free(thread); + ao2_ref(thrash, -1); + return NULL; + } } return thrash; |