[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-20 Thread muks at banu dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #16 from Mukund Sivaraman  ---
(In reply to Andrew Pinski from comment #15)
> > At the very least, if it is possible to detect that the pointer is NULL by
> > static analysis and it is being passed to a function that has the notnull
> > attribute, please warn mentioning inferences being made.
> The warning did not make it into gcc 4.9 due to the patches to do the
> warning were not ready. Gcc 4.10 should warn about it. If it does not then
> that is a bug.

Thank you for this. :) It should detect at least some cases in that case.

If qsort() can cause this sort of disruption to a caller if NULL is passed, I
guess a change in glibc to add an assert(base != NULL) or similar abort is also
in order given that the caller code becomes buggy otherwise. Do you agree? This
would catch remaining cases before any inferred decisions are executed after
the qsort().


[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-20 Thread pinskia at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #15 from Andrew Pinski  ---
(In reply to Mukund Sivaraman from comment #14)
> (In reply to Jakub Jelinek from comment #10)
> > But the compiler doesn't know there that x is NULL.  The compiler sees a
> 
> See comment #3. It generates 2 codepaths, one where (nalloc == 0) and
> another where (nalloc != 0). For the former, it deletes the if statement and
> isc_mem_put() call at the free_rdatas label completely:
> 
>  free_rdatas:
> if (x != NULL)
> isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata));
>   return (result);
> }
> 
> and instead reduces free_rdata's definition to:
> 
>  free_rdatas:
>   return (result);
> }
> 
> How does the compiler do that if it has not inferred that x is NULL there?
> 
> OTOH, you're the compiler developers, so if you say it doesn't know that x
> is NULL, then that is that. :) Maybe the part of compiler code that does
> this doesn't know it.
> 
> Note that despite all this discussion of correctness, this optimization is
> counter intuitive and will bite developers. There should at least be
> warnings where they could be generated.
> 
> The point about correctness with C standards is taken and agreed.
> 
> See what is happening from a programmer's point of view: an explicit NULL
> check is deleted. There are no warnings about qsort() used with NULL
> arguments where it seems the compiler could warn (see above). Also consider
> the use of notnull as an API annotation change by 3rd party libraries, which
> can make caller code buggy without any way to notice it.
> 
> At the very least, if it is possible to detect that the pointer is NULL by
> static analysis and it is being passed to a function that has the notnull
> attribute, please warn mentioning inferences being made.
The warning did not make it into gcc 4.9 due to the patches to do the warning
were not ready. Gcc 4.10 should warn about it. If it does not then that is a
bug.

[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-20 Thread muks at banu dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #14 from Mukund Sivaraman  ---
(In reply to Jakub Jelinek from comment #10)
> But the compiler doesn't know there that x is NULL.  The compiler sees a

See comment #3. It generates 2 codepaths, one where (nalloc == 0) and another
where (nalloc != 0). For the former, it deletes the if statement and
isc_mem_put() call at the free_rdatas label completely:

 free_rdatas:
if (x != NULL)
isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata));
return (result);
}

and instead reduces free_rdata's definition to:

 free_rdatas:
return (result);
}

How does the compiler do that if it has not inferred that x is NULL there?

OTOH, you're the compiler developers, so if you say it doesn't know that x is
NULL, then that is that. :) Maybe the part of compiler code that does this
doesn't know it.

Note that despite all this discussion of correctness, this optimization is
counter intuitive and will bite developers. There should at least be warnings
where they could be generated.

The point about correctness with C standards is taken and agreed.

See what is happening from a programmer's point of view: an explicit NULL check
is deleted. There are no warnings about qsort() used with NULL arguments where
it seems the compiler could warn (see above). Also consider the use of notnull
as an API annotation change by 3rd party libraries, which can make caller code
buggy without any way to notice it.

At the very least, if it is possible to detect that the pointer is NULL by
static analysis and it is being passed to a function that has the notnull
attribute, please warn mentioning inferences being made.


