Qt: Сгенерированный код не работает при обновлении QString - PullRequest
0 голосов
/ 20 сентября 2018

Я изменяю код GUI, написанный на Qt ( LibrePilot ).Есть способ добавить пользовательские классы.Они генерируются автоматически из описания XML.

Таким образом, этот класс:

<xml>
<object name="RecorderService_RecordDescription" singleinstance="true" settings="false" category="State">
    <description>For Recorder gadget</description>

    <field name="text"      units="char"   type="string"  elements="1"/>

    <access gcs="readwrite" flight="readwrite"/>
    <telemetrygcs    acked="false" updatemode="manual"   period="0"/>
    <telemetryflight acked="false" updatemode="periodic" period="1000"/>
    <logging                       updatemode="periodic" period="100"/>
</object>
</xml>

Будет автоматически сгенерирован в класс, в котором есть один элемент данных, содержащийся внутри структуры с методами для доступа к нему.

// Field structure
typedef struct {
    QString text;

} __attribute__((packed)) DataFields;

Когда я пытаюсь установить text с новым значением, используя метод setText:

void RecorderService_RecordDescription::setText(const QString value)
{
   mutex->lock();
   bool changed = (data_.text != static_cast<QString>(value));
   data_.text = static_cast<QString>(value);
   mutex->unlock();
   if (changed) { emit textChanged(value); }
}

Я получаю SIGABRT исключение.

#0  0x00007ffff509ce97 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007ffff509e801 in __GI_abort () at abort.c:79
#2  0x00007ffff50e7897 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff5214b9a "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3  0x00007ffff50ee90a in malloc_printerr (str=str@entry=0x7ffff5212d88 "free(): invalid pointer") at malloc.c:5350
#4  0x00007ffff50f5e1c in _int_free (have_lock=0, p=0x7ffff5f8c5f0, av=0x7ffff5449c40 <main_arena>) at malloc.c:4157
#5  0x00007ffff50f5e1c in __GI___libc_free (mem=0x7ffff5f8c600) at malloc.c:3124
#6  0x00007fffc798671e in RecorderService_RecordDescription::setText(QString) () at /usr/lib/librepilot-gcs/plugins/LibrePilot/libUAVObjects.so

Одно решение, которое я нашел, состоит в том, что, если я добавлю другое поле к RecorderService_RecordDescription.Т.е. XML выглядит так:

<xml>
<object name="RecorderService_RecordDescription" singleinstance="true" settings="false" category="State">
    <description>For Recorder gadget</description>

    <field name="text"      units="char"   type="string"  elements="1"/>
    <field name="seconds"   units="sec"    type="uint32"  elements="1"/>

    <access gcs="readwrite" flight="readwrite"/>
    <telemetrygcs    acked="false" updatemode="manual"   period="0"/>
    <telemetryflight acked="false" updatemode="periodic" period="1000"/>
    <logging                       updatemode="periodic" period="100"/>
</object>
</xml>

Ошибка исчезает.Автоматически сгенерированный класс имеет такую ​​структуру данных:

// Field structure
typedef struct {
    quint32 seconds;
    QString text;

} __attribute__((packed)) DataFields;

Код для setText такой же.Эта ошибка не случалась раньше, когда мы использовали старую версию gcc.Текущая версия - 7.2.

У всех есть идеи, почему происходит ошибка и как ее исправить.Спасибо.

1 Ответ

0 голосов
/ 20 сентября 2018

Тот факт, что код генерируется автоматически, не имеет отношения к этому вопросу.Вы говорите, что у вас есть очень короткий фрагмент кода, который предположительно не работает: переместите его в отдельный main.cpp в качестве тестового примера!Я держу пари, что у вас есть другие проблемы в коде, и поэтому он терпит неудачу.Одна из проблем, с которой вы столкнулись, заключается в том, что __attribute__((packed)) - это то, что вы, по сути, любезно просите компилятор дать вам какое-то неопределенное поведение - вам не нужен этот атрибут, потому что способ, которым он работает, не тот, который вы думаете, он работает.Правильная реализация этого атрибута не должна генерировать записи с недостаточно выровненными элементами, и, таким образом, все еще может быть добавлено заполнение для платформы - вы просто предполагаете, что этого не произойдет.И вообще: QString - это не то, что вы можете записать на диск, поэтому упаковка этой структуры не имеет смысла.В некоторых случаях Gcc неправильно реализовал этот атрибут, что может привести к наблюдаемому вами поведению, хотя и не в конкретном случае структуры, которую вы показываете.Возможно, какая-то другая упакованная структура повредила состояние программы и вызвала сбой, который вы видите.Прежде всего: сделайте отдельный тестовый пример.Тогда мы можем выяснить, что пошло не так.Но, прежде всего: Не используйте __attribute__((packed).Он бесполезен для обычного использования: сериализация. Если вы хотите сериализовать / десериализовать двоичные данные, используйте QDataStream или аналогичный механизм.

...