Bug 3959 - SEGV crash due to random libads/dns.c qsort() comparison function
Summary: SEGV crash due to random libads/dns.c qsort() comparison function
Status: RESOLVED FIXED
Alias: None
Product: Samba 3.0
Classification: Unclassified
Component: winbind (show other bugs)
Version: 3.0.23a
Hardware: Sparc Solaris
: P3 critical
Target Milestone: none
Assignee: Gerald (Jerry) Carter (dead mail address)
QA Contact: Samba QA Contact
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-07-24 22:37 UTC by William Charles
Modified: 2024-04-10 22:46 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description William Charles 2006-07-24 22:37:38 UTC
The qsort() used in libads/dns.c is regularly trashing the list of Domain Controllers. This is because the comparison function dnssrvcmp() is using rand(). AFAIK, that's not recommended -- repeated calls to the qsort() comparison function with the same args _must_ return the same, consistent results.


See here: 

http://www.opengroup.org/onlinepubs/009695399/functions/qsort.html

Quote: When the same objects (consisting of width bytes, irrespective of their current positions in the array) are passed more than once to the comparison function, the results shall be consistent with one another. That is, they shall define a total ordering on the array. 


And discussions, along similar lines here:

http://www.thescripts.com/forum/thread212502.html
http://sourceware.org/ml/binutils/2004-06/msg00091.html

Quote: Finally, and if my crystal ball is working again, the third common problem is the one you are actually running into. If a comparison function is not 100% consistent in deciding that, when a<b, b>a, some qsort() variants will run wild. Hence this:

	int bad_compare(const void *l, const void *r) {
		return (rand() % 3) - 1;
	}

is a terrible function to use, and causes real qsort()s to run off into the weeds. 


A modified comparison routine like this works for me:

static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
{
        if ( a->priority == b->priority ) {

                if ( a->weight == b->weight )
                    return 0;

                /* higher weights should be sorted lower */
                if ( a->weight > b->weight )
                        return -1;
                else
                        return 1;
        }

        if ( a->priority < b->priority )
                return -1;

        return 1;
}
Comment 1 Gerald (Jerry) Carter (dead mail address) 2006-07-25 14:55:37 UTC
Great assessment.  Thanks.  The original code was really a 
half way attempt to implement the SRV priority and weight 
assignments in RFC 2782.  I'll back it out and do a complete
version later.  Applying patch.
Comment 2 Gerald (Jerry) Carter (dead mail address) 2006-07-25 14:58:11 UTC
applied for a potential 3.0.23b