查找“未知地址上的 SEGV”的原因,由 READ 访问引起

Posted

技术标签:

【中文标题】查找“未知地址上的 SEGV”的原因,由 READ 访问引起【英文标题】:Find the cause of 'SEGV on unknown address', cause by READ access 【发布时间】:2019-10-28 19:01:04 【问题描述】:

我正在编写一个 Splay Tree 实现。代码在 VS 中编译得很好,但测试系统因 DEADLYSIGNAL 而失败。 测试的具体输入是:

search 66
min
max
set 1 20
print

这里是完整的代码:

#include <iostream>
#include <sstream>
#include <stack>
#include <queue>
#include <cmath>


struct Node

    int64_t key;
    std::string value;
    Node* left, * right, * parent;

    Node(const int64_t& k) : key(k), left(nullptr), right(nullptr), parent(nullptr) 
    Node(const int64_t& k, const std::string& v, Node* p) : key(k), value(v),
        left(nullptr), right(nullptr), parent(p) 
;

class SplayTree

    Node* root;
    size_t size;

    bool isRight(Node* node)
    
        if (node && node->parent)
            if (node->parent->right == node)
                return true;
        else
            return false;
    

    std::pair<int, Node*> Find(const int64_t& key)
    
        Node* node = root;
        while (node)
        
            if (node->key == key) 
                return  2, node ;
            else if (node->key > key)
                if (node->left)
                    node = node->left;
                else
                    return  0, node ; 
            else if (node->key < key)
                if (node->right)
                    node = node->right;  
                else
                    return  1, node ;
        
    

    void Merge(Node* left, Node* right)
    
        if (!left && !right)
            root = nullptr;
        else if (!left)
        
            root = right;
            right->parent = nullptr;
        
        else if (!right)
        
            root = left;
            left->parent = nullptr;
        
        else
        
            left = Max(left);
            left->parent = nullptr;
            left->right = right;
            right->parent = left;
        
    

    void rotateL(Node* node)
    
        Node* p = node->parent;
        Node* r = node->right;
        if (p != nullptr)
            if (p->left == node)
                p->left = r;
            else
                p->right = r;
        Node* temp = r->left;
        r->left = node;
        node->right = temp;
        node->parent = r;
        r->parent = p;
        if (temp != nullptr)
            temp->parent = node;
    

    void rotateR(Node* node)
    
        Node* p = node->parent;
        Node* l = node->left;
        if (p != nullptr)
            if (p->left == node)
                p->left = l;
            else
                p->right = l;
        Node* temp = l->right;
        l->right = node;
        node->left = temp;
        node->parent = l;
        l->parent = p;
        if (temp != nullptr)
            temp->parent = node;
    

    void Zig(Node* node)
    
        !isRight(node) ?
            rotateR(node->parent) : rotateL(node->parent);
    

    void ZigZig(Node* node, bool side)
    
        if (side)
        
            rotateL(node->parent->parent);
            rotateL(node->parent);
        
        else
        
            rotateR(node->parent->parent);
            rotateR(node->parent);
        
    

    void ZigZag(Node* node, bool side)
    
        if (side)
        
            rotateL(node->parent);
            rotateR(node->parent);
        
        else
        
            rotateR(node->parent);
            rotateL(node->parent);
        
    

    void Splay(Node* node)
    
        while (node->parent != nullptr)
        
            if (node->parent == root)
                Zig(node);
            else if (!isRight(node) && !isRight(node->parent))
                ZigZig(node, 0);
            else if (isRight(node) && isRight(node->parent))  
                ZigZig(node, 1);
            else if (!isRight(node) && isRight(node->parent)) 
                ZigZag(node, 0);
            else                                               
                ZigZag(node, 1);
        
        root = node;
    


    std::string printNode(Node* node)
    
        std::string result;
        result += '[' + std::to_string(node->key) + ' ' + node->value;
        if (node->parent)
            result += ' ' + std::to_string(node->parent->key);
        result += ']';
        return result;
    


    Node* Max(Node* node)
    
        Node* temp = node;
        if (temp)
        
            while (temp->right)
                temp = temp->right;
            Splay(temp);
            return temp;
        
        else
            return nullptr;
    

    Node* Min(Node* node)
    
        Node* temp = node;
        if (temp)
        
            while (temp->left)
                temp = temp->left;
            Splay(temp);
            return temp;
        
        else
            return nullptr;
    
