Bug Summary

File:build/../torch/csrc/fx/fx_init.cpp
Warning:line 89, column 26
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 fx_init.cpp -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-inlined-defensive-checks=false,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/pytorch/csa-scan,ctu-index-name=/tmp/pyrefcon/pytorch/csa-scan/externalDefMap.txt,ctu-invocation-list=/tmp/pyrefcon/pytorch/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 -relaxed-aliasing -fno-rounding-math -ffp-exception-behavior=ignore -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/tmp/pyrefcon/pytorch/build -resource-dir /opt/pyrefcon/lib/clang/13.0.0 -isystem third_party/gloo -isystem ../cmake/../third_party/gloo -isystem ../cmake/../third_party/googletest/googlemock/include -isystem ../cmake/../third_party/googletest/googletest/include -isystem ../third_party/protobuf/src -isystem ../third_party/gemmlowp -isystem ../third_party/neon2sse -isystem ../third_party/XNNPACK/include -isystem ../third_party -isystem ../cmake/../third_party/eigen -isystem /opt/pyrefcon/lib/pyrefcon/models/python3.8 -isystem /usr/lib/python3/dist-packages/numpy/core/include -isystem ../cmake/../third_party/pybind11/include -isystem /usr/lib/x86_64-linux-gnu/openmpi/include/openmpi -isystem /usr/lib/x86_64-linux-gnu/openmpi/include -isystem ../third_party/ideep/mkl-dnn/include -isystem ../third_party/ideep/include -D BUILDING_TESTS -D FMT_HEADER_ONLY=1 -D HAVE_MALLOC_USABLE_SIZE=1 -D HAVE_MMAP=1 -D HAVE_SHM_OPEN=1 -D HAVE_SHM_UNLINK=1 -D MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS -D ONNXIFI_ENABLE_EXT=1 -D ONNX_ML=1 -D ONNX_NAMESPACE=onnx_torch -D THP_BUILD_MAIN_LIB -D USE_C10D -D USE_C10D_GLOO -D USE_C10D_MPI -D USE_DISTRIBUTED -D USE_EXTERNAL_MZCRC -D USE_NUMPY -D USE_RPC -D USE_TENSORPIPE -D USE_VALGRIND -D _FILE_OFFSET_BITS=64 -D torch_python_EXPORTS -I aten/src -I ../aten/src -I . -I ../ -I ../cmake/../third_party/benchmark/include -I caffe2/contrib/aten -I ../third_party/onnx -I third_party/onnx -I ../third_party/foxi -I third_party/foxi -I ../torch/.. -I ../torch/../aten/src -I ../torch/../aten/src/TH -I caffe2/aten/src -I third_party -I ../torch/../third_party/valgrind-headers -I ../torch/../third_party/gloo -I ../torch/../third_party/onnx -I ../torch/csrc -I ../torch/csrc/api/include -I ../torch/lib -I ../torch/lib/libshm -I ../torch/csrc/distributed -I ../torch/csrc/api -I ../c10/.. -I third_party/ideep/mkl-dnn/include -I ../third_party/ideep/mkl-dnn/src/../include -I ../torch/lib/libshm/../../../torch/lib -I ../third_party/fmt/include -D USE_PTHREADPOOL -D NDEBUG -D USE_KINETO -D LIBKINETO_NOCUPTI -D USE_FBGEMM -D USE_QNNPACK -D USE_PYTORCH_QNNPACK -D USE_XNNPACK -D SYMBOLICATE_MOBILE_DEBUG_HANDLE -D HAVE_AVX_CPU_DEFINITION -D HAVE_AVX2_CPU_DEFINITION -D NDEBUG -D NDEBUG -D CAFFE2_USE_GLOO -D HAVE_GCC_GET_CPUID -D USE_AVX -D USE_AVX2 -D TH_HAVE_THREAD -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 -O3 -Wno-narrowing -Wall -Wextra -Werror=return-type -Wno-missing-field-initializers -Wno-type-limits -Wno-array-bounds -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-result -Wno-unused-local-typedefs -Wno-strict-overflow -Wno-strict-aliasing -Wno-error=deprecated-declarations -Wno-stringop-overflow -Wno-psabi -Wno-error=pedantic -Wno-error=redundant-decls -Wno-error=old-style-cast -Wno-unused-but-set-variable -Wno-maybe-uninitialized -Werror=format -Werror=cast-function-type -Wno-stringop-overflow -Wno-write-strings -Wno-strict-aliasing -w -std=gnu++14 -fdeprecated-macro -fdebug-compilation-dir=/tmp/pyrefcon/pytorch/build -ferror-limit 19 -fvisibility-inlines-hidden -fopenmp -fopenmp-cuda-parallel-target-regions -pthread -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -faligned-allocation -fcolor-diagnostics -vectorize-loops -vectorize-slp -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/pyrefcon/pytorch/csa-scan/reports -x c++ ../torch/csrc/fx/fx_init.cpp

