Bug Summary

File:_imagingmorph.c
Warning:line 231, column 38
PyObject ownership leak with reference count of 1

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name _imagingmorph.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -analyzer-output=html -analyzer-checker=python -analyzer-disable-checker=deadcode -analyzer-config prune-paths=true,suppress-c++-stdlib=true,suppress-null-return-paths=false,crosscheck-with-z3=true,model-path=/opt/pyrefcon/lib/pyrefcon/models/models -analyzer-config experimental-enable-naive-ctu-analysis=true,ctu-dir=/tmp/pyrefcon/Pillow/csa-scan,ctu-index-name=/tmp/pyrefcon/Pillow/csa-scan/externalDefMap.txt,ctu-invocation-list=/tmp/pyrefcon/Pillow/csa-scan/invocations.yaml,display-ctu-progress=false -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debug-info-kind=limited -dwarf-version=4 -debugger-tuning=gdb -fcoverage-compilation-dir=/tmp/pyrefcon/Pillow -resource-dir /opt/pyrefcon/lib/clang/13.0.0 -isystem /opt/pyrefcon/lib/pyrefcon/models/python3.8 -D NDEBUG -D _FORTIFY_SOURCE=2 -I /usr/include/freetype2 -I /usr/include/openjpeg-2.3 -I /tmp/pyrefcon/Pillow -I /usr/include/x86_64-linux-gnu -I /usr/include/fribidi -I /usr/include -internal-isystem /opt/pyrefcon/lib/clang/13.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-result -Wsign-compare -Wall -Wformat -Werror=format-security -Wformat -Werror=format-security -Wdate-time -fdebug-compilation-dir=/tmp/pyrefcon/Pillow -ferror-limit 19 -fwrapv -pthread -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/pyrefcon/Pillow/csa-scan/reports -x c src/_imagingmorph.c

src/_imagingmorph.c

