std::unique_ptr<DBusMessage> != nullptr 进入函数参数后

问题描述 投票:0回答:1

我正在尝试编写一个使用 DBus 与 BlueZ 交互的程序。根据我从 DBus 文档、BlueZ DBus API 文档和各种论坛收集的信息,我的思考过程如下:

  1. 连接到DBus
  2. 使用“默认”适配器开始发现(只是硬编码为
    hci0
  3. 使用
    org.freedesktop.DBus.ObjectManager.GetManagedObjects()
    查找可用设备。

所以我写了以下代码:

#include <...>
#include <dbus-1.0/dbus/dbus.h>

struct DBusDeleter
{
    void operator()(DBusConnection *connection) {dbus_connection_unref(connection);}
    void operator()(DBusMessage *msg) {dbus_message_unref(msg);}
    void operator()(DBusError *err) {dbus_error_free(err);}
};

void print_managed_objects(std::unique_ptr<DBusMessage, DBusDeleter> message)
{
    DBusMessageIter message_iter;
    dbus_message_iter_init(message.get(), &message_iter);
    std::cout << (char) dbus_message_iter_get_arg_type(&message_iter) << '\n';

    DBusMessageIter dict_iter;
    dbus_message_iter_recurse(&message_iter, &dict_iter);
    std::cout << (char) dbus_message_iter_get_arg_type(&dict_iter) << '\n';

    while(dbus_message_iter_get_arg_type(&dict_iter) == DBUS_TYPE_DICT_ENTRY)
    {
        DBusMessageIter entry_iter;
        dbus_message_iter_recurse(&dict_iter, &entry_iter);

        char * object_path;

        dbus_message_iter_get_basic(&entry_iter, object_path);
        std::cout << object_path << "\n";

        std::cout << (char) dbus_message_iter_get_arg_type(&entry_iter) << '\n';

        dbus_message_iter_next(&dict_iter);
    }
    std::cout << std::flush;
}

int main()
{
    std::unique_ptr<DBusError, DBusDeleter> dbus_error(new DBusError);
    dbus_error_init(dbus_error.get());

    std::shared_ptr<DBusConnection> conn(dbus_bus_get(DBUS_BUS_SYSTEM, dbus_error.get()), DBusDeleter());

    if (dbus_error_is_set(dbus_error.get()))
    {
        std::cout << "DBus Error: " << dbus_error->message << std::endl;
        return 1;
    }

    std::string service_name = "org.bluez";
    std::unique_ptr<DBusMessage, DBusDeleter> msg, reply;

    // Start Device Discovery

    msg.reset(dbus_message_new_method_call(service_name.c_str(), "/org/bluez/hci0", "org.bluez.Adapter1", "StartDiscovery"));
    reply.reset(nullptr);

    uint32_t serial = 1;

    dbus_connection_send(conn.get(), msg.get(), &serial);

    if (dbus_error_is_set(dbus_error.get()))
    {
        std::cout << "BlueZ Error (Failed to start discovery): " << dbus_error->message << std::endl;
        return 1;
    }

    std::chrono::duration<int64_t> scan_duration = std::chrono::seconds(10);
    std::chrono::_V2::system_clock::time_point start_time = std::chrono::system_clock::now();

    msg.reset(dbus_message_new_method_call(service_name.c_str(), "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"));

    while (start_time + scan_duration >= std::chrono::system_clock::now())
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));

        reply = std::unique_ptr<DBusMessage, DBusDeleter>(dbus_connection_send_with_reply_and_block(conn.get(), msg.get(), -1, dbus_error.get()));

        if (dbus_error_is_set(dbus_error.get()))
        {
            std::cout << "error with reply: " << dbus_error->message << "\n";
            break;
        }

        print_managed_objects(std::move(reply));
        
        if (reply == nullptr) {
            std::cout << "All Good!\n";
            continue;
        }

        std::cout << "Something went wrong!\n";
        break;
    }

    // more code...
}

问题发生在

print_managed_objects
函数调用周围。当函数返回时,我希望由于
print_managed_objects
函数已经消耗了消息,因为我已经赋予了它消息的所有权,所以一切都会好起来,但是对
nullptr
的检查在原始
unique_ptr
上失败了已移出。

这意味着

reply
指针仍然具有对
print_managed_objects
返回后被销毁的消息的引用,并且在循环的下一次迭代中重置指针时,程序会崩溃,因为DBus会吐出以下错误:

dbus[15920]:dbus_message_unref() 的参数不正确,文件 dbus-message.c 第 1728 行中的断言“message-> Generation == _dbus_current_ Generation”失败

我的问题是为什么

reply
的内部指针在移动后没有设置为
nullptr
?根据 另一个堆栈溢出问题,在唯一指针上调用
std::move()
会将该指针的内部指针设置为
nullptr

编辑:我在

print_managed_objects
函数中省略了一些行,我认为我可以省略这些行以获得最小的可重现示例,但这些行实际上是发生错误所必需的。具体来说,这些行:

char * object_path;

dbus_message_iter_get_basic(&entry_iter, object_path);
std::cout << *object_path << "\n";
c++ smart-pointers dbus
1个回答
0
投票

这里有一个问题。

char * object_path;
dbus_message_iter_get_basic(&entry_iter, object_path);
std::cout << *object_path << "\n";

您将未初始化的指针传递给函数。这是未定义的行为。您的情况似乎得到了损坏的堆栈数据。

std::cout << *object_path << "\n";

我不知道你对那里有什么期望。至于第三行,您可能期望单个字符数据。代码应该是

char object_path;
dbus_message_iter_get_basic(&entry_iter, &object_path);
std::cout << object_path << "\n";

&object_path
传递字符存储的地址。

© www.soinside.com 2019 - 2024. All rights reserved.