public:

    Node* getRoot()  return root; 

    SplayTree() : root(nullptr), size(0)  

    SplayTree(uint64_t key)
    
        root = new Node(key); 
        size = 1;
    

    ~SplayTree()
    
        if (root)
        
            std::stack<Node*> toDelete;
            toDelete.push(root);
            while (!toDelete.empty())
            
                Node* node = toDelete.top();
                if (node->left)
                
                    toDelete.push(node->left);
                    node->left = nullptr;
                
                else if (node->right)
                
                    toDelete.push(node->right);
                    node->right = nullptr;
                
                else
                
                    toDelete.pop();
                    delete node;
                
            
        
    

    bool Add(const int64_t& key, const std::string& value)
    
        if (!root)
        
            root = new Node(key, value, nullptr);
            size++;
            return true;
        
        else
        
            std::pair<int, Node*> result = Find(key);
            if (result.first == 2)
                return false;
            else if (result.first == 0)
            
                result.second->left = new Node(key, value, result.second);
                Splay(result.second->left);
                size++;
                return true;
            
            else
            
                result.second->right = new Node(key, value, result.second);
                Splay(result.second->right);
                size++;
                return true;
            
        
    

    std::string Search(const int64_t& key)
    
        if (root)
        
            std::pair<int, Node*> result = Find(key);
            if (result.first == 2)
            
                Splay(result.second);
                return "1 " + result.second->value;
            
            Splay(result.second);
        
        return "0";
    

    Node* Min()  return Min(root); 
    Node* Max()  return Max(root); 

    bool Set(const int64_t& key, const std::string& value)
    

        std::pair<int, Node*> result = Find(key);
        if (result.first == 2)
        
            result.second->value = value;
            Splay(result.second);
            return true;
        
        else
            return false;
    

    bool Delete(const int64_t& key)
    
        if (!root)
            return false;
        std::pair<int, Node*> result = Find(key);
        if (result.first == 2)
        
            Splay(result.second);
            Node* subL = result.second->left;
            Node* subR = result.second->right;
            Merge(subL, subR);
            delete result.second;
            size--;
            return true;
        
        return false;
    

    std::string Print()
    
        std::string result;
        std::queue<Node*> toPrint;
        toPrint.push(root);
        size_t counter = size;
        size_t space = 0;
        size_t i = 0;
        while (!toPrint.empty())
        
            Node* node = toPrint.front();
            toPrint.pop();
            space++;

            if (node)
            
                result += printNode(node);
                toPrint.push(node->left);
                toPrint.push(node->right);
                counter--;
            
            else
            
                result += "_";
                toPrint.push(nullptr);
                toPrint.push(nullptr);
            

            if (space == pow(2, i))
            
                result += "\n";
                if (counter != 0)
                
                    i++;
                    space = 0;
                
            
            else
                result += " ";

            if (counter == 0 && space == pow(2, i))
                break;
        
        return result;
    
;


int main()

    std::string data;
    std::getline(std::cin, data, '\0');
    data += '\n';

    std::istringstream is(data);
    std::ostringstream os; 

    SplayTree tree;

    int64_t key;
    std::string command, value;

    bool empty = false;

    while (is >> command)
    
        if (command.empty())
        
            empty = true;
        
        if (command == "add" && is.peek() != '\n'
            && is >> key && is.peek() != '\n' && is >> value && is.peek() == '\n')
        
            if (!tree.Add(key, value))
                os << "error" << std::endl;
        
        else if (command == "set" && is.peek() != '\n'
            && is >> key && is.peek() != '\n' && is >> value && is.peek() == '\n')
        
            if (!tree.Set(key, value))
                os << "error" << std::endl;
        
        else if (command == "delete" && is.peek() != '\n'
            && is >> key && is.peek() == '\n')
        
            if (!tree.Delete(key))
                os << "error" << std::endl;
        
        else if (command == "search" && is.peek() != '\n'
            && is >> key && is.peek() == '\n')
        
            os << tree.Search(key) << std::endl;
        
        else if (command == "min" && is.peek() == '\n')
        
            Node* temp = tree.Min();
            if (temp)
            
                os << temp->key << " "
                    << temp->value << std::endl;
            
            else
                os << "error" << std::endl;
        
        else if (command == "max" && is.peek() == '\n')
        
            Node* temp = tree.Max();
            if (temp)
            
                os << temp->key << " "
                    << temp->value << std::endl;
            
            else
                os << "error" << std::endl;
        
        else if (command == "print" && is.peek() == '\n')
        
            os << tree.Print();
        
        else
        
            if (!empty)
                os << "error" << std::endl;
        
    
    std::cout << os.str();
    return 0;

VS 调试器没有告诉我导致此错误的原因。 Sanitazier 将其描述为读取错误,但我无法弄清楚它到底发生在哪个函数中。 此外,完整的消毒剂输出:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==26100==ERROR: AddressSanitizer: SEGV on unknown address 0x00000004 (pc 0x08164c7a bp 0xbff0f8d8 sp 0xbff0f420 T0)
==26100==The signal is caused by a READ memory access.
==26100==Hint: address points to the zero page.

希望有人帮忙。提前谢谢你。

【问题讨论】:

VS 调试器没有告诉我导致此错误的原因。 -- 调试器的作用是让您使用收集到的信息,以便您确定错误是什么.调试器不知道你的程序试图做什么——它只是在出现问题时报告,然后你的工作就是将信息更进一步。 代码在 VS 中编译得很好 -- 这仅意味着您的代码没有语法错误,并且链接器已找到您正在调用的所有函数。它与您的代码是否存在逻辑错误无关。其次,我强烈建议您编写main 程序来获取和处理连贯的简单输入,即带有指令(“search”、“max”等)的简单getline。所有这些ispeek 的东西都不重要——它只会把水搅浑,无缘无故地混淆问题。 isRight 有一个错误。打开你的编译器警告,这样编译器可以帮助你注意到这些由“当你的缩进对你说谎”引起的疏忽。 不仅isRightFind也有同样的错误。由于您使用的是 Visual C++,请将您的警告转至 /W4 You have multiple warnings you need to fix. 【参考方案1】:

因为它出现在搜索结果中:

您的代码的某些部分(当您看到完整的 ASan 错误时会发现)正在创建一个无效的地址 0x4 ASan 想要查看其内存。

可能会说 int 意外地转换为指针或像 say 这样的故意转换

 auto p = (int*)4;

查看完整错误和其中的堆栈跟踪。

Derived class offset calculation in boost::serialization. Is it valid?

【讨论】:

以上是关于查找“未知地址上的 SEGV”的原因,由 READ 访问引起的主要内容,如果未能解决你的问题,请参考以下文章

报错TypeError: Cannot read property 'range' of null

查找 read() 返回的错误

EasyUI:Cannot read property 'width' of null

Oracle等待事件之db file scattered read

echarts js报错 Cannot read property 'getAttribute' of null

mysql read commited 和 REPEATABLE read 原因