Hi Jelmer,

On Sep 19, 2011, at 11:22 PM, Jelmer Vernooij wrote:

>> client.c:318 client_set_notify_funct() where notify_baton2 has
>> inconsistent
>> refcounting between the if-clause and else-clause. When you go through the
>> if-clause, notify_baton2 steals a reference to Py_None, which is going
>> to get
>> decref'd in client_dealloc(). The Py_XDECREF there does not protect
>> you from
>> the extra decref of Py_None! You can see that if you go through the
>> else-clause, func will get incref'd, but if you go through the
>> if-clause, you
>> actually leak func! Suggestion: incref notify_baton2 instead of func.
>I don't follow - further down in that function we Py_INCREF func, so we always 
>increment the reference count of func if we assign it to notify_baton2.

Oh, I see it now.  Right, Py_None will get incref'd by virtue of it being
stored in func.  It's a little confusing the way it's written, but agreed that
it's safe.

>> * client.c:256: py_cancel_check should be incref'd?
>
>It's a C function, I don't see why it could go away.

Right (hence the question mark).  Probably, technically more correct to hold
an explicit reference to it, but agreed that it's likely safe.

>> * client.c, multiple locations: PyArg_Parse* does not incref 'O'
>> arguments, so
>> be careful about calling back into Python with any such parsed object. You
>> need to ensure your library increfs such objects before a potential call
>> back into Python, and then decrefs it when you're done with the Python
>> call. I haven't audited all the places this happens, so this could be a
>> false alarm (i.e. you don't call back into Python).
>I'm not aware of any places where we do that in client.c.

Cool.

Thanks for closing bug 632225.  One more Python 2.7 blocker down!  But of
course, I couldn't stop now, so here are a few other minor things that jumped
out at me.

(Aside: FWIW, I've always said that the Python C API is the *perfect* use case
for goto.  You'll see it all over Python's own C code. :).

editor.c, py_txdelta_window_handler(): when PyList_New() fails, and opts is
NULL, you'll return without releasing the GIL.  You should probably also check
the return value for the Py_BuildValue() and PyList_SetItem() calls in this
function.  These are all probably unlikely to fail, so I'm just being paranoid
(IME, not a bad trait to have when it comes to Python's C API. :).

wc.c, py_status(): when Pool(NULL) returns NULL, you'll leak ret.
Technically, this will also happen when dup_status is NULL, but the
PyErr_NoMemory will probably kill you anyway.

The above also happens in adm_init().

adm_entries_read(): check return from PyDict_SetItemString().

adm_get_prop_diffs(): py_propchanges can leak if the Py_BuildValue() returns
NULL, or if py_orig_props ends up NULL.  Also, check the PyList_SetItem()
return value.

repos.c, repos_init(): ret gets leaked if Pool(NULL) returns NULL.

fs_root_paths_changed(): Check return value from PyDict_SetItemString().

util.c, PyOS_tmpfile(): I think tmpfile_fn gets leaked, since
PyObject_GetAttrString() returns a new reference, which you throw away after
the PyObject_CallObject().

prop_hash_to_dict() check return value from PyDict_SetItemString().  Similarly
in pyify_changed_paths() and pyify_changed_paths2().  Also in
pyify_changed_paths2(), when pyval is NULL, py_changed_paths is leaked.

More return value checks missing in py_svn_log_wrapper() and py_dirent().
(Yeah, I know I'm being a PITA :).

stream_init(): ret is leaked when Pool(NULL) returns NULL.  (Is this basically
an svn OOM error?).

py_file_rev_handler() and py_ra_file_rev_handler(): I think ret is leaked if
you don't enter the if-clause.

_ra.c: Similarly, I think it's possible to leak ret from py_open_tmp_file().
E.g You get into the PyFile_Check() else-if-clause, but *fp is not NULL.  ret
doesn't get decref'd.  (OTOH, I don't know the logic of apr_file_from_object()
so it might be an impossible situation.)

get_commit_editor(): commit_callback gets leaked if you take one of the early
exits.

ra_get_dir(): Check return code from PyDict_SetItemString().  py_dirents can
leak if py_props == NULL.

ra_get_locks(): ret can leak if pyval == NULL.  Also, check return value from
PyDict_SetItemString().  (similarly for ra_get_locations,
merge_rangelist_to_list, mergeinfo_to_dict, ra_mergeinfo)

get_username_prompt_provider(): auth can leak if Pool(NULL) returns NULL.

py_simple_prompt(): ret can leak in the early exit error conditions.
Same for:
 * py_ssl_client_cert_pw_prompt()
 * py_ssl_client_cert_prompt()
 * get_ssl_client_cert_pw_prompt_provider()
 * get_ssl_client_cert_prompt_provider()
 * get_username_provider()
 * get_ssl_server_trust_file_provider()
 * get_ssl_client_cert_file_provider()
 * get_ssl_client_cert_pw_file_provider()
 * get_windows_simple_provider()
 * get_windows_ssl_server_trust_provider()
 * get_keychain_simple_provider()

get_ssl_server_trust_prompt_provider(): auth leaked when Pool(NULL) returns
NULL.

py_cb_get_simple_provider_prompt(): ret leaks from the else-clause (it's never
decref'd even when it's not NULL).

Attachment: signature.asc
Description: PGP signature

Reply via email to