../torch/csrc/fx/fx_init.cpp

1#include <torch/csrc/utils/pybind.h>
2
3namespace torch {
4namespace fx {
5
6struct ToRestore {
7 PyObject* m_self;
8 PyMethodDef* m_ml;
9#if PY_VERSION_HEX((3 << 24) | (8 << 16) | (5 << 8) | (0xF <<
4) | (0 << 0))
>= 0x03080000
10 vectorcallfunc vectorcall;
11#endif
12 PyObject* original_fn; // The original method we are trying to patch
13 PyObject* patch_fn; // The function we're patching in place of original_fn
14};
15
16class DecRefGuard {
17 public:
18 DecRefGuard(PyObject* obj) : obj(obj) {}
19 ~DecRefGuard() {
20 Py_DECREF(obj)_Py_DECREF(((PyObject*)(obj)));
21 }
22
23 private:
24 PyObject* obj;
25};
26
27PyObject* replacement_method(PyObject* self, PyObject* args, PyObject* kwargs) {
28 DecRefGuard self_guard(self);
29 // restore the implementation immediately so that patch_fn lives for as little
30 // as possible
31 ToRestore* to_restore = (ToRestore*)PyBytes_AsString(self);
32 PyCFunctionObject* patch_method_c =
33 ((PyCFunctionObject*)to_restore->original_fn);
34 patch_method_c->m_self = to_restore->m_self;
35 patch_method_c->m_ml = to_restore->m_ml;
36#if PY_VERSION_HEX((3 << 24) | (8 << 16) | (5 << 8) | (0xF <<
4) | (0 << 0))
>= 0x03080000
37 patch_method_c->vectorcall = to_restore->vectorcall;
38#endif
39
40 if (kwargs) {
41 Py_INCREF(kwargs)_Py_INCREF(((PyObject*)(kwargs)));
42 } else {
43 kwargs = PyDict_New();
44 }
45 DecRefGuard kwargs_guard(kwargs);
46
47 PyObject* result = nullptr;
48 // Creates a tuple of 3 python objects
49 PyObject* args_ =
50 Py_BuildValue("(OOO)", to_restore->original_fn, args, kwargs);
51 if (!args_) {
52 return nullptr;
53 }
54 DecRefGuard args_guard(args_);
55 // Calls the patched function with arguments of (original function, args,
56 // kwargs)
57 result = PyEval_CallObject(to_restore->patch_fn, args_)PyEval_CallObjectWithKeywords(to_restore->patch_fn, args_,
(PyObject *)__null)
;
58 return result;
59}
60// The general idea is that we're patching a PyCFunctionObject, which has a
61// couple relevant parts: m_ml: A PyMethodDef (the actual function to call)
62// m_self: The self arg.
63// vectorcall: An alternate calling convention (Python 3.8+)
64// Usually we call obj.m_ml(obj.m_self, args, kwargs). However, we want to patch
65// m_ml with ReplacementMethod (which calls our user-provided `patch_fn`). Thus,
66// we also replace `m_self` with `ToRestore`, which contains all the information
67// needed to restore the original function.
68//
69// `patch_function` parses the necessary information from the original
70// PyCFunction and then patches it. When that function is called, it calls
71// `replacement_method`, which then restores back the original `m_ml` and
72// `m_self` values, as well as calling the user-defined `patch_fn`.
73
74static PyObject* patch_function(PyObject* self, PyObject* args) {
75 static PyMethodDef ReplacementMethod = {
76 "replace",
77 (PyCFunction)(void (*)())replacement_method,
78 METH_VARARGS0x0001 | METH_KEYWORDS0x0002,
79 "Replaced method implementation."};
80
81 ToRestore to_restore = {};
82 if (!PyArg_ParseTuple(
1
Assuming the condition is false
2
Taking false branch
83 args, "OO", &to_restore.original_fn, &to_restore.patch_fn)) {
84 return nullptr;
85 }
86 if (!PyCFunction_Check(to_restore.original_fn)((((PyObject*)(to_restore.original_fn))->ob_type) == &
PyCFunction_Type)
) {
3
Assuming the condition is true
4
Taking true branch
87 std::stringstream err;
88 err << "Patched object ";
89 PyObject* obj_repr = PyObject_Repr(to_restore.original_fn);
5
Calling 'PyObject_Repr'
7
Returning from 'PyObject_Repr'
10
PyObject ownership leak with reference count of 1
90 if (PyUnicode_Check(obj_repr)((((((PyObject*)(obj_repr))->ob_type))->tp_flags & (
(1UL << 28))) != 0)
) {
8
Assuming the condition is false
9
Taking false branch
91 err << PyUnicode_AS_DATA(obj_repr)((const char *)(( (((PyASCIIObject *)(obj_repr))->wstr) ? (
((PyASCIIObject *)(obj_repr))->wstr) : PyUnicode_AsUnicode
(((PyObject*)(obj_repr))))))
<< " ";
92 }
93 err << " is not a CFunction. Please report a bug to PyTorch!";
94 PyErr_SetString(PyExc_RuntimeError, err.str().c_str());
95 return nullptr;
96 }
97 DecRefGuard patch_fn_guard(to_restore.patch_fn);
98 Py_INCREF(to_restore.patch_fn)_Py_INCREF(((PyObject*)(to_restore.patch_fn)));
99 DecRefGuard patched_method_guard(to_restore.original_fn);
100 Py_INCREF(to_restore.original_fn)_Py_INCREF(((PyObject*)(to_restore.original_fn)));
101 PyCFunctionObject* patch_method_c =
102 ((PyCFunctionObject*)to_restore.original_fn);
103
104 to_restore.m_self = patch_method_c->m_self;
105 to_restore.m_ml = patch_method_c->m_ml;
106#if PY_VERSION_HEX((3 << 24) | (8 << 16) | (5 << 8) | (0xF <<
4) | (0 << 0))
>= 0x03080000
107 to_restore.vectorcall = patch_method_c->vectorcall;
108#endif
109
110 patch_method_c->m_self =
111 PyBytes_FromStringAndSize((const char*)&to_restore, sizeof(ToRestore));
112 patch_method_c->m_ml = &ReplacementMethod;
113#if PY_VERSION_HEX((3 << 24) | (8 << 16) | (5 << 8) | (0xF <<
4) | (0 << 0))
>= 0x03080000
114 patch_method_c->vectorcall = nullptr;
115#endif
116 return Py_None(&_Py_NoneStruct);
117}
118
119
120void initFx(PyObject* module) {
121 static std::array<PyMethodDef, 2> PatchMethods = {{
122 {"patch_function", patch_function, METH_VARARGS0x0001, "Save"},
123 {nullptr},
124 }};
125
126 static struct PyModuleDef path = {
127 PyModuleDef_HEAD_INIT{ { 1, __null }, __null, 0, __null, },
128 "patch", /* name of module */
129 "", /* module documentation, may be NULL */
130 -1, /* size of per-interpreter state of the module, or -1 if the module
131 keeps state in global variables. */
132 PatchMethods.data()};
133 PyObject* patch = PyModule_Create(&path)PyModule_Create2(&path, 1013);
134 if (!patch) {
135 throw python_error();
136 }
137 if (PyModule_AddObject(module, "_fx", patch) != 0) {
138 throw python_error();
139 }
140}
141} // namespace fx
142} // namespace torch

/opt/pyrefcon/lib/pyrefcon/models/models/PyObject_Repr.model

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