Home > database >  Free invalid pointer error in C for Codewars
Free invalid pointer error in C for Codewars

Time:08-14

I am attempting to solve the Codewars problem "Sum Strings as Numbers" in which you are given two strings that are numbers and you need to return a string that is the sum of these numbers. My program works for the first few tests but it breaks down when encountering random tests with strings that are hundreds of digits long. If I use the same exact input on and run the program on my own computer, there are no issues. I get this error from code wars:

Test Crashed
Caught unexpected signal: 6

and this in stderr:

free(): invalid pointer
free(): invalid pointer

this is stdout:

START
Initial variables:
llu_strlen a = 236, llu_strlen(b) = 184
llu_strlen(s1) = 236, llu_strlen(s2) = 236
ret = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
a: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
s1: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
b: 2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
s2: 00000000000000000000000000000000000000000000000000002750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
entering sum loop:
i = 0, digita = 8, digitb = 4, sumstr=12
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
i = 1, digita = 9, digitb = 5, sumstr=15
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052
i = 2, digita = 7, digitb = 6, sumstr=14
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000452
i = 3, digita = 2, digitb = 6, sumstr=09
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009452
i = 4, digita = 6, digitb = 2, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 5, digita = 3, digitb = 7, sumstr=10
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 6, digita = 9, digitb = 9, sumstr=19
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009089452
i = 7, digita = 9, digitb = 8, sumstr=18
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089089452
i = 8, digita = 3, digitb = 4, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000889089452
i = 9, digita = 7, digitb = 0, sumstr=07
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007889089452
i = 10, digita = 0, digitb = 5, sumstr=05

(continues on like that for a while)
000000000000000000000000000121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 210, digita = 7, digitb = 0, sumstr=07
000000000000000000000000007121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 211, digita = 2, digitb = 0, sumstr=02
000000000000000000000000027121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 212, digita = 8, digitb = 0, sumstr=08
000000000000000000000000827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 213, digita = 4, digitb = 0, sumstr=04
000000000000000000000004827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 214, digita = 6, digitb = 0, sumstr=06
000000000000000000000064827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 215, digita = 9, digitb = 0, sumstr=09
000000000000000000000964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 216, digita = 1, digitb = 0, sumstr=01
000000000000000000001964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 217, digita = 2, digitb = 0, sumstr=02
000000000000000000021964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 218, digita = 7, digitb = 0, sumstr=07
000000000000000000721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 219, digita = 5, digitb = 0, sumstr=05
000000000000000005721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 220, digita = 1, digitb = 0, sumstr=01
000000000000000015721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 221, digita = 9, digitb = 0, sumstr=09
000000000000000915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 222, digita = 6, digitb = 0, sumstr=06
000000000000006915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 223, digita = 4, digitb = 0, sumstr=04
000000000000046915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 224, digita = 9, digitb = 0, sumstr=09
000000000000946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 225, digita = 3, digitb = 0, sumstr=03
000000000003946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 226, digita = 4, digitb = 0, sumstr=04
000000000043946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 227, digita = 4, digitb = 0, sumstr=04
000000000443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 228, digita = 4, digitb = 0, sumstr=04
000000004443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 229, digita 

here is the program that I run on code wars which throws an error:

#include <malloc.h>
#include <string.h>

unsigned long long llu_strlen(const char * s)
{
  unsigned long long len = 0;
  
  while (s[len])
    len  ;
  
  return len;
}


char *strsum(const char *a, const char *b)
{
  puts("START");
  static char * ret;
  char sumstr[] = "00";
  char digita, digitb;
  unsigned long long maxlen, i, carry;

  if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
    return NULL;
  
  maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
  
  // create ret full of maxlen 1 0s plus a '\0'. total size is maxlen 2
  ret = (char *) malloc((maxlen 2) * sizeof(char));
  for (i = 0; i < maxlen 1; i  )
    ret[i] = '0';
  ret[maxlen 1] = '\0';
  
  // create copies of a and b of equal size by buffering with 0s
  char s1[maxlen], s2[maxlen];
  for (i = 0; i < maxlen - llu_strlen(a); i  )
    s1[i] = '0';
  strcpy(s1 i, a);
  for (i = 0; i < maxlen - llu_strlen(b); i  )
    s2[i] = '0';
  strcpy(s2 i, b);

  puts("Initial variables:");
  printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
  printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
  printf("ret = %s\n", ret);
  printf("a: %s\n", a);
  printf("s1: %s\n", s1);
  printf("b: %s\n", b);
  printf("s2: %s\n", s2);
  
  // sum loop
  printf("entering sum loop:\n");
  for (i = carry = 0; i < maxlen; i  )
  {
    digita = s1[maxlen-1-i] - 48;
    digitb = s2[maxlen-1-i] - 48;
    sprintf(sumstr, "llu", digita   digitb   carry);
    carry = sumstr[0] - 48;
    ret[maxlen-i] = sumstr[1];
    
    printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
    puts(ret);
  }
  printf("Done with that\n");
  ret[0] = carry   48;
  
  // remove preceeding zeros
  while (*ret == '0' && *(ret 1) != '\0')
    ret  ;
  printf("final ret: %s\nEND\n\n", ret);    
  
  return ret;
}

and here is the program I run on my computer which finds the result successfully:

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

