LINUX.ORG.RU

Странное поведение memmove

 


0

2
typedef struct DNode
{
    ...

    struct DNode ** nodes;
        uint32_t    ncount;

    ...
} DNode;


void DNodeRemove(DNode * node, uint32_t index)
{
    if (index != (node->ncount - 1))
    {
        memmove(&node->nodes[index],
                &node->nodes[index + 1],
                (node->ncount - index - 1) * sizeof(DNode *));
    }

    node->ncount--;
}

Сдвигает сразу на 4 элемента Ломает память вообще непонятно по какому алгоритму:

[             8.100][ RATATOSKR + 04] >>>
{
    305 => '<status>	<id>305<>Playback Audio Buffer Level<>0<>INT<>0<<>',
    304 => '<status>	<id>304<>Playback Video Buffer Level<>72<>INT<>0<<>',
    307 => '<status>	<id>307<>Playback Load Stage<>4<>INT<>0<<>',
    306 => '<status>	<id>306<>Playback Load State<>0<>INT<>0<<>',
    309 => '<status>	<id>309<>Playback Audio Delay<>0<>INT<>0<<>',
    308 => '<status>	<id>308<>Playback Loop Mode<>false<>BOOL<>0<<>',
    310 => '<status>	<id>310<>Audio Mode<>0<>INT<>0<<>',
    313 => '<status>	<id>313<>Playback Current CPL ID<>urn:uuid:2e1c65ee-9f12-41d9-8ad7-abd67e121f30<>STRING<>0<<>',
    314 => '<status>	<id>314<>Playback Current CPL Offset<>3541<>LONG<>0<<>',
    317 => '<status>	<id>317<>Current Playback ID<>urn:uuid:7a9ab3bd-4341-6bea-b59d-a43e035a31cf<>STRING<>0<<>',
    319 => '<status>	<id>319<>3D Delay Enabled<>false<>BOOL<>0<<>',
    322 => '<status>	<id>322<>Dolby Atmos Playback Online Status<>false<>BOOL<>0<<>',
    320 => '<status>	<id>320<>3D Delay Time<>0<>INT<>0<<>',
    332 => '<status>	<id>332<>Playback Not Married<>false<>BOOL<>0<<>',
    452 => '<status>	<id>452<>Scheduler Next Start Time<><>STRING<>0<<>',
    330 => '<status>	<id>330<>Playback Buffer Underrun Error<>false<>BOOL<>0<<>',
    300 => '<status>	<id>300<>Playback State<>2<>INT<>0<<>',
    451 => '<status>	<id>451<>Scheduler Next Content ID<><>STRING<>0<<>',
    331 => '<status>	<id>331<>Playback ICP Communication Error<>false<>BOOL<>0<<>',
    301 => '<status>	<id>301<>Loaded Content<>urn:uuid:2e1c65ee-9f12-41d9-8ad7-abd67e121f30<>STRING<>0<<>',
    450 => '<status>	<id>450<>Scheduler Active<>true<>BOOL<>0<<>',
    302 => '<status>	<id>302<>Playback Timecode<>3541<>LONG<>0<<>',
    303 => '<status>	<id>303<>Loaded Content Duration<>30000<>LONG<>0<<>',
},
[             9.372][ RATATOSKR + 04] ---
{
    309 => '<status>	<id>309<>Playback Audio Delay<>0<>INT<>0<<>',
    308 => '<status>	<id>308<>Playback Loop Mode<>false<>BOOL<>0<<>',
    310 => '<status>	<id>310<>Audio Mode<>0<>INT<>0<<>',
    313 => '<status>	<id>313<>Playback Current CPL ID<>urn:uuid:2e1c65ee-9f12-41d9-8ad7-abd67e121f30<>STRING<>0<<>',
    314 => '<status>	<id>314<>Playback Current CPL Offset<>3541<>LONG<>0<<>',
    308 => '<status>	<id>308<>Playback Loop Mode<>false<>BOOL<>0<<>',
    310 => '<status>	<id>310<>Audio Mode<>0<>INT<>0<<>',
    313 => '<status>	<id>313<>Playback Current CPL ID<>urn:uuid:2e1c65ee-9f12-41d9-8ad7-abd67e121f30<>STRING<>0<<>',
    314 => '<status>	<id>314<>Playback Current CPL Offset<>3541<>LONG<>0<<>',
    317 => '<status>	<id>317<>Current Playback ID<>urn:uuid:7a9ab3bd-4341-6bea-b59d-a43e035a31cf<>STRING<>0<<>',
    319 => '<status>	<id>319<>3D Delay Enabled<>false<>BOOL<>0<<>',
    322 => '<status>	<id>322<>Dolby Atmos Playback Online Status<>false<>BOOL<>0<<>',
    320 => '<status>	<id>320<>3D Delay Time<>0<>INT<>0<<>',
    332 => '<status>	<id>332<>Playback Not Married<>false<>BOOL<>0<<>',
    452 => '<status>	<id>452<>Scheduler Next Start Time<><>STRING<>0<<>',
    330 => '<status>	<id>330<>Playback Buffer Underrun Error<>false<>BOOL<>0<<>',
    300 => '<status>	<id>300<>Playback State<>2<>INT<>0<<>',
    451 => '<status>	<id>451<>Scheduler Next Content ID<><>STRING<>0<<>',
    331 => '<status>	<id>331<>Playback ICP Communication Error<>false<>BOOL<>0<<>',
    301 => '<status>	<id>301<>Loaded Content<>urn:uuid:2e1c65ee-9f12-41d9-8ad7-abd67e121f30<>STRING<>0<<>',
    450 => '<status>	<id>450<>Scheduler Active<>true<>BOOL<>0<<>',
    302 => '<status>	<id>302<>Playback Timecode<>3541<>LONG<>0<<>',
},
[            10.164][ RATATOSKR + 04] <<<
(на моменте --- вызывается DNodeRemove с индексом 0) Где косяк?



