The benefit of zero_mem in lv_mem.c

In the lv_mem.c, there is a variable called zero_mem. What is the benefit of this variable? A comment says, "/Give the address of this variable if 0 byte should be allocated/ " Why did you do this and not return NULL in case 0 byte should be allocated?
Another question about zero_mem:

void lv_draw_mask_polygon_init(lv_draw_mask_polygon_param_t * param, const lv_point_t * points, uint16_t point_cnt)
{
    /*Join adjacent points if they are on the same coordinate*/
    lv_point_t * p = lv_mem_alloc(point_cnt * sizeof(lv_point_t));
    if(p == NULL) return;
    uint16_t i;
    uint16_t pcnt = 0;
    p[0] = points[0];
    for(i = 0; i < point_cnt - 1; i++) {
        if(points[i].x != points[i + 1].x || points[i].y != points[i + 1].y) {
            p[pcnt] = points[i];
            pcnt++;
        }
    }
    /*The first and the last points are also adjacent*/
    if(points[0].x != points[point_cnt - 1].x || points[0].y != points[point_cnt - 1].y) {
        p[pcnt] = points[point_cnt - 1];
        pcnt++;
    }
    param->cfg.points = p;
    param->cfg.point_cnt = pcnt;
    param->dsc.cb = (lv_draw_mask_xcb_t)lv_draw_mask_polygon;
    param->dsc.type = LV_DRAW_MASK_TYPE_POLYGON;
}

In the above code, the lv_draw_mask_polygon_init function creates p by calling lv_mem_alloc; why didn’t you check if p is equal &zero_mem as you checked if it equals NULL? In the current scenario, if the size parameter was zero, we returned &zero_mem. The value of zero_mem will be changed, and this will return a memory integrity error.
Do I have any confusion?

You should not continue calling lv_draw_mask_polygon_init when point_cnt=0 to avoid undefined behavior.

bool my_draw_func(lv_draw_mask_polygon_param_t * param, const lv_point_t * points, uint16_t point_cnt)
{
  if(point_cnt == 0)
  {
    return false;
  }

  lv_draw_mask_polygon_init(param, points, point_cnt);
  xxx

  return true;
}

@FASTSHIFT Thank you for your reply. I put the code of lv_draw_mask_polygon_init as an example of what I mean. But in general, why is there no check after calling the lv_mem_alloc in the whole code of the LVGL library to check if the return pointer equals the &mem_zero as there is a check if it equals NULL? I think this should be handled in the LVGL library, not in the upper module.

zero_mem is a private variable of lv_mem.c, which is not accessible by external code, so you don’t have to worry about the return value problem of lv_mem_alloc(0).

If you add a point_cnt judgment inside lv_draw_mask_polygon_init, it looks like this:

void lv_draw_mask_polygon_init(lv_draw_mask_polygon_param_t * param, const lv_point_t * points, uint16_t point_cnt)
{
    if(point_cnt == 0) {
        return;
    }
    /*Join adjacent points if they are on the same coordinate*/
    lv_point_t * p = lv_mem_alloc(point_cnt * sizeof(lv_point_t));
    if(p == NULL) return;
    uint16_t i;
    uint16_t pcnt = 0;
    p[0] = points[0];
    for(i = 0; i < point_cnt - 1; i++) {
        if(points[i].x != points[i + 1].x || points[i].y != points[i + 1].y) {
            p[pcnt] = points[i];
            pcnt++;
        }
    }
    /*The first and the last points are also adjacent*/
    if(points[0].x != points[point_cnt - 1].x || points[0].y != points[point_cnt - 1].y) {
        p[pcnt] = points[point_cnt - 1];
        pcnt++;
    }
    param->cfg.points = p;
    param->cfg.point_cnt = pcnt;
    param->dsc.cb = (lv_draw_mask_xcb_t)lv_draw_mask_polygon;
    param->dsc.type = LV_DRAW_MASK_TYPE_POLYGON;
}

The user has no way of knowing if the param structure is initialized correctly, and using an uninitialized structure directly may cause the code to run abnormally.
So the simplest, most efficient and bug-free solution is to refer to the implementation of my_draw_func above.

malloc(0) is an undefined behavior. If you want to avoid this influence, you can judge the correctness of size before malloc.
In addition, lv_mem_alloc may be replaced with a user-defined memory allocator, and it is not reasonable to compare the return value of the custom memory allocator to &zero_mem.