Computing > Programming

malloc to struct pointer = hard fault. What am I doing wrong?

(1/4) > >>

DavidAlfa:
I'm working on dinamically allocating the screens in the stm32 fw, so I can reduce the ram footprint.
A rough description is: Theres a "widget" struct. It holds some data like position and other things, and also a pointer to the content.
The content is like a "sub-widget", can be a button, editable, display...
So what I'm doing is to first allocate the widget, then allocate the sub-widget depending on the type.
However when accessing the subwidget, it causes hard fault with the combo type.
This worked perfectly fine before, using static allocations. It started to happen after using malloc. sizeof reports the correct sizes. mallinfo also reports the correct size being allocated (+8 bytes per malloc).
It's not running out of  heap or stack, it happens with the very first allocation, it's just with the combo type. I can allocate anything else correctly.


--- Code: ---struct selectable_widget_t {
  widgetStateType state;
  widgetStateType previous_state;
  uint8_t tab;
  int (*processInput)(widget_t*, RE_Rotation_t, RE_State_t *);
  int (*longPressAction)(widget_t*);
};

--- End code ---

--- Code: ---struct comboBox_widget_t {                                           //<-- void *content addresses this
  uint8_t currentScroll;
  const uint8_t* font;
  comboBox_item_t *first;
  comboBox_item_t *currentItem;
  selectable_widget_t selectable;
};

--- End code ---

--- Code: ---struct widget_t
{
  widgetType type;
  widgetRefreshType refresh;
  widgetFrameType frameType;
  uint8_t posX;
  uint8_t posY;
  uint8_t width;
  uint8_t enabled;
  int8_t radius;
  widget_t *next_widget;
  struct screen_t *parent;
  void (*draw)(widget_t*);
  void (*update)(widget_t*);
  void *content;                                           //<-- void *content
};

--- End code ---


Well, it looks a lot but it's not. In widget_t,  use void *content to allow any type of pointer.

comboBox_widget_t includes a selectable_widget_t,  And pointers to item, that are added when configuring it.

The allocating function is pretty simple. Of course the code is stripped down to show only what matters:

--- Code: ---widget_t *newWidget(widgetType type){
  widget_t *w=malloc(sizeof(widget_t));
  if(!w) Error_Handler();
  switch(type){
    case widget_combo:
      w->content = malloc(sizeof(comboBox_widget_t));
      break;
    default:
      Error_Handler();
  }
  if(!w->content) Error_Handler();
  widgetDefaultsInit(w, type);
  return w;
}

--- End code ---

The part that causes the hard fault is in widgetDefaultsInit:

--- Code: ---void widgetDefaultsInit(widget_t *w, widgetType type){
    if(type==widget_combo){   
        comboBox_widget_t *combo = (comboBox_widget_t*)w->content;

        w->frameType = frame_combo;
        w->draw = &comboBoxDraw;
        w->parent->current_widget = w;

        # These cause a hard fault! But doesn't with static allocation (Manually declaring each widget and sub-widget)
        combo->first = NULL;
        combo->currentItem = NULL;
        combo->selectable.processInput = &comboBoxProcessInput;
        combo->font = default_font;
        combo->currentScroll = 0;
    }
}

--- End code ---

evb149:
Error handler better be terminal or this will cause an uninitialized access after default case falls through:
 if(!w->content) Error_Handler();

Is parent initialized before this?
w->parent->current_widget = w;

evb149:
Why don't you pretend to implement something like a constructor
and after you allocate a structure initialize every item to some value even if the
structure isn't initialized coherently to its invariants yet. 
i.e. every pointer is NULL.  every scalar is 0 or whatever.
Or at least bzero / memset it to 0x00 for consistency.

Then for every single line where you access a structure member before you've 'constructed' it in its
entirely valid invariant state ask yourself -- "what does this member hold?  is it valid because of previous initialization / assignment, or is it invalid and now I'm assigning the valid final value?".

evb149:
Oh and be careful if you're debugging this or what not and maybe the debugger is trying to load content through pointer type members which aren't pointing to valid memory as you debug / visualize the structure / functions using it.

Also be careful of optimization if something isn't happening at the line number you think it is.

DavidAlfa:

--- Quote from: evb149 on July 29, 2021, 01:08:12 am ---Error handler better be terminal or this will cause an uninitialized access after default case falls through:
 if(!w->content) Error_Handler();

Is parent initialized before this?
w->parent->current_widget = w;

--- End quote ---
That was it! Not exactly that, but yes, I over-simplified the function and it was missing an important step.
I kept looking at the malloc thing,"there must be something wrong with a pointer or a cast! ", but didn't made sense because it looked correct.
Yes, Error_Handler is terminal. It shows the file/line where the problem happened and dies in a forever loop.
Thanks!

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version