मैं अपने आवेदन के एक अपरिभाषित व्यवहार को डीबग कर रहा था। आज, मुझे -fsanitize=undefined -fsanitize=address झंडे आज़माने का मौका मिला, और हमेशा की तरह मैंने अपना आवेदन संकलित किया। पता चला, इसे रन टाइम पर कुछ मिला और इसने इस लॉग को प्रिंट कर लिया,

AddressSanitizer:DEADLYSIGNAL
=================================================================
==502288==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x0000004ce04b bp 0x611000000b98 sp 0x7ffc441a5bf8 T0)
==502288==The signal is caused by a READ memory access.
==502288==Hint: this fault was caused by a dereference of a high value address (see register values below).  Dissassemble the provided pc to learn which register was used.
    #0 0x4ce04b in llhttp__on_message_begin /home/llhttp/src/native/api.c:144:3
    #1 0x4ce4f4 in llhttp__internal__run /home/llhttp/build/c/llhttp.c:14590:13
    #2 0x4ce3e1 in llhttp__internal_execute /home/llhttp/build/c/llhttp.c:14624:10
    #3 0x4c8661 in HTTPTransport::initialize() /home/example.cpp:70:29
    #4 0x4c890f in main /home/example.cpp:76:12
    #5 0x7f09e9f590b2 in __libc_start_main /build/glibc-ZN95T4/glibc-2.31/csu/../csu/libc-start.c:308:16
    #6 0x41d53d in _start (/home/example+0x41d53d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/llhttp/src/native/api.c:144:3 in llhttp__on_message_begin
==502288==ABORTING

मुझे अंततः पता चला कि इसका क्या कारण है। यहाँ यह है,

class Connection : public HTTPTransport
{
public:
    llhttp_t httpParser;
    llhttp_settings_t httpParserSettings;
    sessions session;

    bool auth;
     
    // This line causing it but if I remove it everything works.
    Connection() : auth(){}
};

लेकिन मैंने पाया कि अगर मैं unique_ptr को हटा देता हूं और क्लास के डायरेक्ट इनिशियलाइज़ेशन पर जाता हूं, तो लाइन का कोई प्रभाव नहीं पड़ता है, इस प्रकार segfault।

दिलचस्प बात यह है कि ऐसा नहीं होता है अगर मैं unique_ptr का उपयोग करता हूं और उस लाइन को हटा देता हूं, उसके बाद सब कुछ काम करता है।

मैंने कक्षा में एक इन-क्लास सदस्य प्रारंभकर्ता दृष्टिकोण का उपयोग करने का भी प्रयास किया है; लेकिन यह सिर्फ काम नहीं करता है और एक ही सीईजी गलती फेंकता है।

मैं इसे क्लैंग कंपाइलर पर संकलित कर रहा हूं और सी ++ 17 को लक्षित करता हूं।

संक्षेप में, यहाँ वे चीज़ें हैं जिन्हें मैंने आज़माया है, लेकिन किसी भी तरह से seg दोष को प्रभावित नहीं किया है,

  • इन-क्लास सदस्य आरंभीकरण
  • unique_ptr के बजाय कक्षा का प्रत्यक्ष आरंभीकरण
  • इस वर्ग के पास HTTPTransport आधार वर्ग के साथ विरासत को हटा दिया गया है

मुझे पता है कि std::make_unique क्लास लिस्ट इनिशियलाइज़र को कॉल नहीं करता है, लेकिन तथ्य यह है कि मुझे क्लास के डायरेक्ट इनिशियलाइज़ेशन के साथ एक ही seg फॉल्ट मिल रहा है, और मैंने इसे इस तरह इनिशियलाइज़ किया है,

Connection currentConnection; 

न्यूनतम प्रतिलिपि प्रस्तुत करने योग्य कोड,

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include "llhttp.h"

class HTTPTransport
{
public:
    struct sessions
    {
        std::string url;
    };

private:
    static int handleOnUrl(llhttp_t *ll, const char *buf, size_t len);

public:
    void initialize();    
};

class Connection : public HTTPTransport
{
public:
    llhttp_t httpParser;
    llhttp_settings_t httpParserSettings;
    sessions session;

