diff --git a/NEWS b/NEWS index 98318b776..716365581 100644 --- a/NEWS +++ b/NEWS @@ -52,12 +52,13 @@ ver 0.20 (not yet released) * update - apply .mpdignore matches to subdirectories -ver 0.19.14 (not yet released) +ver 0.19.14 (2016/03/18) * decoder - dsdiff: fix off-by-one buffer overflow - opus: limit tag size to 64 kB * archive - iso9660: fix buffer overflow +* fix quadratic runtime bug in the tag pool * fix build failures on non-glibc builds due to constexpr Mutex ver 0.19.13 (2016/02/23) diff --git a/src/tag/TagPool.cxx b/src/tag/TagPool.cxx index af9e2f71e..efa9cd544 100644 --- a/src/tag/TagPool.cxx +++ b/src/tag/TagPool.cxx @@ -24,19 +24,23 @@ #include "util/VarSize.hxx" #include "util/StringView.hxx" +#include + #include #include #include Mutex tag_pool_lock; -static constexpr size_t NUM_SLOTS = 4096; +static constexpr size_t NUM_SLOTS = 4093; struct TagPoolSlot { TagPoolSlot *next; unsigned char ref; TagItem item; + static constexpr unsigned MAX_REF = std::numeric_limits::max(); + TagPoolSlot(TagPoolSlot *_next, TagType type, StringView value) :next(_next), ref(1) { @@ -114,7 +118,7 @@ tag_pool_get_item(TagType type, StringView value) for (auto slot = *slot_p; slot != nullptr; slot = slot->next) { if (slot->item.type == type && value.Equals(slot->item.value) && - slot->ref < 0xff) { + slot->ref < TagPoolSlot::MAX_REF) { assert(slot->ref > 0); ++slot->ref; return &slot->item; @@ -133,17 +137,14 @@ tag_pool_dup_item(TagItem *item) assert(slot->ref > 0); - if (slot->ref < 0xff) { + if (slot->ref < TagPoolSlot::MAX_REF) { ++slot->ref; return item; } else { - /* the reference counter overflows above 0xff; - duplicate the item, and start with 1 */ - auto slot_p = tag_value_slot_p(item->type, item->value); - slot = TagPoolSlot::Create(*slot_p, item->type, - item->value); - *slot_p = slot; - return &slot->item; + /* the reference counter overflows above MAX_REF; + obtain a reference to a different TagPoolSlot which + isn't yet "full" */ + return tag_pool_get_item(item->type, item->value); } }