Bug Summary

File:.cache/bazel/_bazel_alan/39be661231df2a680c9b74265384c13c/execroot/org_tensorflow/tensorflow/python/util/fast_module_type.cc
Warning:line 192, column 23
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 fast_module_type.cc -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -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/tensorflow/csa-scan,ctu-index-name=/tmp/pyrefcon/tensorflow/csa-scan/externalDefMap.txt,ctu-invocation-list=/tmp/pyrefcon/tensorflow/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=all -relaxed-aliasing -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/pyrefcon/.cache/bazel/_bazel_alan/39be661231df2a680c9b74265384c13c/execroot/org_tensorflow -resource-dir /opt/pyrefcon/lib/clang/13.0.0 -iquote . -iquote bazel-out/k8-opt/bin -iquote external/eigen_archive -iquote bazel-out/k8-opt/bin/external/eigen_archive -iquote external/com_google_absl -iquote bazel-out/k8-opt/bin/external/com_google_absl -iquote external/nsync -iquote bazel-out/k8-opt/bin/external/nsync -iquote external/local_config_python -iquote bazel-out/k8-opt/bin/external/local_config_python -iquote external/pybind11 -iquote bazel-out/k8-opt/bin/external/pybind11 -iquote external/bazel_tools -iquote bazel-out/k8-opt/bin/external/bazel_tools -isystem third_party/eigen3/mkl_include -isystem bazel-out/k8-opt/bin/third_party/eigen3/mkl_include -isystem external/eigen_archive -isystem bazel-out/k8-opt/bin/external/eigen_archive -isystem external/nsync/public -isystem bazel-out/k8-opt/bin/external/nsync/public -isystem /opt/pyrefcon/lib/pyrefcon/models/python3.8 -isystem /opt/pyrefcon/lib/pyrefcon/models/python3.8 -isystem external/pybind11/include -isystem bazel-out/k8-opt/bin/external/pybind11/include -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=1 -D NDEBUG -D EIGEN_MPL2_ONLY -D EIGEN_MAX_ALIGN_BYTES=64 -I bazel-out/k8-opt/bin/external/pybind11/_virtual_includes/pybind11 -D AUTOLOAD_DYNAMIC_KERNELS -D __DATE__="redacted" -D __TIMESTAMP__="redacted" -D __TIME__="redacted" -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -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 -Wall -Wunused-but-set-parameter -Wno-free-nonheap-object -Wno-builtin-macro-redefined -w -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/home/pyrefcon/.cache/bazel/_bazel_alan/39be661231df2a680c9b74265384c13c/execroot/org_tensorflow -ferror-limit 19 -fvisibility hidden -stack-protector 1 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/pyrefcon/tensorflow/csa-scan/reports -x c++ tensorflow/python/util/fast_module_type.cc

tensorflow/python/util/fast_module_type.cc

