From 55bbe92677e4acaaf866cbeae3be6df8925e4618 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Sun, 31 Jul 2016 15:17:40 +0100 Subject: [PATCH] ares_init_options: only propagate init failures from options Commit 46bb820be3a8 ("ares_init_options: don't lose init failure") changed init behaviour so that earlier errors in initialization weren't lost. In particular, if the user passes in specific options but they are not applied (e.g. because of an allocation failure), that failure needs to be reported back to the user; this also applies when duplicating a channel with ares_dup(). However, other initialization failures can be ignored and overridden -- in particular, if init_by_resolv_conf() or init_by_environment() fail, then falling back to default values is OK. So only preserve failures from the init_by_options() stage, not from all initialization stages. Fixes issue 60. --- ares_init.c | 30 +++++++++++++----------------- test/ares-test-init.cc | 4 ++-- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/ares_init.c b/ares_init.c index 61edf42d..4c7f7f96 100644 --- a/ares_init.c +++ b/ares_init.c @@ -112,7 +112,6 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, ares_channel channel; int i; int status = ARES_SUCCESS; - int status2; struct timeval now; #ifdef CURLDEBUG @@ -190,18 +189,17 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, * precedence to lowest. */ - if (status == ARES_SUCCESS) { - status = init_by_options(channel, options, optmask); - if (status != ARES_SUCCESS) - DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n", - ares_strerror(status))); - } - if (status == ARES_SUCCESS) { - status = init_by_environment(channel); - if (status != ARES_SUCCESS) - DEBUGF(fprintf(stderr, "Error: init_by_environment failed: %s\n", - ares_strerror(status))); + status = init_by_options(channel, options, optmask); + if (status != ARES_SUCCESS) { + DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n", + ares_strerror(status))); + /* If we fail to apply user-specified options, fail the whole init process */ + goto done; } + status = init_by_environment(channel); + if (status != ARES_SUCCESS) + DEBUGF(fprintf(stderr, "Error: init_by_environment failed: %s\n", + ares_strerror(status))); if (status == ARES_SUCCESS) { status = init_by_resolv_conf(channel); if (status != ARES_SUCCESS) @@ -213,13 +211,10 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, * No matter what failed or succeeded, seed defaults to provide * useful behavior for things that we missed. */ - status2 = init_by_defaults(channel); - if (status2 != ARES_SUCCESS) { + status = init_by_defaults(channel); + if (status != ARES_SUCCESS) DEBUGF(fprintf(stderr, "Error: init_by_defaults failed: %s\n", ares_strerror(status))); - if (status == ARES_SUCCESS) - status = status2; - } /* Generate random key */ @@ -232,6 +227,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, ares_strerror(status))); } +done: if (status != ARES_SUCCESS) { /* Something failed; clean up memory we may have allocated. */ diff --git a/test/ares-test-init.cc b/test/ares-test-init.cc index 04fc24b4..3f856b71 100644 --- a/test/ares-test-init.cc +++ b/test/ares-test-init.cc @@ -451,8 +451,8 @@ CONTAINED_TEST_F(LibraryTest, ContainerResolvConfNotReadable, "myhostname", "mydomainname.org", filelist) { ares_channel channel = nullptr; MakeUnreadable hide("/etc/resolv.conf"); - // Unavailable /etc/resolv.conf fails initialization. - EXPECT_EQ(ARES_EFILE, ares_init(&channel)); + // Unavailable /etc/resolv.conf falls back to defaults + EXPECT_EQ(ARES_SUCCESS, ares_init(&channel)); return HasFailure(); } CONTAINED_TEST_F(LibraryTest, ContainerNsswitchConfNotReadable,