[Bug c/77966] Corrupt function with -fsanitize-coverage=trace-pc

2016-10-13 Thread vda.linux at googlemail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77966

--- Comment #2 from Denis Vlasenko  ---
Without -fsanitize-coverage=trace-pc, the second, redundant check
"snic->wq_count<=1?" is not generated. This eliminates the hanging "impossible"
code path:

:
   0:   8b 07   mov(%rdi),%eax
   2:   85 c0   test   %eax,%eax
   4:   74 09   je f
   6:   48 8b 7f 08 mov0x8(%rdi),%rdi
   a:   e9 00 00 00 00  jmpq   ioread32
   f:   c3  retq

[Bug c/77966] Corrupt function with -fsanitize-coverage=trace-pc

2016-10-13 Thread vda.linux at googlemail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77966

Denis Vlasenko  changed:

   What|Removed |Added

 CC||vda.linux at googlemail dot com

--- Comment #1 from Denis Vlasenko  ---
Simplified a bit:
- spinlock_t is not essential
- mempool_t is not essential
- snic_log_q_error_err_status variable is not necessary
- __attribute__ ((__aligned__)) can be dropped too
- struct vnic_wq can be folded
OTOH:
- struct vnic_wq_ctrl wrapping of int variable is necessary
- wq_lock[1] unused member is necessary (makes gcc "know for sure" that wq[1]
is 1-element array)
- each of -O2 -fno-reorder-blocks -fsanitize-coverage=trace-pc are necessary


extern unsigned int ioread32(void *);
struct vnic_wq_ctrl {
unsigned int error_status;
};
struct snic {
unsigned int wq_count;
struct vnic_wq_ctrl *wq[1];
int wq_lock[1];
};
void snic_log_q_error(struct snic *snic)
{
unsigned int i;
for (i = 0; i < snic->wq_count; i++)
ioread32(>wq[i]->error_status);
}


:
   0:   53  push   %rbx
   1:   48 89 fbmov%rdi,%rbx
   4:   e8 00 00 00 00  callq  __sanitizer_cov_trace_pc
   9:   8b 03   mov(%rbx),%eax
   b:   85 c0   test   %eax,%eax  # snic->wq_count==0?
   d:   75 09   jne18
   f:   5b  pop%rbx # yes, 0
  10:   e9 00 00 00 00  jmpq   __sanitizer_cov_trace_pc #tail call
  15:   0f 1f 00nopl   (%rax)

  18:   e8 00 00 00 00  callq  __sanitizer_cov_trace_pc
  1d:   48 8b 7b 08 mov0x8(%rbx),%rdi
  21:   e8 00 00 00 00  callq  ioread32
  26:   83 3b 01cmpl   $0x1,(%rbx) # snic->wq_count<=1?
  29:   76 e4   jbef
  2b:   e8 00 00 00 00  callq  __sanitizer_cov_trace_pc


Looks like gcc thinks that the loop can execute only zero or one time
(or else we run off wq[1]). So when it iterated once:

  21:   e8 00 00 00 00  callq  ioread32

it checks that snic->wq_count <= 1

  26:   83 3b 01cmpl   $0x1,(%rbx)
  29:   76 e4   jbef

and if not, we are in "impossible" land and just stop codegen.
-fsanitize-coverage=trace-pc generator twitches one last time:

  2b:   e8 00 00 00 00  callq  __sanitizer_cov_trace_pc