1/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
14==============================================================================*/
15#include <Python.h>
16
17#include "absl/container/flat_hash_map.h"
18#include "pybind11/pybind11.h"
19#include "tensorflow/core/platform/logging.h"
20
21namespace py = pybind11;
22constexpr int PY_MODULE_TYPE_TP_BASIC_SIZE = 56;
23
24struct FastModuleObject {
25 // A dummy array that ensures enough size is reserved for FastModuleObject,
26 // because it's inherited from PyModuleObject.
27 const std::array<char, PY_MODULE_TYPE_TP_BASIC_SIZE> opaque_base_fields;
28 // A cache that helps reduce attribute lookup overhead.
29 absl::flat_hash_map<PyObject *, PyObject *> attr_map;
30 // pointer to the external getattribute function
31 PyObject *cb_getattribute = nullptr;
32 // pointer to the external getattr function
33 PyObject *cb_getattr = nullptr;
34 // static PyTypeObject type;
35
36 FastModuleObject() = delete;
37 ~FastModuleObject() = delete;
38 static FastModuleObject *UncheckedCast(PyObject *obj);
39};
40
41static int FastModule_init(FastModuleObject *self, PyObject *args,
42 PyObject *kwds) {
43 DCHECK_EQ(PY_MODULE_TYPE_TP_BASIC_SIZE, PyModule_Type.tp_basicsize)while (false && ((void)(PY_MODULE_TYPE_TP_BASIC_SIZE)
, (void)(PyModule_Type.tp_basicsize), 0)) ::tensorflow::internal
::LogMessageFatal("tensorflow/python/util/fast_module_type.cc"
, 43)
;
44 if (PyModule_Type.tp_init(reinterpret_cast<PyObject *>(self), args, kwds) < 0)
45 return -1;
46 new (&(self->attr_map)) absl::flat_hash_map<PyObject *, PyObject *>();
47 return 0;
48}
49
50// Parses the input as a callable and checks the result.
51static PyObject *ParseFunc(PyObject *args) {
52 PyObject *func;
53 if (!PyArg_ParseTuple(args, "O:set_callback", &func)) return nullptr;
54 if (!PyCallable_Check(func)) {
55 PyErr_SetString(PyExc_TypeError, "input args must be callable");
56 return nullptr;
57 }
58 Py_INCREF(func)_Py_INCREF(((PyObject*)(func))); // Add a reference to new callback
59 return func;
60}
61
62// Sets the pointer 'cb_getattribute' in the FastModuleObject object
63// corresponding to 'self'.
64static PyObject *SetGetattributeCallback(PyObject *self, PyObject *args) {
65 PyObject *func = ParseFunc(args);
66 // Dispose of previous callback
67 Py_XDECREF(FastModuleObject::UncheckedCast(self)->cb_getattribute)_Py_XDECREF(((PyObject*)(FastModuleObject::UncheckedCast(self
)->cb_getattribute)))
;
68 // Remember new callback
69 FastModuleObject::UncheckedCast(self)->cb_getattribute = func;
70 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
71}
72
73// Sets the pointer 'cb_getattr' in the FastModuleObject object
74// corresponding to 'self'.
75static PyObject *SetGetattrCallback(PyObject *self, PyObject *args) {
76 PyObject *func = ParseFunc(args);
77 // Dispose of previous callback
78 Py_XDECREF(FastModuleObject::UncheckedCast(self)->cb_getattr)_Py_XDECREF(((PyObject*)(FastModuleObject::UncheckedCast(self
)->cb_getattr)))
;
79 // Remember new callback
80 FastModuleObject::UncheckedCast(self)->cb_getattr = func;
81 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
82}
83
84// Inserts or updates a key-value pair in the cache 'attr_map'
85// of the FastModuleObject object corresponding to 'self'.
86static PyObject *FastDictInsert(FastModuleObject *self, PyObject *args) {
87 PyObject *name, *value;
88 if (!PyArg_ParseTuple(args, "OO", &name, &value)) {
89 PyErr_SetString(PyExc_TypeError, "_fastdict_insert: incorrect inputs");
90 return nullptr;
91 }
92 auto &attr_map = self->attr_map;
93 if (attr_map.find(name) != attr_map.end()) {
94 Py_DECREF(name)_Py_DECREF(((PyObject*)(name)));
95 Py_DECREF(value)_Py_DECREF(((PyObject*)(value)));
96 }
97 attr_map.insert_or_assign(name, value);
98 // Increment the reference count
99 Py_INCREF(name)_Py_INCREF(((PyObject*)(name)));
100 Py_INCREF(value)_Py_INCREF(((PyObject*)(value)));
101 // Properly handle returning Py_None
102 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
103}
104
105// Gets a value from a key in the cache 'attr_map'
106// of the FastModuleObject object corresponding to 'self'.
107static PyObject *FastDictGet(FastModuleObject *self, PyObject *args) {
108 PyObject *name;
109 if (!PyArg_ParseTuple(args, "O", &name)) {
110 PyErr_SetString(PyExc_TypeError, "_fastdict_get: incorrect inputs");
111 return nullptr;
112 }
113 auto &attr_map = self->attr_map;
114 auto result = attr_map.find(name);
115 if (result != attr_map.end()) {
116 PyObject *value = result->second;
117 Py_INCREF(value)_Py_INCREF(((PyObject*)(value)));
118 return value;
119 }
120 // Copied from CPython's moduleobject.c
121 PyErr_Format(PyExc_KeyError, "module has no attribute '%U'", name);
122 return nullptr;
123}
124
125// Returns true if a key exists in the cache 'attr_map'
126// of the FastModuleObject object corresponding to 'self',
127// otherwise returns false.
128static PyObject *FastDictContains(FastModuleObject *self, PyObject *args) {
129 PyObject *name;
130 if (!PyArg_ParseTuple(args, "O", &name)) {
131 PyErr_SetString(PyExc_TypeError, "_fastdict_key_in: incorrect inputs");
132 return nullptr;
133 }
134 const auto &attr_map = self->attr_map;
135 const auto result = attr_map.contains(name);
136 if (result) {
137 // Properly handle returning Py_True
138 Py_RETURN_TRUEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_TrueStruct
)))), ((PyObject *) &_Py_TrueStruct)
;
139 }
140 // Properly handle returning Py_False
141 Py_RETURN_FALSEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct
)))), ((PyObject *) &_Py_FalseStruct)
;
142}
143
144// Calls a function 'func' with inputs 'self' and 'args'.
145static PyObject *CallFunc(FastModuleObject *self, PyObject *args,
146 PyObject *func) {
147 if (func == nullptr) {
148 PyErr_SetString(PyExc_NameError,
149 "Attempting to call a callback that was not defined");
150 return nullptr;
151 }
152 PyObject *name;
153 if (!PyArg_ParseTuple(args, "O", &name)) {
154 PyErr_SetString(PyExc_TypeError, "CallFunc: incorrect inputs");
155 return nullptr;
156 }
157 PyObject *arglist = Py_BuildValue("(OO)", self, name);
158 auto result = PyObject_CallObject(func, arglist);
159 Py_DECREF(arglist)_Py_DECREF(((PyObject*)(arglist)));
160 return result;
161}
162
163static PyMethodDef FastModule_methods[] = {
164 {"_fastdict_insert", reinterpret_cast<PyCFunction>(FastDictInsert),
165 METH_VARARGS0x0001, "Registers a method to the fast lookup table."},
166 {"_fastdict_get", reinterpret_cast<PyCFunction>(FastDictGet), METH_VARARGS0x0001,
167 "Gets a method from the fast lookup table."},
168 {"_fastdict_key_in", reinterpret_cast<PyCFunction>(FastDictContains),
169 METH_VARARGS0x0001, "Checks if a method exists in the fast lookup table."},
170 {"set_getattribute_callback", SetGetattributeCallback, METH_VARARGS0x0001,
171 "Defines the callback function to replace __getattribute__"},
172 {"set_getattr_callback", SetGetattrCallback, METH_VARARGS0x0001,
173 "Defines the callback function to replace __getattr__"},
174 {nullptr, nullptr, 0, nullptr},
175};
176
177// Attempts to get the attribute based on 'name' as the key in cache 'attr_map'
178// of the FastModuleObject object corresponding to 'module'.
179// If the lookup fails in the cache, either uses
180// a user-defined callback 'cb_getattribute'
181// or the default 'tp_getattro' function to look for the attribute.
182static PyObject *FastTpGetattro(PyObject *module, PyObject *name) {
183 FastModuleObject *fast_module = FastModuleObject::UncheckedCast(module);
184 auto &attr_map = fast_module->attr_map;
185 auto it = attr_map.find(name);
186 // If the attribute lookup is successful in the cache, directly return it.
187 if (it != attr_map.end()) {
1
Taking false branch
188 PyObject *value = it->second;
189 Py_INCREF(value)_Py_INCREF(((PyObject*)(value)));
190 return value;
191 }
192 PyObject *arglist = Py_BuildValue("(O)", name);
2
Calling 'Py_BuildValue'
4
Returning from 'Py_BuildValue'
9
PyObject ownership leak with reference count of 1
193 PyObject *result;
194 // Prefer the customized callback function over the default function.
195 if (fast_module->cb_getattribute != nullptr) {
5
Assuming the condition is false
6
Taking false branch
196 result = CallFunc(fast_module, arglist, fast_module->cb_getattribute);
197 } else {
198 result = PyModule_Type.tp_getattro(module, name);
199 }
200 // Return result if it's found
201 if (result != nullptr) {
7
Assuming the condition is true
8
Taking true branch
202 return result;
203 }
204 // If the default lookup fails and an AttributeError is raised,
205 // clear the error status before using the __getattr__ callback function.
206 auto is_error = PyErr_Occurred();
207 if (is_error && PyErr_ExceptionMatches(PyExc_AttributeError) &&
208 fast_module->cb_getattr != nullptr) {
209 PyErr_Clear();
210 return CallFunc(fast_module, arglist, fast_module->cb_getattr);
211 }
212 // If all options were used up
213 return result;
214}
215
216// Customized destructor for FastModuleType.tp_dealloc
217// In addition to default behavior it also clears up the contents in attr_map.
218static void FastModuleObjectDealloc(PyObject *module) {
219 auto &attr_map = FastModuleObject::UncheckedCast(module)->attr_map;
220 for (auto &it : attr_map) {
221 Py_DECREF(it.first)_Py_DECREF(((PyObject*)(it.first)));
222 Py_DECREF(it.second)_Py_DECREF(((PyObject*)(it.second)));
223 }
224 attr_map.~flat_hash_map<PyObject *, PyObject *>();
225 Py_TYPE(module)(((PyObject*)(module))->ob_type)->tp_free(module);
226}
227
228static PyTypeObject FastModuleType = []() {
229 PyTypeObject obj = {PyVarObject_HEAD_INIT(&PyType_Type, 0){ { 1, &PyType_Type }, 0 },};
230 obj.tp_name = "fast_module_type.FastModuleType";
231 obj.tp_basicsize = sizeof(FastModuleObject);
232 obj.tp_itemsize = 0;
233 obj.tp_dealloc = FastModuleObjectDealloc;
234 obj.tp_getattro = FastTpGetattro;
235 obj.tp_flags = Py_TPFLAGS_DEFAULT( 0 | (1UL << 18) | 0) | Py_TPFLAGS_BASETYPE(1UL << 10);
236 obj.tp_doc = "FastModuleType objects";
237 obj.tp_methods = FastModule_methods;
238 obj.tp_init = reinterpret_cast<initproc>(FastModule_init);
239 return obj;
240}();
241
242// Returns true if the type of 'obj' or any of its parent class
243// is equal to 'target'. Otherwise returns false.
244bool IsAnyBaseSameType(const PyObject *obj, const PyTypeObject *target) {
245 auto *tp = Py_TYPE(obj)(((PyObject*)(obj))->ob_type);
246 while (true) {
247 if (tp == target) return true;
248 // If the default type is found, there is no need to search further
249 if (tp == &PyBaseObject_Type) break;
250 tp = tp->tp_base;
251 }
252 return false;
253}
254
255// Casts 'obj' to 'FastModuleObject *'.
256// Conducts a check only in non-optimized builds.
257FastModuleObject *FastModuleObject::UncheckedCast(PyObject *obj) {
258 DCHECK(IsAnyBaseSameType(obj, &FastModuleType))while (false && (IsAnyBaseSameType(obj, &FastModuleType
))) ::tensorflow::internal::LogMessageFatal("tensorflow/python/util/fast_module_type.cc"
, 258)
;
259 return reinterpret_cast<FastModuleObject *>(obj);
260}
261
262PYBIND11_MODULE(fast_module_type, m)static ::pybind11::module_::module_def pybind11_module_def_fast_module_type
; __attribute__ ((__unused__)) static void pybind11_init_fast_module_type
(::pybind11::module_ &); extern "C" __attribute__ ((__unused__
)) __attribute__ ((visibility("default"))) PyObject *PyInit_fast_module_type
(); extern "C" __attribute__ ((visibility("default"))) PyObject
*PyInit_fast_module_type() { { const char *compiled_ver = "3"
"." "8"; const char *runtime_ver = Py_GetVersion(); size_t len
= std::strlen(compiled_ver); if (std::strncmp(runtime_ver, compiled_ver
, len) != 0 || (runtime_ver[len] >= '0' && runtime_ver
[len] <= '9')) { PyErr_Format(PyExc_ImportError, "Python version mismatch: module was compiled for Python %s, "
"but the interpreter version is incompatible: %s.", compiled_ver
, runtime_ver); return nullptr; } } pybind11::detail::get_internals
(); auto m = ::pybind11::module_::create_extension_module( "fast_module_type"
, nullptr, &pybind11_module_def_fast_module_type); try { pybind11_init_fast_module_type
(m); return m.ptr(); } catch (pybind11::error_already_set &
e) { PyErr_SetString(PyExc_ImportError, e.what()); return nullptr
; } catch (const std::exception &e) { PyErr_SetString(PyExc_ImportError
, e.what()); return nullptr; } } void pybind11_init_fast_module_type
(::pybind11::module_ &m)
{
263 FastModuleType.tp_base = &PyModule_Type;
264 FastModuleType.tp_setattro = [](PyObject *module, PyObject *name,
265 PyObject *value) -> int {
266 auto &attr_map = FastModuleObject::UncheckedCast(module)->attr_map;
267 if (attr_map.find(name) != attr_map.end()) {
268 Py_DECREF(name)_Py_DECREF(((PyObject*)(name)));
269 Py_DECREF(value)_Py_DECREF(((PyObject*)(value)));
270 }
271 attr_map.insert_or_assign(name, value);
272 // Increment the reference count
273 Py_INCREF(name)_Py_INCREF(((PyObject*)(name)));
274 Py_INCREF(value)_Py_INCREF(((PyObject*)(value)));
275 PyObject_GenericSetAttr(module, name, value);
276 return 0;
277 };
278
279 m.doc() = R"pbdoc(
280 fast_module_type
281 -----
282 )pbdoc";
283 // Use getter function to hold attributes rather than pybind11's m.attr due to
284 // b/145559202.
285 m.def(
286 "get_fast_module_type_class",
287 []() {
288 return py::cast<py::object>(
289 reinterpret_cast<PyObject *>(&FastModuleType));
290 },
291 py::return_value_policy::reference);
292}

/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();
3
Setting reference count to 1
7}
8#else
9#warning "API Py_BuildValue is defined as a macro."
10#endif