【问题标题】:Uncaught exception of type boost::wrapexcept<boost::system::system_error> from boost inside Android app来自 Android 应用程序内部的 boost::wrapexcept<boost::system::system_error> 类型的未捕获异常
【发布时间】:2020-06-30 16:45:02
【问题描述】:

我在一个 android 应用程序中使用 boost 并获得一个随机 SIGABRT:

    "terminating with uncaught exception of type boost::wrapexcept<boost::system::system_error>: partial message" failed'
    2020-06-30 17:44:52.643 24683-24683/? A/DEBUG:     eax 00000000  ebx 0000600f  ecx 00006057  edx 00000006
    2020-06-30 17:44:52.643 24683-24683/? A/DEBUG:     esi 85c46978  edi 85c46920
    2020-06-30 17:44:52.643 24683-24683/? A/DEBUG:     xcs 00000073  xds 0000007b  xes 0000007b  xfs 0000003b  xss 0000007b
    2020-06-30 17:44:52.643 24683-24683/? A/DEBUG:     eip aa5d1424  ebp 85c42918  esp 85c428bc  flags 00000296
    2020-06-30 17:44:52.644 24683-24683/? A/DEBUG: backtrace:
    2020-06-30 17:44:52.644 24683-24683/? A/DEBUG:     #00 pc ffffe424  [vdso:aa5d1000] (__kernel_vsyscall+16)
    2020-06-30 17:44:52.644 24683-24683/? A/DEBUG:     #01 pc 0007a03c  /system/lib/libc.so (tgkill+28)
    2020-06-30 17:44:52.644 24683-24683/? A/DEBUG:     #02 pc 00075885  /system/lib/libc.so (pthread_kill+85)
    2020-06-30 17:44:52.644 24683-24683/? A/DEBUG:     #03 pc 0002785a  /system/lib/libc.so (raise+42)
    2020-06-30 17:44:52.645 24683-24683/? A/DEBUG:     #04 pc 0001ee36  /system/lib/libc.so (abort+86)
    2020-06-30 17:44:52.645 24683-24683/? A/DEBUG:     #05 pc 00023d48  /system/lib/libc.so (__libc_fatal+40)
    2020-06-30 17:44:52.645 24683-24683/? A/DEBUG:     #06 pc 0001f300  /system/lib/libc.so (__assert2+64)

我正在运行 Android 模拟器,所以这发生在 X86 cpu 上,但我不能说更多, ASM 对我来说真的很模糊。代码似乎并不复杂。 这是从 JNI 调用的 CPP 文件:

HttpClient syncclient(io_service);
syncclient.getJsonSync();   <---SIGABRT

getJsonSync 会这样做:

getJsonSync(){
    tcp::resolver resolver(io_service);
    beast::tcp_stream stream(io_service);

    auto const results = resolver.resolve(server, port);

    stream.connect(results);
    http::request<http::string_body> req{http::verb::post, path, 11};

    req.set(http::field::host, server);
    req.version(11);
    req.set(http::field::authorization, authorization);
    req.set(beast::http::field::content_type, "application/json");
    req.set(beast::http::field::connection, "close");
    req.body() = data;
    req.prepare_payload();

    http::write(stream, req);
    beast::flat_buffer buffer;
    http::response<http::dynamic_body> res;
    http::read(stream, buffer, res);

    Response *nr = NULL; //structure where msg body and http status code are copied
    if (res.result_int() == 200*){
        std::string body { boost::asio::buffers_begin(res.body().data()),
                           boost::asio::buffers_end(res.body().data()) };

        initNativeResponse(&nr, id); //alloc the structure

        if(nr == NULL){
            /* memory allocation failed */
            return NULL;
        }
        nr->obj = strdup(body.c_str());
        nr->msg_code =res.result_int();
    }

    beast::error_code ec;
    stream.socket().shutdown(tcp::socket::shutdown_both, ec);

    if (ec && ec != beast::errc::not_connected){
        return NULL;
    }
    return nr;
}

和 initNativeResponse 信息量不是很大,但我在这里添加:

void initNativeResponse(Response **response, int msgId){
*response = (Response *) malloc(sizeof(struct native_response));
if(*response == NULL){
    return;
}
(*response)->id = msgId;
(*response)->obj = NULL;

}

【问题讨论】:

  • 那么,您使用的任何 Boost 函数都可以抛出异常吗?如果是这样,您需要在某个地方处理它们。

标签: android c++ boost java-native-interface sigabrt


【解决方案1】:

崩溃不是随机的。

特别是如果它们来自未捕获的异常(那么它们来自未能处理异常)。

通常异常可以很好地表明问题所在。在你的情况下:

boost::system::system_error: 部分消息

https://www.boost.org/doc/libs/1_66_0/libs/beast/doc/html/beast/using_websocket/send_and_receive_messages.html

那是你的问题。解析器没有收到完整的消息。存在很多原因。如果连接在响应中途关闭,那是很自然的。

阅读您的代码

    std::string body{ boost::asio::buffers_begin(res.body().data()),
                      boost::asio::buffers_end(res.body().data()) };

让我觉得您应该只使用string_body 开头。

一边

initNativeResponse 信息量不是很大,但我在这里添加:

没有信息。这是我很长一段时间以来看到的最令人讨厌的 C 滥用。 strdup 也一样。 strdup 无论如何都不是 POD。

这是一个 c++ 写的:

struct Response {
    int id;
    int msg_code;
    char* obj = nullptr;

    ~Response() {
        ::free(static_cast<void*>(obj));
        obj = nullptr;
    }
};

using ResponsePtr = std::unique_ptr<Response>;

ResponsePtr initNativeResponse(int msgId) {
    return std::make_unique<Response>(Response{ msgId, 0, nullptr });
}

虽然,真的,你最好只使用价值语义:

struct Response {
    int id;
    int msg_code = 0;
    std::string obj;
};

现在你可以写了:

return Response{id, res.result_int(), std::move(res.body())};

这将是异常安全的,更多的分配优化等。如果您真的必须指出“无响应”(为什么?这只会在 malloc 失败时发生......异常区域),请使用std::optional&lt;Response&gt;

演示代码

Live On Coliru

#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <boost/beast/http.hpp>
#include <memory>

namespace beast = boost::beast;
namespace http = beast::http;
using boost::asio::ip::tcp;

boost::asio::io_service io_service;
auto constexpr server = "example.com";
auto constexpr port = "http";
auto constexpr path = "/";
auto constexpr authorization = "dXNlcjpwYXNzd29yZA==";
auto constexpr data = R"({ "some" : 42, "data": { "nested": [1,2,3], "fields" : null } })";

struct Response {
    int id;
    unsigned msg_code = 0;
    std::string obj;
};

static inline auto make_request() {
    http::request<http::string_body> req{ http::verb::post, path, 11 };

    req.set(http::field::host, server);
    req.version(11);
    req.set(http::field::authorization, authorization);
    req.set(beast::http::field::content_type, "application/json");
    req.set(beast::http::field::connection, "close");
    req.body() = data;
    req.prepare_payload();
    return req;
}

Response getJsonSync() {
    tcp::resolver resolver(io_service);
    beast::tcp_stream stream(io_service);

    auto results = resolver.resolve(server, port);

    stream.connect(results);

    http::write(stream, make_request());
    beast::flat_buffer buffer;
    http::response<http::string_body> res;
    http::read(stream, buffer, res);

    if (res.result_int() == 200) {
        stream.socket().shutdown(tcp::socket::shutdown_both); // exception handling FTW

        int id = 42; // FIXME
        return { id, res.result_int(), std::move(res.body()) };
    }

    return {};
}

#include <iostream>
#include <iomanip>
int main() {
    auto res = getJsonSync();
    std::cout << "res.id: " << res.id << "\n";
    std::cout << "res.msg_code: " << res.msg_code << "\n";
    std::cout << "res.obj: " << std::quoted(res.obj) << "\n";
}

打印(给定网络访问权限):

res.id: 42
res.msg_code: 200
res.obj: "<!doctype html>
<html>

     [... snip ...]

</html>
"

【讨论】:

  • 我的意思是崩溃时有发生。很长一段时间后,要回到 C++ 的轨道上来并不容易。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多