media: v4l2-tpg: fix some memleaks in tpg_alloc
authorZhipeng Lu <alexious@zju.edu.cn>
Thu, 1 Feb 2024 12:47:53 +0000 (20:47 +0800)
committerHans Verkuil <hverkuil-cisco@xs4all.nl>
Mon, 5 Feb 2024 11:57:45 +0000 (12:57 +0100)
In tpg_alloc, resources should be deallocated in each and every
error-handling paths, since they are allocated in for statements.
Otherwise there would be memleaks because tpg_free is called only when
tpg_alloc return 0.

Fixes: 63881df94d3e ("[media] vivid: add the Test Pattern Generator")
Signed-off-by: Zhipeng Lu <alexious@zju.edu.cn>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
drivers/media/common/v4l2-tpg/v4l2-tpg-core.c

index a366566f22c3b7a1dc634f172d8c5fb89a47f62a..642c48e8c1f5842717c1e25a97335eb52bdb8344 100644 (file)
@@ -113,6 +113,7 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
 {
        unsigned pat;
        unsigned plane;
+       int ret = 0;
 
        tpg->max_line_width = max_w;
        for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
@@ -121,14 +122,18 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
 
                        tpg->lines[pat][plane] =
                                vzalloc(array3_size(max_w, 2, pixelsz));
-                       if (!tpg->lines[pat][plane])
-                               return -ENOMEM;
+                       if (!tpg->lines[pat][plane]) {
+                               ret = -ENOMEM;
+                               goto free_lines;
+                       }
                        if (plane == 0)
                                continue;
                        tpg->downsampled_lines[pat][plane] =
                                vzalloc(array3_size(max_w, 2, pixelsz));
-                       if (!tpg->downsampled_lines[pat][plane])
-                               return -ENOMEM;
+                       if (!tpg->downsampled_lines[pat][plane]) {
+                               ret = -ENOMEM;
+                               goto free_lines;
+                       }
                }
        }
        for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
@@ -136,18 +141,45 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
 
                tpg->contrast_line[plane] =
                        vzalloc(array_size(pixelsz, max_w));
-               if (!tpg->contrast_line[plane])
-                       return -ENOMEM;
+               if (!tpg->contrast_line[plane]) {
+                       ret = -ENOMEM;
+                       goto free_contrast_line;
+               }
                tpg->black_line[plane] =
                        vzalloc(array_size(pixelsz, max_w));
-               if (!tpg->black_line[plane])
-                       return -ENOMEM;
+               if (!tpg->black_line[plane]) {
+                       ret = -ENOMEM;
+                       goto free_contrast_line;
+               }
                tpg->random_line[plane] =
                        vzalloc(array3_size(max_w, 2, pixelsz));
-               if (!tpg->random_line[plane])
-                       return -ENOMEM;
+               if (!tpg->random_line[plane]) {
+                       ret = -ENOMEM;
+                       goto free_contrast_line;
+               }
        }
        return 0;
+
+free_contrast_line:
+       for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+               vfree(tpg->contrast_line[plane]);
+               vfree(tpg->black_line[plane]);
+               vfree(tpg->random_line[plane]);
+               tpg->contrast_line[plane] = NULL;
+               tpg->black_line[plane] = NULL;
+               tpg->random_line[plane] = NULL;
+       }
+free_lines:
+       for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
+               for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+                       vfree(tpg->lines[pat][plane]);
+                       tpg->lines[pat][plane] = NULL;
+                       if (plane == 0)
+                               continue;
+                       vfree(tpg->downsampled_lines[pat][plane]);
+                       tpg->downsampled_lines[pat][plane] = NULL;
+               }
+       return ret;
 }
 EXPORT_SYMBOL_GPL(tpg_alloc);