Последнее исправление: someoneelsenotme (всего исправлений: 1)

Я бы залогировал параметры memmove и убедился для начала, что и указатели и количество имеют адекватные значения.

ProstoTyoma
()

Вот такой вариант «в лоб» работает, но понятное дело проигрывает по скорости раз в 5. Почему ж все-таки не пашет через memmove?

void DNodeRemove(DNode * node, uint32_t index)
{
    if (index != (node->ncount - 1))
    {
        /*printf("%p, %p, %d\n",
               (node->nodes + index),
               (node->nodes + index + 1),
               (node->ncount - index - 1) * sizeof(DNode *));
        memmove(node->nodes + index,
                node->nodes + index + 1,
                (node->ncount - index - 1) * sizeof(DNode *));*/
        uint32_t i;
        for (i = index; i < (node->ncount - 1); i++)
        {
            DNode * pp         = node->nodes[i];
            node->nodes[i]     = node->nodes[i + 1];
            node->nodes[i + 1] = pp;
        }
    }

    node->ncount--;
}
someoneelsenotme
() автор топика

Ты чего-то недоговариваешь. Элемент из массива удаляется почти хорошо, за вычетом предварительной проверки на пустоту (if (ncount == 0) return).

Запусти под valgrind — есть вероятность, что узнаешь что-то новое.

kawaii_neko ★★★★
()
Ответ на: комментарий от someoneelsenotme

Вот такой вариант «в лоб»

Ты вообще понимаешь что пишешь? Твой «в лоб» не эквивалентен memmove. В данном случае «эквивалент» это

for (int i = index; i < node->ncount - 1; i++)
    node->nodes[i] = node->nodes[i + 1];

kawaii_neko ★★★★
()
Ответ на: комментарий от kawaii_neko

Нет, волгринд показал только пару утечек, которые сейчас должны быть, ибо нет приемника.

