尝试获取具有自定义类型的 DBus 属性时出现致命错误

Posted

技术标签:

【中文标题】尝试获取具有自定义类型的 DBus 属性时出现致命错误【英文标题】:Fatal error when trying to get a DBus property with custom type 【发布时间】:2015-04-05 09:22:34 【问题描述】:

我正在尝试将 UDisks2 与 Qt 应用程序接口,并读取自定义属性使程序崩溃。

对于 SMART 属性,一切正常(包括 custom properties),但是当我尝试读取 RAID 设备属性 ActiveDevices 时,我收到 Qt 致命错误并且应用程序崩溃

以下是说明行为的测试程序:

#include <QApplication>

#include <QDBusMetaType>
#include <QDBusConnection>
#include <QDBusInterface>

#include <QDebug>


//create the structure as defined in 
// http://udisks.freedesktop.org/docs/latest/gdbus-org.freedesktop.UDisks2.MDRaid.html#gdbus-property-org-freedesktop-UDisks2-MDRaid.ActiveDevices 
struct MDRaidMember 
   QDBusObjectPath block;
   qint32 slot;
   QStringList state;
   qint64 numReadErrors;
   QVariantMap expansion;
;
Q_DECLARE_METATYPE(MDRaidMember)


//marshalling operator
QDBusArgument &operator<<(QDBusArgument &argument, const MDRaidMember& raidMember)

    argument.beginStructure();
    argument << raidMember.block;
    argument << raidMember.slot;
    argument << raidMember.state;
    argument << raidMember.numReadErrors;
    argument << raidMember.expansion;
    argument.endStructure();
    return argument;



//unmarshall operator
const QDBusArgument &operator>>(const QDBusArgument &argument, MDRaidMember& raidMember)

    argument.beginStructure();
    argument >> raidMember.block;
    argument >> raidMember.slot;
    argument >> raidMember.state;
    argument >> raidMember.numReadErrors;
    argument >> raidMember.expansion;
    argument.endStructure();
    return argument;




int main(int argc, char *argv[]) 
  QApplication app(argc, argv);

  //register the type, everything looks fine
  qDebug() << qRegisterMetaType<MDRaidMember>("MDRaidMember");
  qDebug() << qDBusRegisterMetaType<MDRaidMember>();


  QDBusInterface iface("org.freedesktop.UDisks2",
                       "/org/freedesktop/UDisks2/mdraid/9aec6784_86ec37d4_8c1c6add_4dc9fe81",
                       "org.freedesktop.UDisks2.MDRaid",
                       QDBusConnection::systemBus());

  //read some properties
  qDebug() << iface.property("UUID");
  qDebug() << iface.property("ActiveDevices"); //crash the test program!

  return app.exec();

执行此代码产生以下输出

1057
1057
QVariant(QString, "9aec6784:86ec37d4:8c1c6add:4dc9fe81")
Cannot construct placeholder type QDBusRawType
zsh: abort (core dumped)  ./app/test_members

有人遇到过这种情况吗?我根本不认为它与我的代码有关,因为如果未声明自定义类型(仅保留 main 函数的内容),结果是相同的。

【问题讨论】:

UDisks2 遇到了完全相同的问题。 【参考方案1】:

我没有找到正确的答案,但这里有一个解决方法:在接口 org.freedesktop.DBus.Properties 上调用 Get 方法并手动解组结果。棘手的部分是计算结果的内容(它是一个 QVariant 包含一个 QDBusVariant 包含一个 QDBusArgument

更新的main函数:

//...

int main(int argc, char *argv[]) 
  QApplication app(argc, argv);

  //register the type, everything looks fine
  qDebug() << qRegisterMetaType<MDRaidMember>("MDRaidMember");
  qDebug() << qDBusRegisterMetaType<MDRaidMember>();


  QDBusInterface iface("org.freedesktop.UDisks2",
                   "/org/freedesktop/UDisks2/mdraid/9aec6784_86ec37d4_8c1c6add_4dc9fe81",
                   "org.freedesktop.DBus.Properties",
                   QDBusConnection::systemBus());

  QDBusMessage reply = iface.call("Get", "org.freedesktop.UDisks2.MDRaid", "ActiveDevices");
  QVariant v = reply.arguments().first();
  QDBusArgument arg = v.value<QDBusVariant>().variant().value<QDBusArgument>();

  QList<MDRaidMember> members;
  arg.beginArray();
  while(!arg.atEnd()) 
    MDRaidMember m;
    arg >> m;
    members << m;
  

  qDebug() << members;

  return app.exec();

【讨论】:

有未记录的qdbus_cast&lt; T &gt;(QVariant) 专门用于这些目的的重载。

以上是关于尝试获取具有自定义类型的 DBus 属性时出现致命错误的主要内容,如果未能解决你的问题,请参考以下文章

Emacs:尝试切换到乳胶模式时出现与 dbus 相关的错误

尝试使用 twilio Api phpSDK 发送消息时出现致命错误

使用 Swift 和 Parse 获取 Facebook UserData 时出现致命错误

为具有嵌套标签的自定义标签编写 jekyll 插件时出现问题

GCC - 将宏用于函数属性时出现“具有初始化程序但类型不完整”错误

尝试使用自定义图标创建 TabBarIOS 时出现不变违规错误