1/*
2 * The Python Imaging Library
3 *
4 * A binary morphology add-on for the Python Imaging Library
5 *
6 * History:
7 * 2014-06-04 Initial version.
8 *
9 * Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com>
10 *
11 * See the README file for information on usage and redistribution.
12 */
13
14#include "Python.h"
15#include "libImaging/Imaging.h"
16
17#define LUT_SIZE(1 << 9) (1 << 9)
18
19/* Apply a morphologic LUT to a binary image. Outputs a
20 a new binary image.
21
22 Expected parameters:
23
24 1. a LUT - a 512 byte size lookup table.
25 2. an input Imaging image id.
26 3. an output Imaging image id
27
28 Returns number of changed pixels.
29*/
30static PyObject *
31apply(PyObject *self, PyObject *args) {
32 const char *lut;
33 PyObject *py_lut;
34 Py_ssize_t lut_len, i0, i1;
35 Imaging imgin, imgout;
36 int width, height;
37 int row_idx, col_idx;
38 UINT8unsigned char **inrows, **outrows;
39 int num_changed_pixels = 0;
40
41 if (!PyArg_ParseTuple(args, "Onn", &py_lut, &i0, &i1)) {
42 PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
43 return NULL((void*)0);
44 }
45
46 if (!PyBytes_Check(py_lut)((((((PyObject*)(py_lut))->ob_type))->tp_flags & ((
1UL << 27))) != 0)
) {
47 PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object");
48 return NULL((void*)0);
49 }
50
51 lut_len = PyBytes_Size(py_lut);
52
53 if (lut_len < LUT_SIZE(1 << 9)) {
54 PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size");
55 return NULL((void*)0);
56 }
57
58 lut = PyBytes_AsString(py_lut);
59
60 imgin = (Imaging)i0;
61 imgout = (Imaging)i1;
62 width = imgin->xsize;
63 height = imgin->ysize;
64
65 if (imgin->type != IMAGING_TYPE_UINT80 || imgin->bands != 1) {
66 PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
67 return NULL((void*)0);
68 }
69 if (imgout->type != IMAGING_TYPE_UINT80 || imgout->bands != 1) {
70 PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
71 return NULL((void*)0);
72 }
73
74 inrows = imgin->image8;
75 outrows = imgout->image8;
76
77 for (row_idx = 0; row_idx < height; row_idx++) {
78 UINT8unsigned char *outrow = outrows[row_idx];
79 UINT8unsigned char *inrow = inrows[row_idx];
80 UINT8unsigned char *prow, *nrow; /* Previous and next row */
81
82 /* zero boundary conditions. TBD support other modes */
83 outrow[0] = outrow[width - 1] = 0;
84 if (row_idx == 0 || row_idx == height - 1) {
85 for (col_idx = 0; col_idx < width; col_idx++) {
86 outrow[col_idx] = 0;
87 }
88 continue;
89 }
90
91 prow = inrows[row_idx - 1];
92 nrow = inrows[row_idx + 1];
93
94 for (col_idx = 1; col_idx < width - 1; col_idx++) {
95 int cim = col_idx - 1;
96 int cip = col_idx + 1;
97 unsigned char b0 = prow[cim] & 1;
98 unsigned char b1 = prow[col_idx] & 1;
99 unsigned char b2 = prow[cip] & 1;
100
101 unsigned char b3 = inrow[cim] & 1;
102 unsigned char b4 = inrow[col_idx] & 1;
103 unsigned char b5 = inrow[cip] & 1;
104
105 unsigned char b6 = nrow[cim] & 1;
106 unsigned char b7 = nrow[col_idx] & 1;
107 unsigned char b8 = nrow[cip] & 1;
108
109 int lut_idx =
110 (b0 | (b1 << 1) | (b2 << 2) | (b3 << 3) | (b4 << 4) | (b5 << 5) |
111 (b6 << 6) | (b7 << 7) | (b8 << 8));
112 outrow[col_idx] = 255 * (lut[lut_idx] & 1);
113 num_changed_pixels += ((b4 & 1) != (outrow[col_idx] & 1));
114 }
115 }
116 return Py_BuildValue("i", num_changed_pixels);
117}
118
119/* Match a morphologic LUT to a binary image and return a list
120 of the coordinates of all matching pixels.
121
122 Expected parameters:
123
124 1. a LUT - a 512 byte size lookup table.
125 2. an input Imaging image id.
126
127 Returns list of matching pixels.
128*/
129static PyObject *
130match(PyObject *self, PyObject *args) {
131 const char *lut;
132 PyObject *py_lut;
133 Py_ssize_t lut_len, i0;
134 Imaging imgin;
135 int width, height;
136 int row_idx, col_idx;
137 UINT8unsigned char **inrows;
138 PyObject *ret = PyList_New(0);
139
140 if (!PyArg_ParseTuple(args, "On", &py_lut, &i0)) {
141 PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
142 return NULL((void*)0);
143 }
144
145 if (!PyBytes_Check(py_lut)((((((PyObject*)(py_lut))->ob_type))->tp_flags & ((
1UL << 27))) != 0)
) {
146 PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object");
147 return NULL((void*)0);
148 }
149
150 lut_len = PyBytes_Size(py_lut);
151
152 if (lut_len < LUT_SIZE(1 << 9)) {
153 PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size");
154 return NULL((void*)0);
155 }
156
157 lut = PyBytes_AsString(py_lut);
158 imgin = (Imaging)i0;
159
160 if (imgin->type != IMAGING_TYPE_UINT80 || imgin->bands != 1) {
161 PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
162 return NULL((void*)0);
163 }
164
165 inrows = imgin->image8;
166 width = imgin->xsize;
167 height = imgin->ysize;
168
169 for (row_idx = 1; row_idx < height - 1; row_idx++) {
170 UINT8unsigned char *inrow = inrows[row_idx];
171 UINT8unsigned char *prow, *nrow;
172
173 prow = inrows[row_idx - 1];
174 nrow = inrows[row_idx + 1];
175
176 for (col_idx = 1; col_idx < width - 1; col_idx++) {
177 int cim = col_idx - 1;
178 int cip = col_idx + 1;
179 unsigned char b0 = prow[cim] & 1;
180 unsigned char b1 = prow[col_idx] & 1;
181 unsigned char b2 = prow[cip] & 1;
182
183 unsigned char b3 = inrow[cim] & 1;
184 unsigned char b4 = inrow[col_idx] & 1;
185 unsigned char b5 = inrow[cip] & 1;
186
187 unsigned char b6 = nrow[cim] & 1;
188 unsigned char b7 = nrow[col_idx] & 1;
189 unsigned char b8 = nrow[cip] & 1;
190
191 int lut_idx =
192 (b0 | (b1 << 1) | (b2 << 2) | (b3 << 3) | (b4 << 4) | (b5 << 5) |
193 (b6 << 6) | (b7 << 7) | (b8 << 8));
194 if (lut[lut_idx]) {
195 PyObject *coordObj = Py_BuildValue("(nn)", col_idx, row_idx);
196 PyList_Append(ret, coordObj);
197 }
198 }
199 }
200
201 return ret;
202}
203
204/* Return a list of the coordinates of all turned on pixels in an image.
205 May be used to extract features after a sequence of MorphOps were applied.
206 This is faster than match as only 1x1 lookup is made.
207*/
208static PyObject *
209get_on_pixels(PyObject *self, PyObject *args) {
210 Py_ssize_t i0;
211 Imaging img;
212 UINT8unsigned char **rows;
213 int row_idx, col_idx;
214 int width, height;
215 PyObject *ret = PyList_New(0);
216
217 if (!PyArg_ParseTuple(args, "n", &i0)) {
1
Assuming the condition is false
2
Taking false branch
218 PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
219
220 return NULL((void*)0);
221 }
222 img = (Imaging)i0;
223 rows = img->image8;
224 width = img->xsize;
225 height = img->ysize;
226
227 for (row_idx = 0; row_idx < height; row_idx++) {
3
Assuming 'row_idx' is < 'height'
4
Loop condition is true. Entering loop body
228 UINT8unsigned char *row = rows[row_idx];
229 for (col_idx = 0; col_idx < width; col_idx++) {
5
Assuming 'col_idx' is < 'width'
6
Loop condition is true. Entering loop body
230 if (row[col_idx]) {
7
Assuming the condition is true
8
Taking true branch
231 PyObject *coordObj = Py_BuildValue("(nn)", col_idx, row_idx);
9
Calling 'Py_BuildValue'
11
Returning from 'Py_BuildValue'
12
PyObject ownership leak with reference count of 1
232 PyList_Append(ret, coordObj);
233 }
234 }
235 }
236 return ret;
237}
238
239static int
240setup_module(PyObject *m) {
241 PyObject *d = PyModule_GetDict(m);
242
243 PyDict_SetItemString(d, "__version", PyUnicode_FromString("0.1"));
244
245 return 0;
246}
247
248static PyMethodDef functions[] = {
249 /* Functions */
250 {"apply", (PyCFunction)apply, METH_VARARGS0x0001, NULL((void*)0)},
251 {"get_on_pixels", (PyCFunction)get_on_pixels, METH_VARARGS0x0001, NULL((void*)0)},
252 {"match", (PyCFunction)match, METH_VARARGS0x0001, NULL((void*)0)},
253 {NULL((void*)0), NULL((void*)0), 0, NULL((void*)0)}};
254
255PyMODINIT_FUNCPyObject*
256PyInit__imagingmorph(void) {
257 PyObject *m;
258
259 static PyModuleDef module_def = {
260 PyModuleDef_HEAD_INIT{ { 1, ((void*)0) }, ((void*)0), 0, ((void*)0), },
261 "_imagingmorph", /* m_name */
262 "A module for doing image morphology", /* m_doc */
263 -1, /* m_size */
264 functions, /* m_methods */
265 };
266
267 m = PyModule_Create(&module_def)PyModule_Create2(&module_def, 1013);
268
269 if (setup_module(m) < 0) {
270 return NULL((void*)0);
271 }
272
273 return m;
274}

/opt/pyrefcon/lib/pyrefcon/models/models/Py_BuildValue.model

1#ifndef Py_BuildValue
2struct _object;
3typedef struct _object PyObject;
4PyObject* clang_analyzer_PyObject_New_Reference();
5PyObject* Py_BuildValue(const char *format, ...) {
6 return clang_analyzer_PyObject_New_Reference();
10
Setting reference count to 1
7}
8#else
9#warning "API Py_BuildValue is defined as a macro."
10#endif