unsigned long long llu_strlen(const char * s)
{
  unsigned long long len = 0;
  
  while (s[len])
    len  ;
  
  return len;
}


char *strsum(const char *a, const char *b)
{
  puts("START");
  static char * ret;
  char sumstr[] = "00";
  char digita, digitb;
  unsigned long long maxlen, i, carry;

  if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
    return NULL;
  
  maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
  
  // create ret full of maxlen 1 0s plus a '\0'. total size is maxlen 2
  ret = (char *) malloc((maxlen 2) * sizeof(char));
  for (i = 0; i < maxlen 1; i  )
    ret[i] = '0';
  ret[maxlen 1] = '\0';
  
  // create copies of a and b of equal size by buffering with 0s
  char s1[maxlen], s2[maxlen];
  for (i = 0; i < maxlen - llu_strlen(a); i  )
    s1[i] = '0';
  strcpy(s1 i, a);
  for (i = 0; i < maxlen - llu_strlen(b); i  )
    s2[i] = '0';
  strcpy(s2 i, b);

  puts("Initial variables:");
  printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
  printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
  printf("ret = %s\n", ret);
  printf("a: %s\n", a);
  printf("s1: %s\n", s1);
  printf("b: %s\n", b);
  printf("s2: %s\n", s2);
  
  // sum loop
  printf("entering sum loop:\n");
  for (i = carry = 0; i < maxlen; i  )
  {
    digita = s1[maxlen-1-i] - 48;
    digitb = s2[maxlen-1-i] - 48;
    sprintf(sumstr, "llu", digita   digitb   carry);
    carry = sumstr[0] - 48;
    ret[maxlen-i] = sumstr[1];
    
    printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
    puts(ret);
  }
  printf("Done with that\n");
  ret[0] = carry   48;
  
  // remove preceeding zeros
  while (*ret == '0' && *(ret 1) != '\0')
    ret  ;
  printf("final ret: %s\nEND\n\n", ret);    
  
  return ret;
}

int main(void)
{
  char * res;
  
  res = strsum("78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798", 
              "2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654");
  
  return 0;
}

The error always occurs while the print statement in the sum for loop is printing. The amount of stuff that print statement manages to print out before being cut off changes every time the program is run. This test has random strings of numbers as input, so the input changes each time. The error usually occurs when i approaches maxlen, but i can sometimes be 30-40 less than maxlen.

CodePudding user response:

In your function you allocate ret in this line:

ret = (char *) malloc((maxlen 2) * sizeof(char));

you then return ret at the end of your function, presumably to be freed by the caller. However within your function you also have these lines:

// remove preceeding zeros
while (*ret == '0' && *(ret 1) != '\0')
  ret  ;

This means that the the ret you are returning no longer has the same pointer value as the one you received from malloc. Then when you call free in the caller the free function doesn't know what the pointer is.

One way to fix this is to find a different way to remove leading zeros, one that doesn't change the value of ret.

CodePudding user response:

These don't have room for the null terminator:

char s1[maxlen], s2[maxlen];

which makes your program write out of bounds and have undefined behavior, so make them:

char s1[maxlen 1], s2[maxlen 1];

And here you change ret, making it impossible for a user to free the malloced memory:

while (*ret == '0' && *(ret 1) != '\0')
    ret  ;

instead, move the part of the string that you want to keep:

char *tmp = ret;
while (*tmp == '0' && tmp[1] != '\0') tmp  ;
memmove(ret, tmp, maxlen-(tmp-ret) 2);

Another detail: You declare ret as static which only makes it unsafe to use the function in a multithreaded program. It does not provide any benefits at all. Just make it:

char *ret;

Another possible improvement would be to not allocate s1 and s2 at all, but to read directly from a and b and to skip leading zeroes before doing the calculation. Example:

#define SWAP(type, x, y) \
    do {                 \
        type tmp = x;    \
        x = y;           \
        y = tmp;         \
    } while (0)

char *strsum(const char *a, const char *b) {
    while(*a == '0' && a[1] != '\0')   a; // skip leading zeroes
    while(*b == '0' && b[1] != '\0')   b; // skip leading zeroes
    size_t lena = strlen(a);
    size_t lenb = strlen(b);

    if (lena == 0 || lenb == 0) return NULL;

    if (lena < lenb) {  // make `a` the longest string
        SWAP(const char *, a, b);
        SWAP(size_t, lena, lenb);
    }

    char *ret = malloc(lena   2);  // may add one digit   null terminator
    ret[lena   1] = '\0';          // null terminate the result

    int carry = 0;
    size_t i = 1;

    // loop while both `b` and `a` have digits:
    for (; i <= lenb;   i) {
        int sum = carry   (a[lena - i] - '0')   (b[lenb - i] - '0');
        ret[lena - i   1] = (sum % 10)   '0';
        carry = sum / 10;
    }

    // loop while only `a` has digits:
    for (; i <= lena;   i) {
        int sum = carry   (a[lena - i] - '0');
        ret[lena - i   1] = (sum % 10)   '0';
        carry = sum / 10;
    }   

    // if no carry, move everything one step to the left:
    if (carry == 0) memmove(ret, ret   1, lena   2 - 1);
    else ret[0] = carry   '0'; // carry goes to the first position

    return ret;
}

Demo

  • Related