You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: doc/sphinx/source/parsing_arguments.rst
+48-4
Original file line number
Diff line number
Diff line change
@@ -62,8 +62,11 @@ There is no parsing required here, a single ``PyObject`` is expected:
62
62
) {
63
63
PyObject *ret = NULL;
64
64
assert(arg);
65
-
/* Treat arg as a borrowed reference. */
66
-
Py_INCREF(arg);
65
+
/* arg as a borrowed reference and the general rule is that you Py_INCREF them
66
+
* whilst you have an interest in them. We do _not_ do that here for reasons
67
+
* explained below.
68
+
*/
69
+
// Py_INCREF(arg);
67
70
68
71
/* Your code here...*/
69
72
@@ -76,8 +79,9 @@ There is no parsing required here, a single ``PyObject`` is expected:
76
79
Py_XDECREF(ret);
77
80
ret = NULL;
78
81
finally:
79
-
/* Treat arg as a borrowed reference. */
80
-
Py_DECREF(arg);
82
+
/* If we were to treat arg as a borrowed reference and had Py_INCREF'd above we
83
+
* should do this. See below. */
84
+
// Py_DECREF(arg);
81
85
return ret;
82
86
}
83
87
@@ -94,6 +98,46 @@ This function can be added to the module with the ``METH_O`` flag:
94
98
{NULL, NULL, 0, NULL} /* Sentinel */
95
99
};
96
100
101
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
102
+
Arguments as Borrowed References
103
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
104
+
105
+
There is some subtlety here as indicated by the comments. ``*arg`` is not our reference, it is a borrowed reference so why don't we increment it at the beginning of this function and decrement it at the end? After all we are trying to protect against calling into some malicious/badly written code that could hurt us. For example:
/* arg potentially could have had a ref count of 0 and been deallocated. */
115
+
/* ... */
116
+
/* So now doing something with arg could be undefined. */
117
+
}
118
+
119
+
A solution would be, since ``arg`` is a 'borrowed' reference and borrowed references should always be incremented whilst in use and decremented when done with. This would suggest the following:
/* arg can not have a ref count of 0 so is safe to use. */
131
+
/* Use arg to your hearts content... */
132
+
/* Do a matching decref. */
133
+
Py_DECREF(arg);
134
+
/* But now arg could have had a ref count of 0 so is unsafe to use by the caller. */
135
+
}
136
+
137
+
But now we have just pushed the burden onto our caller. They created ``arg`` and passed it to us in good faith and whilst we have protected ourselves have not protected the caller and they can fail unexpectedly. So it is best to fail fast, an near the error site, that dastardly ``call_malicious_code_that_decrefs_by_one_this_argument()``.
138
+
139
+
Side note: Of course this does not protect you from malicious/badly written code that decrements by more than one :-)
0 commit comments