    bool auth;

    Connection() : auth(){}
};
    
int HTTPTransport::handleOnUrl(llhttp_t *ll, const char *buf, size_t len)
{
    sessions *session = static_cast<sessions *>(ll->data);
    session->url = std::string(buf, len);
    return 0;
}

void HTTPTransport::initialize()
{
    auto currentConnection = std::make_unique<Connection>();

    llhttp_init(&currentConnection->httpParser, HTTP_REQUEST, &currentConnection->httpParserSettings);

    /* Set callbacks */

    currentConnection->httpParserSettings.on_url = handleOnUrl;
    currentConnection->httpParser.data = &currentConnection->session;

    std::string res = "CONNECT [2607:f8b0:4008:80c::2004]:443 HTTP/1.1\r\nHost: [2607:f8b0:4008:80c::2004]:443\r\n\r\n";

    enum llhttp_errno err = llhttp_execute(&currentConnection->httpParser, res.c_str(), res.length());
}

int main() {
    HTTPTransport Server;

    Server.initialize();

    return 0;
}

इसे बनाने के लिए आपको llhttp पार्सर लाइब्रेरी की आवश्यकता होगी। आप इसे Github पर पा सकते हैं।

यह जोड़ने लायक है कि व्यवहार अभी भी वही है, भले ही मैंने एक unique_ptr . का उपयोग नहीं किया हो

c++
2
jeffbRTC 10 फरवरी 2021, 16:57

2 जवाब

सबसे बढ़िया उत्तर

अपने डिफ़ॉल्ट कंस्ट्रक्टर में आप httpParserSettings को इनिशियलाइज़ नहीं कर रहे हैं, जिसका अर्थ है कि Connection ऑब्जेक्ट बनाते समय इसमें कचरा डेटा होगा, और अंततः llhttp_init उस कचरा डेटा का उपयोग करने का प्रयास करेगा। इसे ठीक करने के लिए, डिफ़ॉल्ट कंस्ट्रक्टर में सभी सदस्यों को इनिशियलाइज़ करें:

class Connection : public HTTPTransport
{
public:
    llhttp_t httpParser;
    llhttp_settings_t httpParserSettings;
    sessions session;

    bool auth;

    Connection()
        : httpParser{},
          httpParserSettings{},
          session{},
          auth{}
    {}
};

या सदस्य प्रारंभकर्ता प्रदान करें:

class Connection : public HTTPTransport
{
public:
    llhttp_t httpParser{};
    llhttp_settings_t httpParserSettings{};
    sessions session{};

    bool auth{};
    // no constructor needed in this case
};

Connection के साथ कोई डिफ़ॉल्ट कंस्ट्रक्टर नहीं होने का कारण यह है कि std::make_unique<Connection>() मान आवंटित ऑब्जेक्ट को इनिशियलाइज़ करता है यदि कोई उपयोगकर्ता द्वारा प्रदान किया गया डिफ़ॉल्ट कंस्ट्रक्टर नहीं है।

3
IlCapitano 10 फरवरी 2021, 19:50
// This line causing it but if I remove it everything works.

इस पेज को चेक करें: https://en.cppreference.com/w/cpp/language/ नियम_ऑफ़_थ्री

चूंकि आपको चलने योग्य होने के लिए Connection ऑब्जेक्ट्स की आवश्यकता है (std :: unique_ptr के माध्यम से) लेकिन कॉपी करने योग्य नहीं है, मैं कुछ ऐसा करने का सुझाव दूंगा:

{
public:
    llhttp_t httpParser;
    llhttp_settings_t httpParserSettings;
    sessions session;

    bool auth;

    Connection() : auth(){}
    ~Connection() = default;

    // Non-copyable
    Connection(const Connection&) = delete;
    Connection& operator=(const Connection&) = delete;

    // Movable
    Connection(Connection&&) = default;
    Connection& operator=(Connection&&) = default;
};

संपादित करें: ऐसा लगता है कि आपने केवल डिफ़ॉल्ट-सीटीआर को परिभाषित किया है, इसलिए मुझे यकीन नहीं है कि यह मुद्दा है ...

0
m88 10 फरवरी 2021, 17:33