# 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?

``````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;
}
``````

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;
}

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;
}
``````

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`.