Search code examples
cdivide-by-zero

divide by zero in simclist library


In the simclist link list library, I've run into a problem where division by zero occurs in the function list_findpos(). Normally I'm be hesitant to modify a widely used 3rd party library, and there must be good reason why it does what it does (I haven't ruled out the library is used incorrectly). The function is defined as:

/* set tmp to point to element at index posstart in l */
static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart) {
    struct list_entry_s *ptr;
    float x;
    int i;

    /* accept 1 slot overflow for fetching head and tail sentinels */
    if (posstart < -1 || posstart > (int)l->numels) return NULL;

    x = (float)(posstart+1) / l->numels;
    if (x <= 0.25) {
        /* first quarter: get to posstart from head */
        for (i = -1, ptr = l->head_sentinel; i < posstart; ptr = ptr->next, i++);
    } else if (x < 0.5) {
        /* second quarter: get to posstart from mid */
        for (i = (l->numels-1)/2, ptr = l->mid; i > posstart; ptr = ptr->prev, i--);
    } else if (x <= 0.75) {
        /* third quarter: get to posstart from mid */
        for (i = (l->numels-1)/2, ptr = l->mid; i < posstart; ptr = ptr->next, i++);
    } else {
        /* fourth quarter: get to posstart from tail */
    for (i = l->numels, ptr = l->tail_sentinel; i > posstart; ptr = ptr->prev, i--);
    }

    return ptr;
}

If l->numels is 0, then the expression on line 9 is a problem. The code otherwise runs ok (without leaks or segfaults), but intel inspector is saying a division by zero occurs on this line. The proposed change is:

/* set tmp to point to element at index posstart in l */
static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart) {
    struct list_entry_s *ptr;
    float x;
    int i;

    /* accept 1 slot overflow for fetching head and tail sentinels */
    if (posstart < -1 || posstart > (int)l->numels) return NULL;

    if (l->numels == 0){ //avoid division-by-zero on first element
       ptr = l->head_sentinel;
    }
    else{
       x = (float)(posstart + 1) / l->numels;
       if (x <= 0.25) {
          /* first quarter: get to posstart from head */
          for (i = -1, ptr = l->head_sentinel; i < posstart; ptr = ptr->next, i++);
       }
       else if (x < 0.5) {
          /* second quarter: get to posstart from mid */
          for (i = (l->numels - 1) / 2, ptr = l->mid; i > posstart; ptr = ptr->prev, i--);
       }
       else if (x <= 0.75) {
          /* third quarter: get to posstart from mid */
          for (i = (l->numels - 1) / 2, ptr = l->mid; i < posstart; ptr = ptr->next, i++);
       }
       else {
          /* fourth quarter: get to posstart from tail */
          for (i = l->numels, ptr = l->tail_sentinel; i > posstart; ptr = ptr->prev, i--);
       }
    }
    return ptr;
}

Wondering if anyone can comment on this that has experience using simclist?


EDIT

list_findpos is not an API function; rather, it's an internal function. The sequence of calls leading to the issues are:

/* ... */
list_init(...) 
list_attributes_copy(...)
list_append(...) /* <---- list_findpos() is called here, divide by zero */

Solution

  • This function is not part of the library's API; it's totally internal. What the author/maintainer of the library will need to know in order to fix it is what sequence of API calls you made that caused it to fail.