Search code examples
cmemory-managementreallocpebble-sdk

Pebble crashes on `realloc`, but only in a certain function


I'm using a custom vector in a Pebble app. Pebble is crashing on the call to realloc.

main.c

#include <pebble.h>
#include "movement.h"

static PointArray point_array;

int main(void) {;
    point_array_create(&point_array, 1);
    GPoint point1 = (GPoint){.x = 1, .y = 1};
    GPoint point2 = (GPoint){.x = 2, .y = 2};
    GPoint point3 = (GPoint){.x = 3, .y = 3};

    point_array_push(&point_array, point1);
    point_array_push(&point_array, point2);
    point_array_push(&point_array, point3);
    APP_LOG(APP_LOG_LEVEL_DEBUG, "Done\n");
}

movement.c

#include "movement.h"
#include "pebble.h"


static void point_array_resize(PointArray *point_array){
  point_array->capacity *= 2;
  size_t new_size = point_array->capacity * sizeof(GPoint) + sizeof(GPoint);
  point_array->points = (GPoint*)realloc(point_array->points, new_size);
}


void point_array_create(PointArray *arr, int capacity) {
    arr->points = (GPoint*)malloc(capacity * sizeof(GPoint));
    arr->length = 0;
    arr->capacity = capacity;
}

void point_array_push(PointArray *point_array, GPoint point) {

  APP_LOG(APP_LOG_LEVEL_DEBUG, "pushing");

  if (point_array->length > point_array->capacity) {
    APP_LOG(APP_LOG_LEVEL_DEBUG, "resizing");
    point_array_resize(point_array);
    APP_LOG(APP_LOG_LEVEL_DEBUG, "successful resize");
  }
  point_array->points[point_array->length] = point;
  point_array->length++;
  APP_LOG(APP_LOG_LEVEL_DEBUG, "+ length");
}

movement.h

#include <pebble.h>
#include <stdlib.h>
#include <math.h>

typedef struct {
  GPoint *points;
  int length;
  int capacity;
} PointArray;

void point_array_create(PointArray *arr, int capacity);

void point_array_push(PointArray *point_array, GPoint point);

void point_array_destroy(PointArray *point_array, GPoint point);

GPoint move(GPoint point, float distance, float degrees);

The logs show that the app is crashing at the call to realloc:

[DEBUG] movement.c:20: pushing
[DEBUG] movement.c:29: + length
[DEBUG] movement.c:20: pushing
[DEBUG] movement.c:29: + length
[DEBUG] movement.c:20: pushing
[DEBUG] movement.c:23: resizing

Here's what I tried:

  • The code runs fine on both GCC and Clang (!).
  • I verified that point_array and point_array->points are not null and
  • new_size is larger than the existing size of point_array->points.
  • I looked at this issue, which doesn't seem to apply.
  • I tried calling realloc at the bottom of point_array_create, and it works fine. It just doesn't work in point_array_resize.

Solution

  • In point_array_push, you test if you need to resize your points at the top, but the test is wrong. You only resize if the length has exceeded capacity, which means you have already overrun your array.

    Instead, check to see if the length has reached capacity.

      if (point_array->length == point_array->capacity) {
        APP_LOG(APP_LOG_LEVEL_DEBUG, "resizing");
        point_array_resize(point_array);
        APP_LOG(APP_LOG_LEVEL_DEBUG, "successful resize");
      }