someoneelsenotme
() автор топика
Ответ на: комментарий от kawaii_neko

Не важно, я к тому, что доступ к памяти сам по себе не вызываете краша или порчи памяти.

someoneelsenotme
() автор топика
Ответ на: комментарий от anonymous

Если что-то потребовало удаления любого элемента при их количестве == 0 - значит память похерилась уровнем выше. Но да, можно тут exit поставить.

someoneelsenotme
() автор топика

Я вот такой код вообще не понимаю

memmove(&node->nodes[index], &node->nodes[index + 1], (node->ncount - index - 1) * sizeof(DNode *));

Попробуйте

memmove(node->nodes + index, node->nodes + index + 1, (node->ncount - index - 1) * sizeof(DNode *));

ну или

memmove(&(node->nodes[index]), &(node->nodes[index + 1]), (node->ncount - index - 1) * sizeof(DNode *));

Может вы конечно его легко читаетте и точно помните приоритетность всех операторов, но вот я не могу сказать точно к чему именно применяется взятие адресса (до обращения по индексу или после)

zaz ★★★★
()
Ответ на: комментарий от zaz

Тот же эффект. Разницы никакой. Если не помните приоритет - просто вспомните что есть [] ->

a[b] = *(a + b)

P.S. Вспомнил прикол 23[array].

someoneelsenotme
() автор топика

Твои два массива соотносятся так:

0   305
1   304
2   307
3   306
4   309 - 309   0
5   308 - 308   1
6   310 - 310   2
7   313 - 313   3
8   314 - 314   4
          308   5
          310   6
          313   7
          314   8
9   317 - 317   9
    319 - 319
    322 - 322
    320 - 320
    332 - 332
    452 - 452
    330 - 330
    300 - 300
    451 - 451
    331 - 331
    301 - 301
    450 - 450
    302 - 302
    303

Последнего 303 нет, потому что ncount--. А по верхней части видно, что ты скопировал индексы 4-8 (309...314, итого 5 шт.) на место 0. Оригинальные значения по индексам 5-8 (308...314) остались на месте, как и должно быть. Значит, если принять указатели a и b за DNode*, выполнился memmove(a[0], a[4], 5*sizeof(DNode*)). Учитывая, что index==0, а ncount==23, похоже на то, что ты копируешь 23-0-1==22 байта, что есть 5.5 указателей на 32-битной архитектуре. Так получилось, что 6-й (индекс 5) лег сам в себя, потому что отличается только младшими двумя байтами, которые и пришлись на 0.5 указателя.

Итого: твой код написан с * sizeof(...), а собран без него. Чини систему сборки или руки.

arturpub ★★
()
Ответ на: комментарий от arturpub

*Опа какая-то. Спасибо за подробный анализ, но это какая-то *опа. Ничего больше не барахлит, все по десять раз пересобиралось, в других местах memmove используется для такой же цели, и работает вроде правильно.

Физически не могу понять, почему творится такая байда. Вернусь на работу - попробую вместо sizeof(DNode *) зашить 4 или sizeof(void *), хоть это и неправильно.

// someoneelsenotme

anonymous
()
Ответ на: комментарий от anonymous

Да, но если проблема в сборке, то остается только гадать, что же там реально было при последнем билде. Остальные симптомы сходятся.

arturpub ★★
()
Ответ на: комментарий от zaz

Любой сишнег знает, что сначала применяется всё справа, а потом всё слева.

vzzo ★★★
()

Косяк у тебя в if(index != (node->ncount - 1) фишка в чем если у тебя индекс вышел за границы ты это никак не отслеживаешь соответственно ты начинаешь крушить память. Правильно эта проверка выглядит как if(index < (node->ncount - 1).

BlackJack
()
Ответ на: комментарий от ProstoTyoma

Ничем не кончилось, поменял на

for (int i = index; i < node->ncount - 1; i++)
    node->nodes[i] = node->nodes[i + 1];
someoneelsenotme
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.