Comment 1 for bug 1395019

Revision history for this message
In , Cj-gcc (cj-gcc) wrote :

So, we have the following code:

void *lst_realloc(void *, int);

typedef struct smartlist_t {
 void **list;
 int num_used;
 int capacity;
} smartlist_t;

#define MAX_CAPACITY 32

void smartlist_ensure_capacity(smartlist_t *sl, int size) {
 if (size > sl->capacity) {
  int higher = sl->capacity;
  if (size > (int)MAX_CAPACITY/2) {
   higher = MAX_CAPACITY;
  }
  else {
   while (size > higher) {
    higher *= 2;
   }
  }
  sl->capacity = higher;
  sl->list = lst_realloc(sl->list, sl->capacity);
 }
}

Compiling that:
$ x86_64-pc-linux-gnu-gcc-4.8.2 -Os -S -o test.s test.c

Gives:

 pushq %rbx
 cmpl 12(%rdi), %esi
 movq %rdi, %rbx
 jle .L1
 cmpl $16, %esi
 jg .L3
.L4:
 jmp .L4 <----- unexpected infinite loop if size <= capacity/2
.L3:
 movl $32, 12(%rdi)
 movq (%rdi), %rdi
 movl $32, %esi
 call lst_realloc
 movq %rax, (%rbx)
.L1:
 popq %rbx
 ret

Originally from the smartlist_ensure_capacity() function from TOR:
https://gitweb.torproject.org/tor.git/blob/e65b54ec75e3c9e9ada33c8f3ee868d1bea167f5:/src/common/container.c#l61
TOR bug: https://trac.torproject.org/projects/tor/ticket/10259

Reduced by o11c (https://gist.github.com/o11c/7729355) and got help from pinskia.