diff --git a/bindings/python/src/session.cpp b/bindings/python/src/session.cpp index 9e330c102..34340216b 100644 --- a/bindings/python/src/session.cpp +++ b/bindings/python/src/session.cpp @@ -207,7 +207,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 >(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( + extract(params["ti"])); + } + if (params.has_key("info_hash")) p.info_hash = sha1_hash(bytes(extract(params["info_hash"])).arr); @@ -439,20 +448,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) { diff --git a/bindings/python/test.py b/bindings/python/test.py index 5317ccc50..31cc02c36 100644 --- a/bindings/python/test.py +++ b/bindings/python/test.py @@ -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): diff --git a/include/libtorrent/heterogeneous_queue.hpp b/include/libtorrent/heterogeneous_queue.hpp index ffdf33181..bed8c2bee 100644 --- a/include/libtorrent/heterogeneous_queue.hpp +++ b/include/libtorrent/heterogeneous_queue.hpp @@ -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];