[PATCH v2] resolv: Avoid duplicate query if search list contains '.' (bug 33804)

Carlos O'Donell codonell@redhat.com
Tue Mar 3 19:55:01 GMT 2026


On 3/3/26 12:50 PM, Florian Weimer wrote:
> From: Carlos Peón Costa <carlospeon@gmail.com>
> 
> Co-authored-by: Florian Weimer <fweimer@redhat.com>
> Signed-off-by: Florian Weimer <fweimer@redhat.com>

Original - fixed the issue in the res_query.c code.
v2 - fixed the atomic issue in the test case.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
  
> ---
> v2: Use _Atomic unsigned int for the query counter.  Add a comment.
> 
>   resolv/res_query.c            | 11 +++++++----
>   resolv/tst-resolv-no-search.c | 12 ++++++++++++
>   2 files changed, 19 insertions(+), 4 deletions(-)
> 
> diff --git a/resolv/res_query.c b/resolv/res_query.c
> index 039c25a3c3..30ace9d06d 100644
> --- a/resolv/res_query.c
> +++ b/resolv/res_query.c
> @@ -354,7 +354,7 @@ __res_context_search (struct resolv_context *ctx,
>   	char tmp[NS_MAXDNAME];
>   	u_int dots;
>   	int trailing_dot, ret, saved_herrno;
> -	int got_nodata = 0, got_servfail = 0, root_on_list = 0;
> +	int got_nodata = 0, got_servfail = 0;
>   	int tried_as_is = 0;
>   	int searched = 0;
>   
> @@ -433,8 +433,11 @@ __res_context_search (struct resolv_context *ctx,
>   			   domain.  */
>   			if (dname[0] == '.')
>   				dname++;
> -			if (dname[0] == '\0')
> -				root_on_list++;
> +			if (dname[0] == '\0') {
> +				if (tried_as_is)
> +					continue;
> +				tried_as_is++;
> +			}
>   
>   			ret = __res_context_querydomain
>   			  (ctx, name, dname, class, type,
> @@ -506,7 +509,7 @@ __res_context_search (struct resolv_context *ctx,
>   	 * unless RES_NOTLDQUERY is set and there were no dots.
>   	 */
>   	if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
> -	    && !(tried_as_is || root_on_list)) {
> +	    && !tried_as_is) {
>   		ret = __res_context_querydomain
>   		  (ctx, name, NULL, class, type,
>   		   answer, anslen, answerp, answerp2, nanswerp2,
> diff --git a/resolv/tst-resolv-no-search.c b/resolv/tst-resolv-no-search.c
> index 29701d4772..7d78d4044c 100644
> --- a/resolv/tst-resolv-no-search.c
> +++ b/resolv/tst-resolv-no-search.c
> @@ -27,6 +27,11 @@
>   #include <support/resolv_test.h>
>   #include <support/support.h>
>   
> +/* Used to check for duplicated queries (bug 33804).  POSIX does not
> +   explicitly say that socket calls (as used in the resolver tests)
> +   provide synchronization.  */
> +static _Atomic unsigned int query_count;

OK. Perfect. While _Atomic does not guarantee a total global order, it
occurs by nature of the program and the call to the function in question.
There is write-read coherence that ensures the main thread sees the
modified value.

> +
>   /* Check that plain res_init loads the configuration as expected.  */
>   static void
>   test_res_init (void *ignored)
> @@ -43,6 +48,7 @@ response (const struct resolv_response_context *ctx,
>   {
>     TEST_VERIFY_EXIT (qclass == C_IN);
>     TEST_COMPARE (ctx->server_index, 0);
> +  ++query_count;
>   
>     if (strncmp (qname, "does-not-exist", strlen ("does-not-exist")) == 0)
>       {
> @@ -82,12 +88,16 @@ check_h (const char *name, int family, const char *expected)
>     if (family == AF_INET)
>       {
>         char *query = xasprintf ("gethostbyname (\"%s\")", name);
> +      query_count = 0;
>         check_hostent (query, gethostbyname (name), expected);
> +      TEST_COMPARE (query_count, 1);
>         free (query);
>       }
>     {
>       char *query = xasprintf ("gethostbyname2 (\"%s\", %d)", name, family);
> +    query_count = 0;
>       check_hostent (query, gethostbyname2 (name, family), expected);
> +    TEST_COMPARE (query_count, 1);
>       free (query);
>     }
>   }
> @@ -98,8 +108,10 @@ check_ai (const char *name, int family, const char *expected)
>     struct addrinfo hints = { .ai_family = family, .ai_socktype = SOCK_STREAM, };
>     struct addrinfo *ai;
>     char *query = xasprintf ("%s:80 [%d]", name, hints.ai_family);
> +  query_count = 0;
>     int ret = getaddrinfo (name, "80", &hints, &ai);
>     check_addrinfo (query, ai, ret, expected);
> +  TEST_COMPARE (query_count, family == AF_UNSPEC ? 2 : 1);
>     if (ret == 0)
>       freeaddrinfo (ai);
>     free (query);
> 
> base-commit: c995686e2cbe2a3ab2a11877a61c14a2e1fc35cb
> 


-- 
Cheers,
Carlos



More information about the Libc-alpha mailing list