Bug Summary

File:build/../torch/csrc/autograd/python_function.cpp
Warning:line 699, column 22
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 python_function.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/autograd/python_function.cpp

../torch/csrc/autograd/python_function.cpp

1#include <torch/csrc/autograd/python_function.h>
2
3#include <torch/csrc/python_headers.h>
4#include <structmember.h>
5#include <ATen/ATen.h>
6#include <ATen/SequenceNumber.h>
7#include <c10/util/irange.h>
8#include <pybind11/pybind11.h>
9
10#include <torch/csrc/THP.h>
11#include <torch/csrc/autograd/grad_mode.h>
12#include <torch/csrc/autograd/functions/accumulate_grad.h>
13#include <torch/csrc/autograd/functions/basic_ops.h>
14#include <torch/csrc/autograd/functions/utils.h>
15#include <torch/csrc/autograd/python_cpp_function.h>
16#include <torch/csrc/autograd/python_hook.h>
17#include <torch/csrc/autograd/saved_variable.h>
18#include <torch/csrc/autograd/python_anomaly_mode.h>
19#include <torch/csrc/jit/frontend/tracer.h>
20#include <torch/csrc/jit/ir/ir.h>
21#include <torch/csrc/jit/python/python_tracer.h>
22#include <torch/csrc/jit/python/pybind_utils.h>
23#include <torch/csrc/utils/python_strings.h>
24#include <torch/csrc/DynamicTypes.h>
25#include <torch/csrc/Exceptions.h>
26
27#include <exception>
28#include <functional>
29#include <memory>
30#include <stdexcept>
31#include <string>
32#include <tuple>
33#include <unordered_map>
34#include <unordered_set>
35#include <utility>
36#include <vector>
37
38using namespace torch;
39using namespace torch::autograd;
40using namespace torch::jit;
41using at::Tensor;
42
43// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
44PyObject *THPFunctionClass = nullptr;
45
46#define THPFunction_assert(condition, ...)if (!(condition)) { THPUtils_setError(...); throw python_error
(); }
\
47 if (!(condition)) { THPUtils_setError(__VA_ARGS__); throw python_error(); }
48
49namespace torch { namespace autograd {
50
51void PyNode::throw_python_error() {
52 python_error err;
53 err.persist();
54 throw err;
55}
56
57// NOTE: this function is written in a way that assumes it's only called for backward;
58// it's used by engine.cpp. This is responsible for forwarding a call from
59// C++'s Node::apply to a Python method "apply".
60auto PyNode::apply(variable_list&& inputs) -> variable_list {
61 pybind11::gil_scoped_acquire gil;
62 at::OptionalDeviceGuard _device_guard;
63 THPFunction* py_fn = (THPFunction*)obj;
64
65 // Massage a C++ variable_list into a Python arguments tuple
66 auto num_inputs = inputs.size();
67 THPObjectPtr pyInputs(PyTuple_New(num_inputs));
68 if (!pyInputs) throw_python_error();
69 auto& output_info = py_fn->output_info;
70 for (const auto i : c10::irange(num_inputs)) {
71 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
72 PyObject* input;
73 if (inputs[i].defined() || !py_fn->materialize_grads) {
74 input = THPVariable_Wrap(inputs[i]);
75 } else {
76 input = THPVariable_Wrap(output_info[i].zeros(_device_guard));
77 }
78 if (!input) throw_python_error();
79 PyTuple_SET_ITEM(pyInputs.get(), i, input)PyTuple_SetItem(pyInputs.get(), i, input);
80 }
81
82 THPObjectPtr apply_fn(PyObject_GetAttrString(obj, "apply"));
83 if (!apply_fn) throw_python_error();
84 THPObjectPtr r(PyObject_CallObject(apply_fn, pyInputs.get()));
85 if (!r) throw_python_error();
86 ensure_tuple(r);
87
88 auto& is_variable_input = py_fn->is_variable_input;
89 int num_outputs = PyTuple_GET_SIZE(r.get())(((PyVarObject*)(((PyTupleObject *)(r.get()))))->ob_size);
90 int num_forward_inputs = is_variable_input.size();
91 // Returning too many results is ok, but only as long as they're all None.
92 // Truncate the result tuple in that case.
93 if (num_outputs > num_forward_inputs) {
94 bool all_none = true;
95 for (const auto i : c10::irange(num_forward_inputs, num_outputs)) {
96 all_none &= PyTuple_GET_ITEM(r.get(), i)(((PyTupleObject *)(r.get()))->ob_item[i]) == Py_None(&_Py_NoneStruct);
97 }
98 if (all_none) {
99 num_outputs = num_forward_inputs;
100 r = PyTuple_GetSlice(r.get(), 0, num_forward_inputs);
101 if (!r) throw_python_error();
102 }
103 }
104
105 // Now the number of gradients should match
106 if (num_outputs != num_forward_inputs) {
107 std::string msg("function ");
108 msg += name() + " returned an incorrect number of gradients (expected ";
109 msg += std::to_string(num_forward_inputs) + ", got " ;
110 msg += std::to_string(num_outputs) + ")";
111 throw std::runtime_error(msg);
112 }
113
114 // Massage the Python results tuple back into a C++ variable_list
115 variable_list results;
116 results.reserve(num_outputs);
117 for (int i = 0; i != num_outputs; ++i) {
118 PyObject* output = PyTuple_GET_ITEM(r.get(), i)(((PyTupleObject *)(r.get()))->ob_item[i]);
119 bool was_variable = is_variable_input[i];
120 if (!was_variable) {
121 if (output != Py_None(&_Py_NoneStruct)) {
122 std::string msg("function ");
123 msg += name() + " returned a gradient different than None at position ";
124 msg += std::to_string(i + 1) + ", but the corresponding forward input was not a Variable";
125 throw std::runtime_error(msg);
126 }
127 continue;
128 }
129 if (output == Py_None(&_Py_NoneStruct)) {
130 results.emplace_back();
131 } else {
132 if (!THPVariable_Check(output)) {
133 std::string msg("expected Variable or None (got ");
134 msg += THPUtils_typename(output)((((PyObject*)(output))->ob_type)->tp_name);
135 msg += ")";
136 throw std::runtime_error(msg);
137 }
138 results.emplace_back(THPVariable_Unpack(output));
139 }
140 }
141
142 return results;
143}
144
145auto PyNode::is_traceable() -> bool {
146 pybind11::gil_scoped_acquire gil;
147 THPObjectPtr forward_class {PyObject_GetAttrString(obj, "_forward_cls")};
148 if (!forward_class) throw_python_error();
149 THPObjectPtr traceable_py_bool {PyObject_GetAttrString(forward_class, "is_traceable")};
150 if (!traceable_py_bool) throw_python_error();
151 return traceable_py_bool == Py_True((PyObject *) &_Py_TrueStruct);
152}
153
154auto PyNode::release_variables() -> void {
155 pybind11::gil_scoped_acquire gil;
156 auto f = (THPFunction*) obj;
157 f->saved_variables.clear();
158 f->has_freed_buffers = 1;
159}
160
161auto PyNode::name() const -> std::string {
162 pybind11::gil_scoped_acquire gil;
163 auto f = (THPFunction*) obj;
164 auto name = std::string(Py_TYPE(f)(((PyObject*)(f))->ob_type)->tp_name);
165 return name;
166}
167
168}} // namespace torch::autograd
169
170// Traverse and clear are required for supporting Python's GC cycle handling.
171static int THPFunction_traverse(THPFunction *self, visitproc visit, void *arg)
172{
173 // cdata could be null if the PyNode has already gone out of scope
174 // by the time we're GC'ing this THPFunction (e.g., the user saved grad_fn only).
175 //
176 // TODO: I'm not really sure if we're actually obligated to traverse PyObject
177 // that is stored in PyNode, since we don't really own that C++ object.
178 if (auto cdata = self->cdata.lock()) {
179 for (const auto& hook : cdata->pre_hooks()) {
180 if (auto pyhook = dynamic_cast<PyFunctionPreHook*>(hook.get())) {
181 Py_VISIT(pyhook->dict)do { if (pyhook->dict) { int vret = visit(((PyObject*)(pyhook
->dict)), arg); if (vret) return vret; } } while (0)
;
182 }
183 }
184 for (const auto& hook : cdata->post_hooks()) {
185 if (auto pyhook = dynamic_cast<PyFunctionPostHook*>(hook.get())) {
186 Py_VISIT(pyhook->dict)do { if (pyhook->dict) { int vret = visit(((PyObject*)(pyhook
->dict)), arg); if (vret) return vret; } } while (0)
;
187 }
188 }
189 }
190 Py_VISIT(self->to_save)do { if (self->to_save) { int vret = visit(((PyObject*)(self
->to_save)), arg); if (vret) return vret; } } while (0)
;
191 Py_VISIT(self->non_differentiable)do { if (self->non_differentiable) { int vret = visit(((PyObject
*)(self->non_differentiable)), arg); if (vret) return vret
; } } while (0)
;
192 Py_VISIT(self->dirty_tensors)do { if (self->dirty_tensors) { int vret = visit(((PyObject
*)(self->dirty_tensors)), arg); if (vret) return vret; } }
while (0)
;
193 return 0;
194}
195
196static int THPFunction_clear(THPFunction *self)
197{
198 // Note that the cdata might not be expired yet in the case where this
199 // object is part of a cycle and the GC happens to tp_clear this PyObject
200 // before the other ones that trigger the de-allocation of the cdata
201
202 Py_CLEAR(self->needs_input_grad)do { PyObject *_py_tmp = ((PyObject*)(self->needs_input_grad
)); if (_py_tmp != __null) { (self->needs_input_grad) = __null
; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0)
;
203
204 Py_CLEAR(self->to_save)do { PyObject *_py_tmp = ((PyObject*)(self->to_save)); if (
_py_tmp != __null) { (self->to_save) = __null; _Py_DECREF(
((PyObject*)(_py_tmp))); } } while (0)
;
205 Py_CLEAR(self->non_differentiable)do { PyObject *_py_tmp = ((PyObject*)(self->non_differentiable
)); if (_py_tmp != __null) { (self->non_differentiable) = __null
; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0)
;
206 Py_CLEAR(self->dirty_tensors)do { PyObject *_py_tmp = ((PyObject*)(self->dirty_tensors)
); if (_py_tmp != __null) { (self->dirty_tensors) = __null
; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0)
;
207
208 self->output_info.clear();
209 self->input_info.clear();
210 self->saved_variables.clear();
211 self->is_variable_input.clear();
212
213 return 0;
214}
215
216static void THPFunction_dealloc(THPFunction* self)
217{
218 // Why is this guaranteed to be true? Suppose that self->cdata is non-null
219 // (otherwise the condition is trivially true). Then there is a PyNode
220 // which contains an owning reference to this object. But we are only
221 // allowed to clear if all owning references are gone! Contradiction.
222 //
223 // However, note that THPFunction_clear is typically called in the shared_ptr
224 // destructor of PyNode; in that case, per
225 // https://cplusplus.github.io/LWG/lwg-active.html#2751 it's not currently
226 // specified in the standard that this is guaranteed. If you see this
227 // assert triggering in the wild, feel free to comment it out. They're
228 // likely to standardize that you ARE guaranteed to see the weak pointers
229 // as expired in the destructor in the future, so we'll keep this for now.
230 TORCH_INTERNAL_ASSERT(self->cdata.expired())if ((__builtin_expect(static_cast<bool>(!(self->cdata
.expired())), 0))) { ::c10::detail::torchInternalAssertFail( __func__
, "../torch/csrc/autograd/python_function.cpp", static_cast<
uint32_t>(230), "self->cdata.expired()" "INTERNAL ASSERT FAILED at "
"\"../torch/csrc/autograd/python_function.cpp\"" ":" "230" ", please report a bug to PyTorch. "
, c10::str()); }
;
231
232 PyObject_GC_UnTrack(self);
233 THPFunction_clear(self);
234 self->cdata.~weak_ptr<PyNode>();
235 self->output_info.~vector();
236 self->input_info.~vector();
237 self->saved_variables.~vector();
238 self->is_variable_input.~vector();
239 Py_TYPE(self)(((PyObject*)(self))->ob_type)->tp_free((PyObject*)self);
240}
241
242PyObject *THPFunction_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
243{
244 PyObject* obj = type->tp_alloc(type, 0);
245 if (!obj) return nullptr;
246 // Python zero-initializes the object memory, so there's no need to initialize
247 // most fields
248 THPFunction* self = (THPFunction*)obj;
249 // Setup the PyNode later; we can't keep it live here
250 new (&self->cdata) std::weak_ptr<PyNode>();
251 new (&self->output_info) std::vector<VariableInfo>();
252 new (&self->input_info) std::vector<VariableInfo>();
253 new (&self->saved_variables) std::vector<SavedVariable>();
254 new (&self->is_variable_input) std::vector<bool>();
255 self->materialize_grads = true;
256 return obj;
257}
258
259////////////////////////////////////////////////////////////////////////////////
260// Forward
261////////////////////////////////////////////////////////////////////////////////
262
263// Bump the counters of all recorded dirty input tensors, adding each of them
264// into dirty_inputs. Also does some sanity checking.
265static std::unordered_set<at::TensorImpl*> _mark_dirty(THPFunction *self)
266{
267 // Increase versions of modified tensors
268 std::unordered_set<at::TensorImpl*> dirty_inputs;
269 if (!self->dirty_tensors) return dirty_inputs;
270
271 THPFunction_assert(PyTuple_Check(self->dirty_tensors), "autograd "if (!(((((((PyObject*)(self->dirty_tensors))->ob_type))
->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError
("autograd " "internal error: dirty_tensors attribute is expected to be a tuple "
"but is %s", ((((PyObject*)(self->dirty_tensors))->ob_type
)->tp_name)); throw python_error(); }
272 "internal error: dirty_tensors attribute is expected to be a tuple "if (!(((((((PyObject*)(self->dirty_tensors))->ob_type))
->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError
("autograd " "internal error: dirty_tensors attribute is expected to be a tuple "
"but is %s", ((((PyObject*)(self->dirty_tensors))->ob_type
)->tp_name)); throw python_error(); }
273 "but is %s", THPUtils_typename(self->dirty_tensors))if (!(((((((PyObject*)(self->dirty_tensors))->ob_type))
->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError
("autograd " "internal error: dirty_tensors attribute is expected to be a tuple "
"but is %s", ((((PyObject*)(self->dirty_tensors))->ob_type
)->tp_name)); throw python_error(); }
;
274 Py_ssize_t num_dirty = PyTuple_GET_SIZE(self->dirty_tensors)(((PyVarObject*)(((PyTupleObject *)(self->dirty_tensors)))
)->ob_size)
;
275 dirty_inputs.reserve(num_dirty);
276 for(const auto i : c10::irange(num_dirty)) {
277 PyObject *obj = PyTuple_GET_ITEM(self->dirty_tensors, i)(((PyTupleObject *)(self->dirty_tensors))->ob_item[i]);
278 THPFunction_assert(THPVariable_Check(obj), "mark_dirty can "if (!(THPVariable_Check(obj))) { THPUtils_setError("mark_dirty can "
"only accept variables, but argument %d is of type %s", i, (
(((PyObject*)(obj))->ob_type)->tp_name)); throw python_error
(); }
279 "only accept variables, but argument %d is of type %s", i,if (!(THPVariable_Check(obj))) { THPUtils_setError("mark_dirty can "
"only accept variables, but argument %d is of type %s", i, (
(((PyObject*)(obj))->ob_type)->tp_name)); throw python_error
(); }
280 THPUtils_typename(obj))if (!(THPVariable_Check(obj))) { THPUtils_setError("mark_dirty can "
"only accept variables, but argument %d is of type %s", i, (
(((PyObject*)(obj))->ob_type)->tp_name)); throw python_error
(); }
;
281
282 const auto& tensor = THPVariable_Unpack(obj);
283 dirty_inputs.insert(tensor.unsafeGetTensorImpl());
284 torch::autograd::impl::bump_version(tensor);
285 }
286 // We're not going to ever need this so let's remove references now
287 Py_CLEAR(self->dirty_tensors)do { PyObject *_py_tmp = ((PyObject*)(self->dirty_tensors)
); if (_py_tmp != __null) { (self->dirty_tensors) = __null
; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0)
;
288 return dirty_inputs;
289}
290
291static std::unordered_set<at::TensorImpl*> _parse_non_differentiable(THPFunction *self);
292
293// Given a Python tuple of raw output tensors (raw_output), set each of
294// the corresponding entries in a different Python tuple (outputs) with
295// these tensors wrapped with variables. We save the gradient function (self)
296// to the variable if the output requires grad.
297//
298// There is a considerable amount of complexity to handle if the operation
299// that produced these output tensors is inplace. A mapping of *input*
300// tensors to variables (t2var) is used to test if this occurred, and
301// the set of dirty tensors (dirty_inputs) is used to figure out what to
302// do in this case. After this method is run, t2var is extended with
303// mappings for output tensors as well.
304static void _wrap_outputs(const std::shared_ptr<PyNode>& cdata, THPFunction *self,
305 const variable_list &input_vars, PyObject *raw_output, PyObject *outputs, bool is_executable)
306{
307 auto cdata_if_executable = is_executable ? cdata : nullptr;
308 Py_ssize_t num_outputs = PyTuple_GET_SIZE(raw_output)(((PyVarObject*)(((PyTupleObject *)(raw_output))))->ob_size
)
;
309 if (is_executable) {
310 self->output_info.clear();
311 self->output_info.reserve(num_outputs);
312 }
313
314 auto non_differentiable = _parse_non_differentiable(self);
315 auto dirty_inputs = _mark_dirty(self);
316
317 std::vector<c10::optional<Variable>> raw_output_vars;
318 raw_output_vars.reserve(num_outputs);
319 for (const auto i : c10::irange(num_outputs)) {
320 PyObject* obj = PyTuple_GET_ITEM(raw_output, i)(((PyTupleObject *)(raw_output))->ob_item[i]);
321 // Only process tensors as outputs for autograd purposes.
322 if (THPVariable_Check(obj)) {
323 raw_output_vars.emplace_back(THPVariable_Unpack(obj));
324 } else {
325 raw_output_vars.emplace_back();
326 }
327 }
328
329 // Wrap only the tensor outputs.
330 auto wrapped_outputs = _wrap_outputs(input_vars, non_differentiable, dirty_inputs, raw_output_vars, cdata_if_executable);
331
332 for(const auto i : c10::irange(num_outputs)) {
333 PyObject* obj = PyTuple_GetItem(raw_output, i);
334 // Keep the non-tensor outputs as is.
335 if (!THPVariable_Check(obj)) {
336 if (is_executable) {
337 self->output_info.emplace_back();
338 }
339 Py_INCREF(obj)_Py_INCREF(((PyObject*)(obj)));
340 PyTuple_SetItem(outputs, i, obj);
341 } else {
342 if (is_executable) {
343 self->output_info.emplace_back(*wrapped_outputs[i]);
344 }
345 PyTuple_SetItem(outputs, i, THPVariable_Wrap(*wrapped_outputs[i]));
346 }
347 }
348}
349
350// Save any variables that requested by to_save
351static void _save_variables(const std::shared_ptr<PyNode>& cdata_ptr, THPFunction* self)
352{
353 if (!self->to_save) return;
354
355 THPFunction_assert(PyTuple_Check(self->to_save), "autograd internal "if (!(((((((PyObject*)(self->to_save))->ob_type))->tp_flags
& ((1UL << 26))) != 0))) { THPUtils_setError("autograd internal "
"error: to_save attribute is expected to be a tuple but is %s"
, ((((PyObject*)(self->to_save))->ob_type)->tp_name)
); throw python_error(); }
356 "error: to_save attribute is expected to be a tuple but is %s",if (!(((((((PyObject*)(self->to_save))->ob_type))->tp_flags
& ((1UL << 26))) != 0))) { THPUtils_setError("autograd internal "
"error: to_save attribute is expected to be a tuple but is %s"
, ((((PyObject*)(self->to_save))->ob_type)->tp_name)
); throw python_error(); }
357 THPUtils_typename(self->to_save))if (!(((((((PyObject*)(self->to_save))->ob_type))->tp_flags
& ((1UL << 26))) != 0))) { THPUtils_setError("autograd internal "
"error: to_save attribute is expected to be a tuple but is %s"
, ((((PyObject*)(self->to_save))->ob_type)->tp_name)
); throw python_error(); }
;
358 Py_ssize_t num_saved = PyTuple_GET_SIZE(self->to_save)(((PyVarObject*)(((PyTupleObject *)(self->to_save))))->
ob_size)
;
359 self->saved_variables.clear();
360 self->saved_variables.reserve(num_saved);
361 for(const auto i : c10::irange(num_saved)) {
362 PyObject *obj = PyTuple_GET_ITEM(self->to_save, i)(((PyTupleObject *)(self->to_save))->ob_item[i]);
363 if (obj == Py_None(&_Py_NoneStruct)) {
364 self->saved_variables.emplace_back();
365 continue;
366 } else if (THPVariable_Check(obj)) {
367 const auto& tensor = THPVariable_Unpack(obj);
368 bool is_output = tensor.grad_fn().get() == cdata_ptr.get();
369 self->saved_variables.emplace_back(tensor, is_output);
370 } else {
371 throw torch::TypeError(
372 "save_for_backward can only save variables, but argument %ld is of "
373 "type %s", i, Py_TYPE(obj)(((PyObject*)(obj))->ob_type)->tp_name);
374 }
375 }
376 // Free .to_save
377 Py_CLEAR(self->to_save)do { PyObject *_py_tmp = ((PyObject*)(self->to_save)); if (
_py_tmp != __null) { (self->to_save) = __null; _Py_DECREF(
((PyObject*)(_py_tmp))); } } while (0)
;
378}
379
380// Mark requires_grad = 0 on non-differentiable variables (as per non_differentiable)
381static std::unordered_set<at::TensorImpl*>
382_parse_non_differentiable(THPFunction *self)
383{
384 std::unordered_set<at::TensorImpl*> set;
385 if (!self->non_differentiable) return set;
386
387 THPFunction_assert(PyTuple_Check(self->non_differentiable), "autograd "if (!(((((((PyObject*)(self->non_differentiable))->ob_type
))->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError
("autograd " "internal error: non_differentiable attribute is expected to be a "
"tuple but is %s", ((((PyObject*)(self->non_differentiable
))->ob_type)->tp_name)); throw python_error(); }
388 "internal error: non_differentiable attribute is expected to be a "if (!(((((((PyObject*)(self->non_differentiable))->ob_type
))->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError
("autograd " "internal error: non_differentiable attribute is expected to be a "
"tuple but is %s", ((((PyObject*)(self->non_differentiable
))->ob_type)->tp_name)); throw python_error(); }
389 "tuple but is %s", THPUtils_typename(self->non_differentiable))if (!(((((((PyObject*)(self->non_differentiable))->ob_type
))->tp_flags & ((1UL << 26))) != 0))) { THPUtils_setError
("autograd " "internal error: non_differentiable attribute is expected to be a "
"tuple but is %s", ((((PyObject*)(self->non_differentiable
))->ob_type)->tp_name)); throw python_error(); }
;
390 Py_ssize_t num_nondiff = PyTuple_GET_SIZE(self->non_differentiable)(((PyVarObject*)(((PyTupleObject *)(self->non_differentiable
))))->ob_size)
;
391 set.reserve(num_nondiff);
392 for(const auto i : c10::irange(num_nondiff)) {
393 PyObject *t = PyTuple_GET_ITEM(self->non_differentiable, i)(((PyTupleObject *)(self->non_differentiable))->ob_item
[i])
;
394 THPFunction_assert(THPVariable_Check(t), "mark_non_differentiable "if (!(THPVariable_Check(t))) { THPUtils_setError("mark_non_differentiable "
"only accepts variable arguments, but got %s", ((((PyObject*
)(t))->ob_type)->tp_name)); throw python_error(); }
395 "only accepts variable arguments, but got %s", THPUtils_typename(t))if (!(THPVariable_Check(t))) { THPUtils_setError("mark_non_differentiable "
"only accepts variable arguments, but got %s", ((((PyObject*
)(t))->ob_type)->tp_name)); throw python_error(); }
;
396 set.insert(THPVariable_Unpack(t).unsafeGetTensorImpl());
397 }
398 Py_CLEAR(self->non_differentiable)do { PyObject *_py_tmp = ((PyObject*)(self->non_differentiable
)); if (_py_tmp != __null) { (self->non_differentiable) = __null
; _Py_DECREF(((PyObject*)(_py_tmp))); } } while (0)
;
399 return set;
400}
401
402struct UnpackedInput {
403 THPObjectPtr input_tuple;
404 variable_list input_vars;
405};
406
407struct InputFlags {
408 bool is_executable = false;
409 edge_list next_edges;
410 THPObjectPtr needs_input_grad;
411 std::vector<bool> is_variable_input;
412};
413
414template<bool enforce_variables>
415std::pair<UnpackedInput, InputFlags> unpack_input(PyObject *args) {
416 UnpackedInput unpacked;
417 InputFlags flags;
418
419 auto num_args = PyTuple_GET_SIZE(args)(((PyVarObject*)(((PyTupleObject *)(args))))->ob_size);
420 unpacked.input_tuple = PyTuple_New(num_args);
421 flags.needs_input_grad = PyTuple_New(num_args);
422 for(const auto i : c10::irange(num_args)) {
423 PyObject *arg = PyTuple_GET_ITEM(args, i)(((PyTupleObject *)(args))->ob_item[i]);
424
425 bool is_variable = THPVariable_Check(arg);
426 flags.is_variable_input.push_back(is_variable);
427 if (!is_variable) {
428 // TODO: remove this code path once Variable and Tensor are merged in Python
429 if (enforce_variables) {
430 THPUtils_setError("expected a Tensor argument, but got %s",
431 THPUtils_typename(arg)((((PyObject*)(arg))->ob_type)->tp_name));
432 throw python_error();
433 }
434 Py_INCREF(Py_False)_Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct)))
)
;
435 PyTuple_SET_ITEM(flags.needs_input_grad.get(), i, Py_False)PyTuple_SetItem(flags.needs_input_grad.get(), i, ((PyObject *
) &_Py_FalseStruct))
;
436 } else {
437 const auto& tensor = THPVariable_Unpack(arg);
438 unpacked.input_vars.push_back(tensor);
439 PyObject* needs_grad = tensor.requires_grad() ? Py_True((PyObject *) &_Py_TrueStruct) : Py_False((PyObject *) &_Py_FalseStruct);
440 Py_INCREF(needs_grad)_Py_INCREF(((PyObject*)(needs_grad)));
441 PyTuple_SET_ITEM(flags.needs_input_grad.get(), i, needs_grad)PyTuple_SetItem(flags.needs_input_grad.get(), i, needs_grad);
442 }
443 Py_INCREF(arg)_Py_INCREF(((PyObject*)(arg)));
444 PyTuple_SET_ITEM(unpacked.input_tuple.get(), i, arg)PyTuple_SetItem(unpacked.input_tuple.get(), i, arg);
445 }
446
447 flags.is_executable = GradMode::is_enabled() && any_variable_requires_grad(unpacked.input_vars);
448 flags.next_edges = (flags.is_executable ? collect_next_edges(unpacked.input_vars) : edge_list());
449 return std::make_pair(std::move(unpacked), std::move(flags));
450}
451
452static torch::jit::Node* _trace_pre_record(
453 PyObject* op_obj,
454 PyObject *input_objects,
455 const variable_list& input_vars) {
456 if (!jit::tracer::isTracing()) {
457 return nullptr;
458 }
459
460 // Save scalar args and the calling convention
461 auto num_args = PyTuple_GET_SIZE(input_objects)(((PyVarObject*)(((PyTupleObject *)(input_objects))))->ob_size
)
;
462 pyobj_list scalar_args;
463 std::string arg_types;
464 arg_types.reserve(num_args);
465 scalar_args.reserve(num_args);
466 for(const auto i : c10::irange(num_args)) {
467 PyObject *arg_object = PyTuple_GET_ITEM(input_objects, i)(((PyTupleObject *)(input_objects))->ob_item[i]);
468 if (THPVariable_Check(arg_object)) {
469 arg_types.push_back('d');
470 } else {
471 arg_types.push_back('c');
472 Py_INCREF(arg_object)_Py_INCREF(((PyObject*)(arg_object)));
473 scalar_args.emplace_back(arg_object);
474 }
475 }
476
477 Py_INCREF(op_obj)_Py_INCREF(((PyObject*)(op_obj)));
478 auto pyobj = THPObjectPtr(op_obj);
479 return jit::tracer::preRecordPythonTrace(
480 std::move(pyobj), arg_types, input_vars, std::move(scalar_args));
481}
482
483static void _trace_post_record(
484 torch::jit::Node* node,
485 PyObject* op_obj,
486 const variable_list& input_vars,
487 PyObject *output_objects,
488 bool is_inplace,
489 bool unpack_output) {
490 if (!jit::tracer::isTracing()) {
491 return;
492 }
493
494 node->i_(jit::attr::inplace, is_inplace);
495
496 // Isolate C variable ptrs in a vector
497 int num_outputs = PyTuple_GET_SIZE(output_objects)(((PyVarObject*)(((PyTupleObject *)(output_objects))))->ob_size
)
;
498 auto graph = node->owningGraph();
499 node->addOutput();
500 if (!unpack_output) {
501 std::vector<TypePtr> tuple_values(num_outputs, TensorType::get());
502 TypePtr tuple_type = TupleType::create(std::move(tuple_values));
503 node->output()->setType(tuple_type);
504 auto unpacked = graph->createTupleUnpack(node->output())->insertAfter(node);
505 node = unpacked;
506 }
507 for (const auto i : c10::irange(num_outputs)) {
508 PyObject* obj = PyTuple_GET_ITEM(output_objects, i)(((PyTupleObject *)(output_objects))->ob_item[i]);
509 if (THPVariable_Check(obj)) {
510 Value* value = node->outputs()[i];
511 const auto& tensor = THPVariable_Unpack(obj);
512 if (tensor.defined()) {
513 value->inferTypeFrom(tensor);
514 jit::tracer::setValueTrace(tensor, value);
515 }
516 }
517 }
518}
519
520PyObject* process_outputs(PyObject *op_obj, const std::shared_ptr<PyNode>& cdata,
521 THPFunction* grad_fn, const UnpackedInput& unpacked,
522 PyObject *inputs, THPObjectPtr&& raw_output, bool is_executable,
523 torch::jit::Node* node) {
524 bool unpack_output = ensure_tuple(raw_output);
525
526 auto num_outputs = PyTuple_GET_SIZE(raw_output.get())(((PyVarObject*)(((PyTupleObject *)(raw_output.get()))))->
ob_size)
;
527
528 THPObjectPtr outputs(PyTuple_New(num_outputs));
529 if (!outputs) throw python_error();
530
531 cdata->clear_input_metadata();
532
533 // Record type, device, and size information about inputs
534 if (is_executable) {
535 grad_fn->input_info.clear();
536 grad_fn->input_info.reserve(unpacked.input_vars.size());
537 for (auto& var : unpacked.input_vars) {
538 grad_fn->input_info.emplace_back(var);
539 }
540 }
541
542 bool is_inplace = static_cast<bool>(grad_fn->dirty_tensors);
543 _wrap_outputs(cdata, grad_fn, unpacked.input_vars, raw_output, outputs, is_executable);
544 _trace_post_record(node, op_obj, unpacked.input_vars, outputs, is_inplace, unpack_output);
545 if (is_executable) {
546 _save_variables(cdata, grad_fn);
547 } else {
548 // Remove unnecessary attributes
549 Py_XDECREF(grad_fn->to_save)_Py_XDECREF(((PyObject*)(grad_fn->to_save)));
550 grad_fn->to_save = nullptr;
551 Py_XDECREF(grad_fn->non_differentiable)_Py_XDECREF(((PyObject*)(grad_fn->non_differentiable)));
552 grad_fn->non_differentiable = nullptr;
553 }
554
555 // Unpack the output, unless .forward() returned a tuple
556 if (unpack_output) {
557 PyObject *output = PyTuple_GET_ITEM(outputs.get(), 0)(((PyTupleObject *)(outputs.get()))->ob_item[0]);
558 Py_INCREF(output)_Py_INCREF(((PyObject*)(output)));
559 return output;
560 }
561
562 return outputs.release();
563}
564
565PyObject* THPFunction_name(PyObject *self, PyObject* noargs) {
566 HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try {
567 auto cdata = ((THPFunction*)self)->cdata.lock();
568 TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
569 "Attribute 'name' is invalid for this instance of _C._FunctionBase. "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
570 "Accessing this attribute directly on an instance of autograd.Function is a legacy "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
571 "access pattern that is no longer supported. For examples on how to use new-style "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
572 "autograd functions, see "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
573 "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function ")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(573), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'name' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
;
574 return THPUtils_packString(cdata->name());
575 END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw
; } } catch (python_error & e) { e.restore(); return nullptr
; } catch (const c10::IndexError& e) { auto msg = torch::
get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace
(); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg(
msg)); return nullptr; } catch (const c10::ValueError& e)
{ auto msg = torch::get_cpp_stacktraces_enabled() ? e.what()
: e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError
, torch::processErrorMsg(msg)); return nullptr; } catch (torch
::PyTorchError & e) { auto msg = torch::processErrorMsg(e
.what()); PyErr_SetString(e.python_type(), msg); return nullptr
; } catch (const std::exception& e) { auto msg = torch::processErrorMsg
(e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr
; }
576}
577
578PyObject *THPFunction_apply(PyObject *cls, PyObject *inputs)
579{
580 HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try {
581 RECORD_FUNCTION(at::RecordFunction guard(at::RecordScope::FUNCTION); if (guard
.isActive()) { if (guard.needsInputs()) { guard.before(((PyTypeObject
*)cls)->tp_name, std::vector<c10::IValue>(), at::sequence_number
::peek()); } else { guard.before(((PyTypeObject*)cls)->tp_name
, at::sequence_number::peek()); } }
582 ((PyTypeObject*)cls)->tp_name,at::RecordFunction guard(at::RecordScope::FUNCTION); if (guard
.isActive()) { if (guard.needsInputs()) { guard.before(((PyTypeObject
*)cls)->tp_name, std::vector<c10::IValue>(), at::sequence_number
::peek()); } else { guard.before(((PyTypeObject*)cls)->tp_name
, at::sequence_number::peek()); } }
583 std::vector<c10::IValue>(),at::RecordFunction guard(at::RecordScope::FUNCTION); if (guard
.isActive()) { if (guard.needsInputs()) { guard.before(((PyTypeObject
*)cls)->tp_name, std::vector<c10::IValue>(), at::sequence_number
::peek()); } else { guard.before(((PyTypeObject*)cls)->tp_name
, at::sequence_number::peek()); } }
584 at::sequence_number::peek())at::RecordFunction guard(at::RecordScope::FUNCTION); if (guard
.isActive()) { if (guard.needsInputs()) { guard.before(((PyTypeObject
*)cls)->tp_name, std::vector<c10::IValue>(), at::sequence_number
::peek()); } else { guard.before(((PyTypeObject*)cls)->tp_name
, at::sequence_number::peek()); } }
;
585
586 THPObjectPtr backward_cls(PyObject_GetAttrString(cls, "_backward_cls"));
587 if (!backward_cls) return nullptr;
588 THPObjectPtr ctx_obj(PyObject_CallFunctionObjArgs(backward_cls, nullptr));
589 if (!ctx_obj) return nullptr;
590 THPFunction* ctx = (THPFunction*)ctx_obj.get();
591
592 auto cdata = std::shared_ptr<PyNode>(new PyNode(std::move(ctx_obj)), deleteNode);
593 ctx->cdata = cdata;
594
595 // Prepare inputs and allocate context (grad fn)
596 auto info_pair = unpack_input<false>(inputs);
597 UnpackedInput& unpacked_input = info_pair.first;
598 InputFlags& input_info = info_pair.second;
599
600 // Record input nodes if tracing
601 auto* node = _trace_pre_record(cls, inputs, unpacked_input.input_vars);
602
603 // Initialize backward function (and ctx)
604 bool is_executable = input_info.is_executable;
605 cdata->set_next_edges(std::move(input_info.next_edges));
606 ctx->needs_input_grad = input_info.needs_input_grad.release();
607 ctx->is_variable_input = std::move(input_info.is_variable_input);
608
609 // Prepend ctx to input_tuple, in preparation for static method call
610 auto num_args = PyTuple_GET_SIZE(inputs)(((PyVarObject*)(((PyTupleObject *)(inputs))))->ob_size);
611 THPObjectPtr ctx_input_tuple(PyTuple_New(num_args + 1));
612 if (!ctx_input_tuple) return nullptr;
613 Py_INCREF(ctx)_Py_INCREF(((PyObject*)(ctx)));
614 PyTuple_SET_ITEM(ctx_input_tuple.get(), 0, (PyObject*)ctx)PyTuple_SetItem(ctx_input_tuple.get(), 0, (PyObject*)ctx);
615 for (const auto i : c10::irange(num_args)) {
616 PyObject *arg = PyTuple_GET_ITEM(unpacked_input.input_tuple.get(), i)(((PyTupleObject *)(unpacked_input.input_tuple.get()))->ob_item
[i])
;
617 Py_INCREF(arg)_Py_INCREF(((PyObject*)(arg)));
618 PyTuple_SET_ITEM(ctx_input_tuple.get(), i + 1, arg)PyTuple_SetItem(ctx_input_tuple.get(), i + 1, arg);
619 }
620
621 // Call forward
622 THPObjectPtr tensor_outputs;
623 {
624 AutoGradMode grad_mode(false);
625 THPObjectPtr forward_fn(PyObject_GetAttrString(cls, "forward"));
626 if (!forward_fn) return nullptr;
627 tensor_outputs = PyObject_CallObject(forward_fn, ctx_input_tuple);
628 if (!tensor_outputs) return nullptr;
629 }
630
631 return process_outputs(cls, cdata, ctx, unpacked_input, inputs, std::move(tensor_outputs),
632 is_executable, node);
633 END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw
; } } catch (python_error & e) { e.restore(); return nullptr
; } catch (const c10::IndexError& e) { auto msg = torch::
get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace
(); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg(
msg)); return nullptr; } catch (const c10::ValueError& e)
{ auto msg = torch::get_cpp_stacktraces_enabled() ? e.what()
: e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError
, torch::processErrorMsg(msg)); return nullptr; } catch (torch
::PyTorchError & e) { auto msg = torch::processErrorMsg(e
.what()); PyErr_SetString(e.python_type(), msg); return nullptr
; } catch (const std::exception& e) { auto msg = torch::processErrorMsg
(e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr
; }
634}
635
636
637////////////////////////////////////////////////////////////////////////////////
638// Other methods / attributes
639////////////////////////////////////////////////////////////////////////////////
640
641PyObject* THPFunction__register_hook_dict(PyObject *_self, PyObject *_var)
642{
643 HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try {
644 THPUtils_assert(THPVariable_Check(_var), "_register_hook_dict expected a Tensor")if ((__builtin_expect((!(THPVariable_Check(_var))), (0)))) { THPUtils_setError
("_register_hook_dict expected a Tensor"); return nullptr; }
;
645 THPVariable* var = reinterpret_cast<THPVariable*>(_var);
646 const auto& tensor = THPVariable_Unpack(var);
647 std::unique_ptr<FunctionPreHook> hook(new PyFunctionPreHook(
648 var->backward_hooks, tensor.output_nr()));
649 auto self = (THPFunction*)_self;
650 auto cdata = self->cdata.lock();
651 TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
652 "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
653 "Accessing this attribute directly on an instance of autograd.Function is a legacy "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
654 "access pattern that is no longer supported. For examples on how to use new-style "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
655 "autograd functions, see "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
656 "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function ")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(656), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute '_register_hook_dict' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
;
657 cdata->add_pre_hook(std::move(hook));
658 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
659 END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw
; } } catch (python_error & e) { e.restore(); return nullptr
; } catch (const c10::IndexError& e) { auto msg = torch::
get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace
(); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg(
msg)); return nullptr; } catch (const c10::ValueError& e)
{ auto msg = torch::get_cpp_stacktraces_enabled() ? e.what()
: e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError
, torch::processErrorMsg(msg)); return nullptr; } catch (torch
::PyTorchError & e) { auto msg = torch::processErrorMsg(e
.what()); PyErr_SetString(e.python_type(), msg); return nullptr
; } catch (const std::exception& e) { auto msg = torch::processErrorMsg
(e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr
; }
660}
661
662PyObject* THPFunction_register_hook(PyObject *_self, PyObject *hook)
663{
664 HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try {
665 auto self= (THPFunction*)_self;
666 auto cdata = self->cdata.lock();
667 TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
668 "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
669 "Accessing this attribute directly on an instance of autograd.Function is a legacy "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
670 "access pattern that is no longer supported. For examples on how to use new-style "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
671 "autograd functions, see "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
672 "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function ")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(672), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'register_hook' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
;
673 return torch::autograd::registerFunctionHook(*cdata, hook);
674 END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw
; } } catch (python_error & e) { e.restore(); return nullptr
; } catch (const c10::IndexError& e) { auto msg = torch::
get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace
(); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg(
msg)); return nullptr; } catch (const c10::ValueError& e)
{ auto msg = torch::get_cpp_stacktraces_enabled() ? e.what()
: e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError
, torch::processErrorMsg(msg)); return nullptr; } catch (torch
::PyTorchError & e) { auto msg = torch::processErrorMsg(e
.what()); PyErr_SetString(e.python_type(), msg); return nullptr
; } catch (const std::exception& e) { auto msg = torch::processErrorMsg
(e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr
; }
675}
676
677int THPFunction_set_materialize_grads(THPFunction *self, PyObject *value, void *unused)
678{
679 HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try {
680 if (!PyBool_Check(value)((((PyObject*)(value))->ob_type) == &PyBool_Type)) {
681 THPUtils_invalidArguments(value, nullptr, "set_materialize_grads", 1, "(bool)");
682 return -1;
683 }
684 self->materialize_grads = (value == Py_True((PyObject *) &_Py_TrueStruct));
685 return 0;
686 END_HANDLE_TH_ERRORS_RET(-1)} catch(...) { __enforce_warning_buffer.set_in_exception(); throw
; } } catch (python_error & e) { e.restore(); return -1; }
catch (const c10::IndexError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_IndexError
, torch::processErrorMsg(msg)); return -1; } catch (const c10
::ValueError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError
, torch::processErrorMsg(msg)); return -1; } catch (const c10
::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError
, torch::processErrorMsg(msg)); return -1; } catch (const c10
::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError
, torch::processErrorMsg(msg)); return -1; } catch (const c10
::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError
, torch::processErrorMsg(msg)); return -1; } catch (torch::PyTorchError
& e) { auto msg = torch::processErrorMsg(e.what()); PyErr_SetString
(e.python_type(), msg); return -1; } catch (const std::exception
& e) { auto msg = torch::processErrorMsg(e.what()); PyErr_SetString
(PyExc_RuntimeError, msg); return -1; }
687}
688
689static PyObject *unpack_saved_variables(
690 THPFunction *self,
691 const std::function<PyObject*(const Variable&)>& unpack_fn)
692{
693 THPUtils_assert(!self->has_freed_buffers, ERR_BACKWARD_TWICE)if ((__builtin_expect((!(!self->has_freed_buffers)), (0)))
) { THPUtils_setError(ERR_BACKWARD_TWICE); return nullptr; }
;
2
Assuming field 'has_freed_buffers' is 0
3
Taking false branch
694 auto& saved_variables = self->saved_variables;
695 if (saved_variables.empty())
4
Assuming the condition is false
5
Taking false branch
696 return PyTuple_New(0);
697
698 int num_saved = saved_variables.size();
699 THPObjectPtr saved(PyTuple_New(num_saved));
6
Calling 'PyTuple_New'
8
Returning from 'PyTuple_New'
12
PyObject ownership leak with reference count of 1
700 if (!saved)
9
Assuming the condition is false
10
Taking false branch
701 return nullptr;
702 auto saved_for = self->cdata.lock();
703 // This is really a true assert, because we've already tested for the
704 // self->has_freed_buffers case at the beginning of this function:
705 // buffers are freed when PyNode dies; if the buffers are not freed,
706 // PyNode must be live. (Note that the buffers could be freed
707 // even though the PyNode is live, but that doesn't matter here
708 // because we will never hit this line of code if the buffers are freed--
709 // and in any case saved_for will be non-NULL.)
710 TORCH_INTERNAL_ASSERT(saved_for)if ((__builtin_expect(static_cast<bool>(!(saved_for)), 0
))) { ::c10::detail::torchInternalAssertFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(710), "saved_for" "INTERNAL ASSERT FAILED at "
"\"../torch/csrc/autograd/python_function.cpp\"" ":" "710" ", please report a bug to PyTorch. "
, c10::str()); }
;
11
Taking true branch
711 for(const auto i : c10::irange(num_saved)) {
712 auto unpacked_var = saved_variables[i].unpack(saved_for);
713 THPObjectPtr value;
714 if (!unpacked_var.defined()) {
715 Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct))));
716 value = Py_None(&_Py_NoneStruct);
717 } else {
718 value = unpack_fn(unpacked_var);
719 }
720 PyTuple_SET_ITEM(saved.get(), i, value.release())PyTuple_SetItem(saved.get(), i, value.release());
721 }
722 return saved.release();
723}
724
725PyObject *THPFunction_saved_tensors(THPFunction *self, void *_unused)
726{
727 HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try {
728 return unpack_saved_variables(self, [](const Variable& var) {
1
Calling 'unpack_saved_variables'
729 return THPVariable_Wrap(var);
730 });
731 END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw
; } } catch (python_error & e) { e.restore(); return nullptr
; } catch (const c10::IndexError& e) { auto msg = torch::
get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace
(); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg(
msg)); return nullptr; } catch (const c10::ValueError& e)
{ auto msg = torch::get_cpp_stacktraces_enabled() ? e.what()
: e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError
, torch::processErrorMsg(msg)); return nullptr; } catch (torch
::PyTorchError & e) { auto msg = torch::processErrorMsg(e
.what()); PyErr_SetString(e.python_type(), msg); return nullptr
; } catch (const std::exception& e) { auto msg = torch::processErrorMsg
(e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr
; }
732}
733
734PyObject *THPFunction_saved_variables(THPFunction *self, void *_unused)
735{
736 HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try {
737 auto r = PyErr_WarnEx(PyExc_DeprecationWarning,
738 "'saved_variables' is deprecated; use 'saved_tensors'", 0);
739 if (r != 0) throw python_error();
740 return unpack_saved_variables(self, [](const Variable& var) {
741 return THPVariable_Wrap(var);
742 });
743 END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw
; } } catch (python_error & e) { e.restore(); return nullptr
; } catch (const c10::IndexError& e) { auto msg = torch::
get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace
(); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg(
msg)); return nullptr; } catch (const c10::ValueError& e)
{ auto msg = torch::get_cpp_stacktraces_enabled() ? e.what()
: e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError
, torch::processErrorMsg(msg)); return nullptr; } catch (torch
::PyTorchError & e) { auto msg = torch::processErrorMsg(e
.what()); PyErr_SetString(e.python_type(), msg); return nullptr
; } catch (const std::exception& e) { auto msg = torch::processErrorMsg
(e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr
; }
744}
745
746PyObject *THPFunction_next_functions(THPFunction *self, void *_unused)
747{
748 HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try {
749 auto cdata = self->cdata.lock();
750 TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
751 "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
752 "Accessing this attribute directly on an instance of autograd.Function is a legacy "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
753 "access pattern that is no longer supported. For examples on how to use new-style "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
754 "autograd functions, see "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
755 "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function ")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(755), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "Attribute 'next_functions' is invalid for this instance of _C._FunctionBase. "
"Accessing this attribute directly on an instance of autograd.Function is a legacy "
"access pattern that is no longer supported. For examples on how to use new-style "
"autograd functions, see " "https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function "
))); }
;
756 const auto num_outputs = cdata->num_outputs();
757 THPObjectPtr result(PyTuple_New(num_outputs));
758 if (!result)
759 return nullptr;
760 for (const auto i : c10::irange(num_outputs)) {
761 THPObjectPtr fn_tuple(PyTuple_New(2));
762 if (!fn_tuple) return nullptr;
763 const auto& edge = cdata->next_edge(i);
764 PyObject* fn = functionToPyObject(edge.function);
765 if (!fn) return nullptr;
766 PyTuple_SET_ITEM(fn_tuple.get(), 0, fn)PyTuple_SetItem(fn_tuple.get(), 0, fn);
767 PyTuple_SET_ITEM(fn_tuple.get(), 1, THPUtils_packInt64(edge.input_nr))PyTuple_SetItem(fn_tuple.get(), 1, THPUtils_packInt64(edge.input_nr
))
;
768 PyTuple_SET_ITEM(result.get(), i, fn_tuple.release())PyTuple_SetItem(result.get(), i, fn_tuple.release());
769 }
770 return result.release();
771 END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw
; } } catch (python_error & e) { e.restore(); return nullptr
; } catch (const c10::IndexError& e) { auto msg = torch::
get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace
(); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg(
msg)); return nullptr; } catch (const c10::ValueError& e)
{ auto msg = torch::get_cpp_stacktraces_enabled() ? e.what()
: e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError
, torch::processErrorMsg(msg)); return nullptr; } catch (torch
::PyTorchError & e) { auto msg = torch::processErrorMsg(e
.what()); PyErr_SetString(e.python_type(), msg); return nullptr
; } catch (const std::exception& e) { auto msg = torch::processErrorMsg
(e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr
; }
772}
773
774PyObject *THPFunction_metadata(THPFunction *self, void *_unused)
775{
776 HANDLE_TH_ERRORStry { torch::PyWarningHandler __enforce_warning_buffer; try {
777 auto cdata = self->cdata.lock();
778 // The correct way to solve this problem is to stop exposing grad_fn
779 // of PyFunctions as THPFunction; instead, we should use THPCppFunction
780 // like everyone else. But this is a BC-breaking change as it would
781 // mean that you no longer get the property that grad_fn is a subclass
782 // of the autograd function class that you defined in the custom case,
783 // so I didn't fix it here.
784 TORCH_CHECK(cdata,if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function "
"but the underlying PyNode has already been deallocated. The most likely "
"reason this occurred is because you assigned x.grad_fn to a local variable "
"and then let the original variable get deallocated. Don't do that! If "
"you really have no way of restructuring your code so this is the case, "
"please file an issue reporting that you are affected by this."
))); }
785 "You attempted to access the anomaly metadata of a custom autograd function "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function "
"but the underlying PyNode has already been deallocated. The most likely "
"reason this occurred is because you assigned x.grad_fn to a local variable "
"and then let the original variable get deallocated. Don't do that! If "
"you really have no way of restructuring your code so this is the case, "
"please file an issue reporting that you are affected by this."
))); }
786 "but the underlying PyNode has already been deallocated. The most likely "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function "
"but the underlying PyNode has already been deallocated. The most likely "
"reason this occurred is because you assigned x.grad_fn to a local variable "
"and then let the original variable get deallocated. Don't do that! If "
"you really have no way of restructuring your code so this is the case, "
"please file an issue reporting that you are affected by this."
))); }
787 "reason this occurred is because you assigned x.grad_fn to a local variable "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function "
"but the underlying PyNode has already been deallocated. The most likely "
"reason this occurred is because you assigned x.grad_fn to a local variable "
"and then let the original variable get deallocated. Don't do that! If "
"you really have no way of restructuring your code so this is the case, "
"please file an issue reporting that you are affected by this."
))); }
788 "and then let the original variable get deallocated. Don't do that! If "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function "
"but the underlying PyNode has already been deallocated. The most likely "
"reason this occurred is because you assigned x.grad_fn to a local variable "
"and then let the original variable get deallocated. Don't do that! If "
"you really have no way of restructuring your code so this is the case, "
"please file an issue reporting that you are affected by this."
))); }
789 "you really have no way of restructuring your code so this is the case, "if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function "
"but the underlying PyNode has already been deallocated. The most likely "
"reason this occurred is because you assigned x.grad_fn to a local variable "
"and then let the original variable get deallocated. Don't do that! If "
"you really have no way of restructuring your code so this is the case, "
"please file an issue reporting that you are affected by this."
))); }
790 "please file an issue reporting that you are affected by this.")if ((__builtin_expect(static_cast<bool>(!(cdata)), 0)))
{ ::c10::detail::torchCheckFail( __func__, "../torch/csrc/autograd/python_function.cpp"
, static_cast<uint32_t>(790), (::c10::detail::torchCheckMsgImpl
( "Expected " "cdata" " to be true, but got false. " "(Could this error message be improved? If so, "
"please report an enhancement request to PyTorch.)", "You attempted to access the anomaly metadata of a custom autograd function "
"but the underlying PyNode has already been deallocated. The most likely "
"reason this occurred is because you assigned x.grad_fn to a local variable "
"and then let the original variable get deallocated. Don't do that! If "
"you really have no way of restructuring your code so this is the case, "
"please file an issue reporting that you are affected by this."
))); }
;
791 auto metadata = static_cast<PyAnomalyMetadata*>(cdata->metadata())->dict();
792
793 Py_INCREF(metadata)_Py_INCREF(((PyObject*)(metadata)));
794 return metadata;
795 END_HANDLE_TH_ERRORS} catch(...) { __enforce_warning_buffer.set_in_exception(); throw
; } } catch (python_error & e) { e.restore(); return nullptr
; } catch (const c10::IndexError& e) { auto msg = torch::
get_cpp_stacktraces_enabled() ? e.what() : e.what_without_backtrace
(); PyErr_SetString(PyExc_IndexError, torch::processErrorMsg(
msg)); return nullptr; } catch (const c10::ValueError& e)
{ auto msg = torch::get_cpp_stacktraces_enabled() ? e.what()
: e.what_without_backtrace(); PyErr_SetString(PyExc_ValueError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::TypeError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_TypeError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::NotImplementedError& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_NotImplementedError
, torch::processErrorMsg(msg)); return nullptr; } catch (const
c10::Error& e) { auto msg = torch::get_cpp_stacktraces_enabled
() ? e.what() : e.what_without_backtrace(); PyErr_SetString(PyExc_RuntimeError
, torch::processErrorMsg(msg)); return nullptr; } catch (torch
::PyTorchError & e) { auto msg = torch::processErrorMsg(e
.what()); PyErr_SetString(e.python_type(), msg); return nullptr
; } catch (const std::exception& e) { auto msg = torch::processErrorMsg
(e.what()); PyErr_SetString(PyExc_RuntimeError, msg); return nullptr
; }
796}
797
798typedef PyObject *(*getter)(PyObject *, void *);
799typedef int (*setter)(PyObject *, PyObject *, void *);
800
801namespace {
802
803template<PyObject* THPFunction::*ptr>
804PyObject* getObject(PyObject* obj, void* _unused) {
805 auto self = (THPFunction*)obj;
806 PyObject* value = self->*ptr;
807 if (!value) {
808 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
809 }
810 Py_INCREF(value)_Py_INCREF(((PyObject*)(value)));
811 return value;
812}
813
814template<PyObject* THPFunction::*ptr>
815int setObject(PyObject* obj, PyObject* value, void* _unused) {
816 auto self = (THPFunction*)obj;
817 if (value == Py_None(&_Py_NoneStruct)) {
818 value = nullptr;
819 }
820 Py_XDECREF((self->*ptr))_Py_XDECREF(((PyObject*)((self->*ptr))));
821 Py_XINCREF(value)_Py_XINCREF(((PyObject*)(value)));
822 self->*ptr = value;
823 return 0;
824}
825
826template<typename M, M THPFunction::*ptr, PyObject* (*Convert)(long)>
827PyObject* getMember(PyObject* obj, void* _unused) {
828 auto self = (THPFunction*)obj;
829 return Convert(self->*ptr);
830}
831
832template<typename M, M autograd::Node::*ptr, PyObject* (*Convert)(long)>
833PyObject* getImplMember(PyObject* obj, void* _unused) {
834 auto self = (THPFunction*)obj;
835 return Convert(self->cdata.*ptr);
836}
837
838PyObject* getRequiresGrad(PyObject* obj, void* _unused) {
839 Py_RETURN_TRUEreturn _Py_INCREF(((PyObject*)(((PyObject *) &_Py_TrueStruct
)))), ((PyObject *) &_Py_TrueStruct)
;
840}
841
842}
843
844// NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-non-const-global-variables)
845static struct PyGetSetDef THPFunction_properties[] = {
846 {"saved_tensors", (getter)THPFunction_saved_tensors, nullptr, nullptr, nullptr},
847 {"saved_variables", (getter)THPFunction_saved_variables, nullptr, nullptr, nullptr},
848 {"next_functions", (getter)THPFunction_next_functions, nullptr, nullptr, nullptr},
849 {"to_save", &getObject<&THPFunction::to_save>, &setObject<&THPFunction::to_save>, nullptr, nullptr},
850 {"non_differentiable", &getObject<&THPFunction::non_differentiable>, &setObject<&THPFunction::non_differentiable>, nullptr, nullptr},
851 {"dirty_tensors", &getObject<&THPFunction::dirty_tensors>, &setObject<&THPFunction::dirty_tensors>, nullptr, nullptr},
852 {"needs_input_grad", &getObject<&THPFunction::needs_input_grad>, nullptr, nullptr, nullptr},
853 {"requires_grad", getRequiresGrad, nullptr, nullptr, nullptr},
854 {"metadata", (getter)THPFunction_metadata, nullptr, nullptr, nullptr},
855 {"materialize_grads", nullptr, (setter)THPFunction_set_materialize_grads, nullptr, nullptr},
856 {nullptr}
857};
858
859// NOLINTNEXTLINE(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays,cppcoreguidelines-avoid-non-const-global-variables)
860static struct PyMethodDef THPFunction_methods[] = {
861 {(char*)"name", THPFunction_name, METH_NOARGS0x0004, nullptr},
862 {(char*)"apply", THPFunction_apply, METH_CLASS0x0010 | METH_VARARGS0x0001, nullptr},
863 {(char*)"_register_hook_dict", THPFunction__register_hook_dict, METH_O0x0008, nullptr},
864 {(char*)"register_hook", THPFunction_register_hook, METH_O0x0008, nullptr},
865 {nullptr}
866};
867
868// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
869PyTypeObject THPFunctionType = {
870 PyVarObject_HEAD_INIT(nullptr, 0){ { 1, nullptr }, 0 },
871 "torch._C._FunctionBase", /* tp_name */
872 sizeof(THPFunction), /* tp_basicsize */
873 0, /* tp_itemsize */
874 (destructor)THPFunction_dealloc, /* tp_dealloc */
875 // NOLINTNEXTLINE(modernize-use-nullptr)
876 0, /* tp_vectorcall_offset */
877 nullptr, /* tp_getattr */
878 nullptr, /* tp_setattr */
879 nullptr, /* tp_reserved */
880 nullptr, /* tp_repr */
881 nullptr, /* tp_as_number */
882 nullptr, /* tp_as_sequence */
883 nullptr, /* tp_as_mapping */
884 nullptr, /* tp_hash */
885 nullptr, /* tp_call */
886 nullptr, /* tp_str */
887 nullptr, /* tp_getattro */
888 nullptr, /* tp_setattro */
889 nullptr, /* tp_as_buffer */
890 Py_TPFLAGS_DEFAULT( 0 | (1UL << 18) | 0) | Py_TPFLAGS_BASETYPE(1UL << 10) | Py_TPFLAGS_HAVE_GC(1UL << 14), /* tp_flags */
891 nullptr, /* tp_doc */
892 (traverseproc)THPFunction_traverse, /* tp_traverse */
893 (inquiry)THPFunction_clear, /* tp_clear */
894 nullptr, /* tp_richcompare */
895 0, /* tp_weaklistoffset */
896 nullptr, /* tp_iter */
897 nullptr, /* tp_iternext */
898 THPFunction_methods, /* tp_methods */
899 nullptr, /* tp_members */
900 THPFunction_properties, /* tp_getset */
901 nullptr, /* tp_base */
902 nullptr, /* tp_dict */
903 nullptr, /* tp_descr_get */
904 nullptr, /* tp_descr_set */
905 0, /* tp_dictoffset */
906 nullptr, /* tp_init */
907 nullptr, /* tp_alloc */
908 THPFunction_new /* tp_new */
909};
910
911bool THPFunction_initModule(PyObject *module)
912{
913 if (PyType_Ready(&THPFunctionType) < 0)
914 return false;
915 Py_INCREF(&THPFunctionType)_Py_INCREF(((PyObject*)(&THPFunctionType)));
916 PyModule_AddObject(module, "_FunctionBase", (PyObject *)&THPFunctionType);
917 return true;
918}

/opt/pyrefcon/lib/pyrefcon/models/models/PyTuple_New.model

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