[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-20 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #13 from Jakub Jelinek  ---
(In reply to Andrew Pinski from comment #11)
> It is not incorrect as the C standard says this about qsort:
> nmemb can have the value zero on a call to that function; the comparison
> function is not called, a search finds no matching element, and sorting
> performs no rearrangement. Pointer arguments on such a call shall still have
> valid values, as described in 7.1.4.
> 
> POSIX 2008 defers to the C standard now so this is neither a glibc or a GCC
> bug in the end.

I've missed the "Pointer arguments on such a call shall still have
valid values, as described in 7.1.4." sentence in C99 7.20.5 (was looking for
that in 7.20.5.2), with that it is exactly the same thing in this regard as
memcpy etc.

[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-20 Thread pinskia at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #12 from Andrew Pinski  ---
(In reply to Andrew Pinski from comment #11) 
> It is not incorrect as the C standard says this about qsort:
> nmemb can have the value zero on a call to that function; the comparison
> function is not called, a search finds no matching element, and sorting
> performs no rearrangement. Pointer arguments on such a call shall still have
> valid values, as described in 7.1.4.

7.1.4 says this:
Each of the following statements applies unless explicitly stated otherwise in
the detailed
descriptions that follow: If an argument to a function has an invalid value
(such as a value
outside the domain of the function, or a pointer outside the address space of
the program,
or a null pointer, or a pointer to non-modifiable storage when the corresponding
parameter is not const-qualified) or a type (after promotion) not expected by a
function
with variable number of arguments, the behavior is undefined.

So there is not need to say it was detected to be non-null as the null pointer
case is mentioned in 7.1.4.

[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-20 Thread pinskia at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #11 from Andrew Pinski  ---
(In reply to Jakub Jelinek from comment #10)
> If you believe the nonnull attribute on qsort is incorrect, then you should
> report that as glibc bug, not gcc bug, the prototype is provided by glibc.
> The more aggressive GCC optimization is documented e.g. in
> https://gcc.gnu.org/gcc-4.9/porting_to.html
> plus we hope to add -fsanitize=undefined instrumentation for this in the
> upcoming GCC version, so you find it out more easily.

It is not incorrect as the C standard says this about qsort:
nmemb can have the value zero on a call to that function; the comparison
function is not called, a search finds no matching element, and sorting performs
no rearrangement. Pointer arguments on such a call shall still have valid
values, as described in 7.1.4.

POSIX 2008 defers to the C standard now so this is neither a glibc or a GCC bug
in the end.

[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-20 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

Jakub Jelinek  changed:

   What|Removed |Added

 Status|WAITING |RESOLVED
 Resolution|--- |INVALID

--- Comment #10 from Jakub Jelinek  ---
If you believe the nonnull attribute on qsort is incorrect, then you should
report that as glibc bug, not gcc bug, the prototype is provided by glibc.
The more aggressive GCC optimization is documented e.g. in
https://gcc.gnu.org/gcc-4.9/porting_to.html
plus we hope to add -fsanitize=undefined instrumentation for this in the
upcoming GCC version, so you find it out more easily.

> When the compiler knows at that point that base (=x) is NULL as an
> argument to qsort(), why isn't it warning when the attribute expects it
> to be non-NULL, esp. as it is using this inferred decision to optimize
> code down below?

But the compiler doesn't know there that x is NULL.  The compiler sees a call
to a function which must not be called with NULL, and from that derives the
value range of x to be anything but NULL.  Instead of qsort consider here some
less controversial function, e.g. memcpy, where the standard is very clear that
memcpy (NULL, "", 0); or memcpy ("", NULL, 0); is invalid despite the length 0.


[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-20 Thread muks at banu dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #9 from Mukund Sivaraman  ---
Hi Jakub, Markus

We discussed this during our daily standup call today, and there are two
points we'd like to make:

1. The qsort() defintion in C99 doesn't explicitly state that base must
not be NULL, though it seems you are deducing that from "the initial
element of which is pointed to by base."

The POSIX definition of qsort() adds this:

 "If the nel argument has the value zero, the comparison function
  pointed to by compar shall not be called and no rearrangement shall
  take place."

2. From our perpective as users of GCC, this kind of agressive
optimization seems counter-intuitive. We'd like code to compile to
correct object code first before performance.

When the compiler knows at that point that base (=x) is NULL as an
argument to qsort(), why isn't it warning when the attribute expects it
to be non-NULL, esp. as it is using this inferred decision to optimize
code down below?

The compiler knows x is NULL at this point in this codepath regardless
of what qsort()'s attributes say. Why is it using the attribute then?

qsort() also does not assert (at runtime) that base is non-NULL.  There
is no way to detect this for code which used to run correctly before,
but doesn't anymore (without it _hopefully_ crashing somewhere).

Other similar functions such as memcpy(), etc. also have this annotation
in glibc, whereas there is no definition of n=0 case in C99.

This example of qsort() is in libc, but imagine a case where a program
uses a 3rd party system installed utility shared library. If the
library, in a new version, adds a nonnull annotation for a function, but
the library function itself continues to work for NULL input, see what
happens to the program: The library is not affected, but the pointer in
the calling program is affected if the compiler infers that the pointer
is non-NULL due to the attribute. The calling program is now buggy due
to a change in the library. How do we discover it?

It makes sense to just avoid the qsort() in our case and we will update
our code to do so, but please consider the arguments above.


[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-19 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

Jakub Jelinek  changed:

   What|Removed |Added

 CC||jakub at gcc dot gnu.org

--- Comment #8 from Jakub Jelinek  ---
The glibc prototype for qsort is:
extern void qsort (void *__base, size_t __nmemb, size_t __size,
   __compar_fn_t __compar) __nonnull ((1, 4));
therefore when you pass x to it, gcc derives from that that x must not be NULL.
As ISO C99 says that qsort sorts an array of nmemb objects, I'd say the glibc
prototype is correct and therefore BIND is buggy, because NULL is not an
address of any object.


[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-19 Thread trippels at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #7 from Markus Trippelsdorf  ---
-fno-delete-null-pointer-checks fixes the issue and is an easy workaround
for now.


[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-19 Thread trippels at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #6 from Markus Trippelsdorf  ---
(In reply to Markus Trippelsdorf from comment #4)
> Could you please try to reproduce the issue with a more recent snapshot:

No need. I can reproduce the issue and will look deeper tomorrow.


[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-19 Thread trippels at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #5 from Markus Trippelsdorf  ---
(In reply to Markus Trippelsdorf from comment #4)
> Could you please try to reproduce the issue with a more recent snapshot:
>  ftp://gcc.gnu.org/pub/gcc/snapshots/4.10-20140518/ 

Sorry wrong address. This one is correct:
 ftp://gcc.gnu.org/pub/gcc/snapshots/4.9-20140514/


[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-19 Thread trippels at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

Markus Trippelsdorf  changed:

   What|Removed |Added

 Status|UNCONFIRMED |WAITING
   Last reconfirmed||2014-05-19
 CC||trippels at gcc dot gnu.org
 Ever confirmed|0   |1

--- Comment #4 from Markus Trippelsdorf  ---
Could you please try to reproduce the issue with a more recent snapshot:
 ftp://gcc.gnu.org/pub/gcc/snapshots/4.10-20140518/ 

There were several bug fixes for tree-ssa-threadedge.c that went
in after "gcc version 4.9.1 20140507".


[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-19 Thread muks at banu dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #3 from Mukund Sivaraman  ---
The following is _incorrect_ generated x86_64 code for
dns_rdataslab_fromrdataset() as compiled with:

gcc version 4.9.1 20140507 (prerelease) (GCC).

(the current version of GCC on Arch Linux).

NOTE that there are two copies of generated code for this
function. Either the first or second copy of code is called based on
whether (nalloc == 0) implying (nitems == 0) too.

In the (nitems == 0) case, the entire free_rdatas block is deleted by
GCC as x is inferred to be NULL.

In the (nitems != 0) case, the "if (x != NULL)" check is deleted as x is
inferred to NOT be NULL, and isc_mem_put() is always called.

The failed assertion obviously happens when (x == NULL), i.e.,
(nitems == 0). And the fact that the "if (x != NULL)" check was deleted
is an obvious sign that code flow is through that path to cause the
assertion failure.

Because the code is like noodles, I've added STEP# comments in the code
to take you through the (nitems == 0) case. Go from STEP #0 to STEP #13.

The bug happens because the (nitems == 0) case branches into code for
(nitems != 0) where checks have been removed.

; STEP #0
0051fc10 :
  51fc10:   41 57   push   %r15
  51fc12:   41 56   push   %r14
  51fc14:   49 89 f7mov%rsi,%r15
  51fc17:   41 55   push   %r13
  51fc19:   41 54   push   %r12
  51fc1b:   49 89 fcmov%rdi,%r12
  51fc1e:   55  push   %rbp
  51fc1f:   53  push   %rbx
  51fc20:   48 83 ec 38 sub$0x38,%rsp
  51fc24:   48 89 54 24 08  mov%rdx,0x8(%rsp)
  51fc29:   89 4c 24 20 mov%ecx,0x20(%rsp)
  51fc2d:   e8 9e e7 ff ff  callq  51e3d0 
  51fc32:   41 89 c5mov%eax,%r13d

;; STEP #1
;; Is (nitems == 0)? If not, go to 51fc60. It is 0 in our case.

  51fc35:   45 85 edtest   %r13d,%r13d
  51fc38:   75 26   jne51fc60


;; STEP #2
;; if (nitems == 0 && rdataset->type != 0)
;;return (ISC_R_FAILURE);
;;
;; Here, let's take it that (rdataset->type != 0) so that we can
;;   continue execution. Jump to 51fd20 (STEP #3).

  51fc3a:   66 41 83 7c 24 22 00cmpw   $0x0,0x22(%r12)
  51fc41:   ba 19 00 00 00  mov$0x19,%edx
  51fc46:   0f 84 d4 00 00 00   je 51fd20


; out:
;
; control comes back here as part of a "return;" statement's code from
; below.

  51fc4c:   48 83 c4 38 add$0x38,%rsp
  51fc50:   89 d0   mov%edx,%eax
  51fc52:   5b  pop%rbx
  51fc53:   5d  pop%rbp
  51fc54:   41 5c   pop%r12
  51fc56:   41 5d   pop%r13
  51fc58:   41 5e   pop%r14
  51fc5a:   41 5f   pop%r15
  51fc5c:   c3  retq   


  51fc5d:   0f 1f 00nopl   (%rax)

; (nitems != 0) case.

  51fc60:   41 81 fd ff ff 00 00cmp$0x,%r13d
  51fc67:   ba 13 00 00 00  mov$0x13,%edx
  51fc6c:   77 de   ja 51fc4c

  51fc6e:   44 89 e8mov%r13d,%eax
  51fc71:   b9 a1 00 00 00  mov$0xa1,%ecx
  51fc76:   ba 6b e1 63 00  mov$0x63e16b,%edx
  51fc7b:   48 8d 1c 40 lea(%rax,%rax,2),%rbx
  51fc7f:   4c 89 ffmov%r15,%rdi
  51fc82:   48 c1 e3 04 shl$0x4,%rbx
  51fc86:   48 89 demov%rbx,%rsi
  51fc89:   e8 d2 a9 0a 00  callq  5ca660 
  51fc8e:   48 85 c0test   %rax,%rax
  51fc91:   49 89 c6mov%rax,%r14
  51fc94:   0f 84 7d 01 00 00   je 51fe17

  51fc9a:   4c 89 e7mov%r12,%rdi

; /* FIRST COPY OF GENERATED CODE (nalloc > 0) */
;
;   result = dns_rdataset_first(rdataset);

  51fc9d:   e8 0e e8 ff ff  callq  51e4b0 

;   if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
;   goto free_rdatas;

; 0x1d (ISC_R_NOMORE)

  51fca2:   83 f8 1dcmp$0x1d,%eax
  51fca5:   74 08   je 51fcaf


; 0x0 (ISC_R_SUCCESS).  if (result != ISC_R_SUCCESS && result !=
; ISC_R_NOMORE), jmp to 51fd53 (free_rdatas) below.

  51fca7:   85 c0   test   %eax,%eax
  51fca9:   0f 85 a4 00 00 00   jne51fd53


; go below to free_rdatas.

; ignore: for loop

  51fcaf:   31 ed   xor%ebp,%ebp
  51fcb1:   85 c0   test   %eax,%eax
  51fcb3:   74 1f   je 51fcd4

  51fcb5:   e9 82 00 00 00  jmpq   51fd3c

  51fcba:   66 0f 1f 44 00 00   nopw   0x0(%rax,%rax,1)

[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-19 Thread muks at banu dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #2 from Mukund Sivaraman  ---
This is the C function (so you can compare notes from the next comment):

isc_result_t
dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
   isc_region_t *region, unsigned int reservelen)
{
/*
 * Use &removed as a sentinal pointer for duplicate
 * rdata as rdata.data == NULL is valid.
 */
static unsigned char removed;
struct xrdata  *x;
unsigned char  *rawbuf;
#if DNS_RDATASET_FIXED
unsigned char  *offsetbase;
#endif
unsigned intbuflen;
isc_result_tresult;
unsigned intnitems;
unsigned intnalloc;
unsigned inti;
#if DNS_RDATASET_FIXED
unsigned int   *offsettable;
#endif
unsigned intlength;

buflen = reservelen + 2;

nalloc = dns_rdataset_count(rdataset);
nitems = nalloc;
if (nitems == 0 && rdataset->type != 0)
return (ISC_R_FAILURE);

if (nalloc > 0x)
return (ISC_R_NOSPACE);


if (nalloc != 0) {
x = isc_mem_get(mctx, nalloc * sizeof(struct xrdata));
if (x == NULL)
return (ISC_R_NOMEMORY);
} else
x = NULL;

/*
 * Save all of the rdata members into an array.
 */
result = dns_rdataset_first(rdataset);
if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
goto free_rdatas;
for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
INSIST(result == ISC_R_SUCCESS);
dns_rdata_init(&x[i].rdata);
dns_rdataset_current(rdataset, &x[i].rdata);
INSIST(x[i].rdata.data != &removed);
#if DNS_RDATASET_FIXED
x[i].order = i;
#endif
result = dns_rdataset_next(rdataset);
}
if (result != ISC_R_NOMORE)
goto free_rdatas;
if (i != nalloc) {
/*
 * Somehow we iterated over fewer rdatas than
 * dns_rdataset_count() said there were!
 */
result = ISC_R_FAILURE;
goto free_rdatas;
}

/*
 * Put into DNSSEC order.
 */
qsort(x, nalloc, sizeof(struct xrdata), compare_rdata);

/*
 * Remove duplicates and compute the total storage required.
 *
 * If an rdata is not a duplicate, accumulate the storage size
 * required for the rdata.  We do not store the class, type, etc,
 * just the rdata, so our overhead is 2 bytes for the number of
 * records, and 8 for each rdata, (length(2), offset(4) and order(2))
 * and then the rdata itself.
 */
for (i = 1; i < nalloc; i++) {
if (compare_rdata(&x[i-1].rdata, &x[i].rdata) == 0) {
x[i-1].rdata.data = &removed;
#if DNS_RDATASET_FIXED
/*
 * Preserve the least order so A, B, A -> A, B
 * after duplicate removal.
 */
if (x[i-1].order < x[i].order)
x[i].order = x[i-1].order;
#endif
nitems--;
} else {
#if DNS_RDATASET_FIXED
buflen += (8 + x[i-1].rdata.length);
#else
buflen += (2 + x[i-1].rdata.length);
#endif
/*
 * Provide space to store the per RR meta data.
 */
if (rdataset->type == dns_rdatatype_rrsig)
buflen++;
}
}
/*
 * Don't forget the last item!
 */
if (nalloc != 0) {
#if DNS_RDATASET_FIXED
buflen += (8 + x[i-1].rdata.length);
#else
buflen += (2 + x[i-1].rdata.length);
#endif
}

/*
 * Provide space to store the per RR meta data.
 */
if (rdataset->type == dns_rdatatype_rrsig)
buflen++;

/*
 * Ensure that singleton types are actually singletons.
 */
if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
/*
 * We have a singleton type, but there's more than one
 * RR in the rdataset.
 */
result = DNS_R_SINGLETON;
goto free_rdatas;
}

/*
 * Allocate the memory, set up a buffer, start copying in
 * data.
 */
rawbuf = isc_mem_get(mctx, buflen);
if (rawbuf == NULL) {
result = ISC_R_NOMEMORY;
goto free_rdatas;
}

#if DNS_RDATASET_FIXED
/* Allocate temporary offset table. */
offsettable = isc_mem_get(mctx, nalloc * sizeof(unsigned int));
if (offsettable == NULL) {
isc_mem_put(mctx, rawbuf, buflen);
result = ISC_R_NOMEMORY;
goto free_rdatas;
}
memset(offsettable, 0, nalloc * sizeof(unsigned int));
#endif

region->base = rawbuf;
region->length = buflen;

rawbuf += reservelen;
#if DNS_RDATASET_FIXED
offsetbase = rawbuf;
#endif

*rawbuf++ = (nitems & 0xff00) >> 8;
*rawbuf++ = (nitems & 0x00ff);

#if DNS_RDATASET_FIXED
/* Skip load order table.  Filled in later. */
rawbuf += nitems * 4;
#endif

for (i = 0; i < nalloc; i++) {
if (x[i].rdata.data == &removed)
continue;
#if DNS_RDATASET_FIXED
offsettable[x[i].order] = rawbuf - offsetbase;

[Bug c/61236] GCC 4.9 generates incorrect object code

2014-05-19 Thread muks at banu dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236

--- Comment #1 from Mukund Sivaraman  ---
The following is _correct_ generated x8t_64 code for
dns_rdataslab_fromrdataset() as compiled with:

gcc version 4.8.2 20131212 (Red Hat 4.8.2-7) (GCC)

Under free_rdatas label, you can see that there is a 0 check for x
(%r14) as in the C code. It was not deleted by the compiler.

00521450 :

; find dns_rdata_set_first() call below:

  521450:   41 57   push   %r15
  521452:   49 89 f7mov%rsi,%r15
  521455:   41 56   push   %r14
  521457:   41 55   push   %r13
  521459:   41 54   push   %r12
  52145b:   49 89 fcmov%rdi,%r12
  52145e:   55  push   %rbp
  52145f:   53  push   %rbx
  521460:   48 83 ec 38 sub$0x38,%rsp
  521464:   48 89 54 24 10  mov%rdx,0x10(%rsp)
  521469:   89 4c 24 0c mov%ecx,0xc(%rsp)
  52146d:   e8 ce e7 ff ff  callq  51fc40 
  521472:   41 89 c5mov%eax,%r13d
  521475:   45 85 edtest   %r13d,%r13d
  521478:   75 26   jne5214a0

  52147a:   45 31 f6xor%r14d,%r14d
  52147d:   66 41 83 7c 24 22 00cmpw   $0x0,0x22(%r12)
  521484:   b8 19 00 00 00  mov$0x19,%eax
  521489:   74 4c   je 5214d7

  52148b:   48 83 c4 38 add$0x38,%rsp
  52148f:   5b  pop%rbx
  521490:   5d  pop%rbp
  521491:   41 5c   pop%r12
  521493:   41 5d   pop%r13
  521495:   41 5e   pop%r14
  521497:   41 5f   pop%r15
  521499:   c3  retq   
  52149a:   66 0f 1f 44 00 00   nopw   0x0(%rax,%rax,1)
  5214a0:   41 81 fd ff ff 00 00cmp$0x,%r13d
  5214a7:   b8 13 00 00 00  mov$0x13,%eax
  5214ac:   77 dd   ja 52148b

  5214ae:   44 89 e8mov%r13d,%eax
  5214b1:   b9 a1 00 00 00  mov$0xa1,%ecx
  5214b6:   ba eb 20 64 00  mov$0x6420eb,%edx
  5214bb:   48 8d 34 40 lea(%rax,%rax,2),%rsi
  5214bf:   4c 89 ffmov%r15,%rdi
  5214c2:   48 c1 e6 04 shl$0x4,%rsi
  5214c6:   e8 45 c2 0a 00  callq  5cd710 
  5214cb:   48 85 c0test   %rax,%rax
  5214ce:   49 89 c6mov%rax,%r14
  5214d1:   0f 84 a7 00 00 00   je 52157e

  5214d7:   4c 89 e7mov%r12,%rdi

;   result = dns_rdataset_first(rdataset);

  5214da:   e8 41 e8 ff ff  callq  51fd20 

;   if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
;   goto free_rdatas;

; 0x1d (ISC_R_NOMORE)

  5214df:   83 f8 1dcmp$0x1d,%eax
  5214e2:   74 04   je 5214e8


; 0x0 (ISC_R_SUCCESS).  if (result != ISC_R_SUCCESS && result !=
; ISC_R_NOMORE), jmp to 52153f (free_rdatas) below.

;; test instruction does logical AND of operands and sets zero flag if
;; %eax is 0. jne (same as jnz) tests ZF and performs conditional jump
;; if ZF=0.

  5214e4:   85 c0   test   %eax,%eax
  5214e6:   75 57   jne52153f


; go below to free_rdatas.

; ignore: for loop

  5214e8:   31 db   xor%ebx,%ebx
  5214ea:   85 c0   test   %eax,%eax
  5214ec:   75 4c   jne52153a

  5214ee:   45 85 edtest   %r13d,%r13d
  5214f1:   75 0a   jne5214fd

  5214f3:   eb 45   jmp52153a

  5214f5:   0f 1f 00nopl   (%rax)

; ignore: for loop iterate (continue;)

  5214f8:   41 39 ddcmp%ebx,%r13d
  5214fb:   76 3d   jbe52153a

  5214fd:   89 d8   mov%ebx,%eax
  5214ff:   48 8d 2c 40 lea(%rax,%rax,2),%rbp
  521503:   48 c1 e5 04 shl$0x4,%rbp
  521507:   4c 01 f5add%r14,%rbp
  52150a:   48 89 efmov%rbp,%rdi
  52150d:   e8 4e 9e fd ff  callq  4fb360 
  521512:   48 89 eemov%rbp,%rsi
  521515:   4c 89 e7mov%r12,%rdi
  521518:   e8 a3 e8 ff ff  callq  51fdc0 

; Second INSIST() inside for loop. First INSIST() is redundant.
  52151d:   48 81 7d 00 a8 c6 8bcmpq   $0x8bc6a8,0x0(%rbp)
  521524:   00 
  521525:   0f 84 00 02 00 00   je 52172b


  52152b:   4c 89 e7mov%r12,%rdi
  52152e:   83 c3 01add$0x1,%ebx
  521531:   e8 3a e8 ff ff