tag: fix segfault on update
clearMpdTag could be called on a tag that was still in a tag_begin_add transaction before tag_end_add is called. This was causing free() to attempt to operate on bulk.items; which is un-free()-able. Now instead we unmark the bulk.busy to avoid committing the tags to the heap only to be immediately freed. Additionally, we need to remember to call tag_end_add() when a song is updated before we NULL song->tag to avoid tripping an assertion the next time tag_begin_add() is called.
This commit is contained in:
parent
6146d4f5bb
commit
092bdf3d32
@ -202,6 +202,7 @@ static void insertSongIntoList(SongList * list, ListNode ** nextSongNode,
|
|||||||
Song *tempSong = (Song *) ((*nextSongNode)->data);
|
Song *tempSong = (Song *) ((*nextSongNode)->data);
|
||||||
if (tempSong->mtime != song->mtime) {
|
if (tempSong->mtime != song->mtime) {
|
||||||
tag_free(tempSong->tag);
|
tag_free(tempSong->tag);
|
||||||
|
tag_end_add(song->tag);
|
||||||
tempSong->tag = song->tag;
|
tempSong->tag = song->tag;
|
||||||
tempSong->mtime = song->mtime;
|
tempSong->mtime = song->mtime;
|
||||||
song->tag = NULL;
|
song->tag = NULL;
|
||||||
|
35
src/tag.c
35
src/tag.c
@ -26,6 +26,19 @@
|
|||||||
#include "tagTracker.h"
|
#include "tagTracker.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of items managed in the bulk list; if it is
|
||||||
|
* exceeded, we switch back to "normal" reallocation.
|
||||||
|
*/
|
||||||
|
#define BULK_MAX 64
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
int busy;
|
||||||
|
#endif
|
||||||
|
struct tag_item *items[BULK_MAX];
|
||||||
|
} bulk;
|
||||||
|
|
||||||
const char *mpdTagItemKeys[TAG_NUM_OF_ITEM_TYPES] = {
|
const char *mpdTagItemKeys[TAG_NUM_OF_ITEM_TYPES] = {
|
||||||
"Artist",
|
"Artist",
|
||||||
"Album",
|
"Album",
|
||||||
@ -288,8 +301,15 @@ static void clearMpdTag(struct tag *tag)
|
|||||||
tag_pool_put_item(tag->items[i]);
|
tag_pool_put_item(tag->items[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag->items)
|
if (tag->items == bulk.items) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert(bulk.busy);
|
||||||
|
bulk.busy = 0;
|
||||||
|
#endif
|
||||||
|
} else if (tag->items) {
|
||||||
free(tag->items);
|
free(tag->items);
|
||||||
|
}
|
||||||
|
|
||||||
tag->items = NULL;
|
tag->items = NULL;
|
||||||
|
|
||||||
tag->numOfItems = 0;
|
tag->numOfItems = 0;
|
||||||
@ -363,19 +383,6 @@ static inline const char *fix_utf8(const char *str, size_t *length_r) {
|
|||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of items managed in the bulk list; if it is
|
|
||||||
* exceeded, we switch back to "normal" reallocation.
|
|
||||||
*/
|
|
||||||
#define BULK_MAX 64
|
|
||||||
|
|
||||||
static struct {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
int busy;
|
|
||||||
#endif
|
|
||||||
struct tag_item *items[BULK_MAX];
|
|
||||||
} bulk;
|
|
||||||
|
|
||||||
void tag_begin_add(struct tag *tag)
|
void tag_begin_add(struct tag *tag)
|
||||||
{
|
{
|
||||||
assert(!bulk.busy);
|
assert(!bulk.busy);
|
||||||
|
Loading…
Reference in New Issue
Block a user