Raphael Rakhimov
Raphael Rakhimov

Reputation: 3

Segmentation fault in malloc()

I need to create a function which returns an array of ints. This int array should contain all values between min and max (both included).

The question is why, when min = -2147483468 and max = 2147483647 (and len becomes 4294967296) I get "Segmentation fault"?

My code:

   #include <stdlib.h>
   #include <stdio.h>

   int *ft_range(int min, int max)
   {
       int         *range;
       long int    len;
       long int    i;

       range = NULL;
       if (min >= max)
           return (NULL);
       len = max - min + 1;
       if(!(range = (int *)malloc(sizeof(int) * len)))
           return (NULL);
       i = 0;
       while (min < max)
       {
           range[i] = min;
           min++;
           i++;
       }
       range[i] = max;
       return (range);
   }


   int main(void)
   {
       int      max;
       int      min;
       long int     len;
       int      *range;
       long int     i;

       max = 2147483647;
       min = -2147483648;
       if (max != min)
           len = max - min + 1;
       else
           len = 0;
       i = 0;
       range = ft_range(min, max);
       while (i < len)
       {
           printf("%d", range[i]);
           i++;
       }
       free(range);
       return (0);
   }

But, if I enter min = -2147483468 and max = 2147483646 with len = 4294967295 it works.

Upvotes: 0

Views: 282

Answers (3)

Raphael Rakhimov
Raphael Rakhimov

Reputation: 3

I solved the problem by using len and i as long long int, added long long int this way:

len = (long long int)max - min + 1;

Also I forgot to check if malloc returns NULL in main() function.

This is the correct version:

    #include <stdlib.h>
    #include <stdio.h>

    int *ft_range(int min, int max)
    {
        int             *range;
        long long int   len;
        long long int   i;

        range = NULL;
        if (min >= max)
            return (NULL);
        len = (long long int)max - min + 1;
        if(!(range = (int *)malloc(sizeof(int) * len)))
            return (NULL);
        i = 0;
        while (min < max)
        {
            range[i] = min;
            min++;
            i++;
        }
        range[i] = max;
        return (range);
    }

    int main(void)
    {
        int             *range;
        int             max;
        int             min;
        long long int   len;
        long long int   i;

        max = 2147483647;
        min = -2147483648;
        len = 0;
        if (max != min)
            len = (long long int)max - min + 1;
        i = 0;
        if(!ft_range(min, max))
            return (0);
        range = ft_range(min, max);
        while (i < len)
        {
            printf("%d", range[i]);
            i++;
        }
            free(range);
            return (0);
    }

Upvotes: 0

Jonathon S.
Jonathon S.

Reputation: 1980

min and max are type int, which is only guaranteed to be 16 bits signed (-32768, 32767), although the compiler may choose to use more bits to store the values. Therefore, if you were to expect values ranging (-2147483468, 2147483647), these should be of type long int. The program may or may not be be truncating some of the bits when you supply (-2147483468, 2147483647) or (-2147483468, 2147483646) as inputs. This would also apply to the type for range.

Secondly, variable len is long int which is only guaranteed to be 32 bits signed (-2147483468, 2147483647). Since you want to be able to store value 4294967296, this will need to be either long long int or long long unsigned int. Even long unsigned int will only have a range of (0, 4294967295). This would also apply to i.

Additionally, the statement len = max - min + 1;, will need to include a type cast to long long int to avoid overflow when performing the arithmetic. You can do it by adding (long long int) this way: len = (long long int)max - min + 1;; or if you want to be more explicit: len = ((long long int)max - (long long int)min) + 1LL;

To summarize:

   #include <stdlib.h>
   #include <stdio.h>

   int *ft_range(long int min, long int max)
   {
       long int         *range;
       long long int    len;
       long long int    i;

       range = NULL;
       if (min >= max)
           return (NULL);
       len = (long long int)max - min + 1;
       if(!(range = (int *)malloc(sizeof(int) * len)))
           return (NULL);
       i = 0;
       while (min < max)
       {
           range[i] = min;
           min++;
           i++;
       }
       range[i] = max;
       return (range);
   }

Side note: Range (-2147483468, 2147483647) is going to require around 16 GB of memory to be allocated, so I hope that you are ready for that.

Upvotes: 1

chux
chux

Reputation: 153468

int overflow with max - min + 1;

  • Use wider math for size calculations.

  • Use size_t for allocation size and indexing

  • Add more error checks.


int *ft_range(int min, int max) {
  // Add required test explicitly
  if (min >= max) {
    return NULL;
  }

  long long size = 1LL + max - min; // Use long long math
  if (size > SIZE_MAX/sizeof(int) || size < 1) {
    return NULL;
  }
  size_t usize = (size_t)size;

  int *range = malloc(sizeof *range * usize);
  if (range == NULL) {
    return NULL;
  }

  size_t i = 0;
  while (min < max) {
    range[i] = min;
    min++;
    i++;
  }
  range[i] = max;
  return range;
}

Upvotes: 1

Related Questions