fix python GIL issue when passing in a torrent_info object that later gets destroyed from within libtorrent

This commit is contained in:
arvidn 2016-04-03 23:50:06 -04:00
parent cf5c39a050
commit 90efec5d19
3 changed files with 43 additions and 15 deletions

View File

@ -188,7 +188,16 @@ namespace
{
// torrent_info objects are always held by a shared_ptr in the python binding
if (params.has_key("ti") && params.get("ti") != boost::python::object())
p.ti = extract<boost::shared_ptr<torrent_info> >(params["ti"]);
{
// make a copy here. We don't want to end up holding a python-owned
// object inside libtorrent. If the last reference goes out of scope
// on the C++ side, it will end up freeing the python object
// without holding the GIL and likely crash.
// https://mail.python.org/pipermail/cplusplus-sig/2007-June/012130.html
p.ti = boost::make_shared<torrent_info>(
extract<torrent_info const&>(params["ti"]));
}
if (params.has_key("info_hash"))
p.info_hash = sha1_hash(bytes(extract<bytes>(params["info_hash"])).arr);
@ -420,20 +429,20 @@ namespace
return ret;
}
cache_status get_cache_info1(lt::session& s, torrent_handle h, int flags)
{
cache_status ret;
s.get_cache_info(&ret, h, flags);
return ret;
}
cache_status get_cache_info1(lt::session& s, torrent_handle h, int flags)
{
cache_status ret;
s.get_cache_info(&ret, h, flags);
return ret;
}
#ifndef TORRENT_NO_DEPRECATE
cache_status get_cache_status(lt::session& s)
{
cache_status ret;
s.get_cache_info(&ret);
return ret;
}
cache_status get_cache_status(lt::session& s)
{
cache_status ret;
s.get_cache_info(&ret);
return ret;
}
dict get_utp_stats(session_status const& st)
{

View File

@ -73,6 +73,25 @@ class test_alerts(unittest.TestCase):
print(st.info_hash)
self.assertEqual(st.save_path, os.getcwd())
def test_pop_alerts(self):
ses = lt.session({'alert_mask': lt.alert.category_t.all_categories})
ses.async_add_torrent({"ti": lt.torrent_info("base.torrent"), "save_path": "."})
# this will cause an error (because of duplicate torrents) and the
# torrent_info object created here will be deleted once the alert goes out
# of scope. When that happens, it will decrement the python object, to allow
# it to release the object.
# we're trying to catch the error described in this post, with regards to
# torrent_info.
# https://mail.python.org/pipermail/cplusplus-sig/2007-June/012130.html
ses.async_add_torrent({"ti": lt.torrent_info("base.torrent"), "save_path": "."})
time.sleep(1)
for i in range(0, 10):
alerts = ses.pop_alerts()
for a in alerts:
print(a.message())
time.sleep(0.1)
class test_bencoder(unittest.TestCase):
def test_bencode(self):

View File

@ -163,9 +163,9 @@ namespace libtorrent {
const static int header_size = (sizeof(header_t) + sizeof(uintptr_t)
- 1) / sizeof(uintptr_t);
void grow_capacity(int size)
void grow_capacity(int const size)
{
int amount_to_grow = (std::max)(size + header_size
int const amount_to_grow = (std::max)(size + header_size
, (std::max)(m_capacity * 3 / 2, 128));
uintptr_t* new_storage = new uintptr_t[m_capacity + amount_to_grow];