簡體   English   中英

使用共享指針時釋放后堆的使用

[英]Heap use after free when using shared pointers

當我嘗試將共享指針傳遞給 class object 時,出現免費錯誤后,我一直在使用堆。

首先,我的樹構建器將根作為私有字段:

class ExpressionTree{
private:
std::shared_ptr<ASTNode> root;
public:
std::shared_ptr<ASTNode> getRoot();
void build(std::string expression);
}

ASTNode 供參考:

class ASTNode {
public:
    virtual ~ASTNode() = default;
    virtual void accept(ASTVisitor& visitor, ElementMap elements) = 0;
};

構建 function(使用調車場算法)將節點存儲在出隊中:

 std::deque<std::shared_ptr<ASTNode>> nodeStack;
std::deque<std::string> operatorStack;

例如,對於二元運算符(從 ASTNode 派生的ASTNode ):

auto right = nodeStack.back();
nodeStack.pop_back();
auto left= nodeStack.back();
nodeStack.pop_back();

root = std::make_shared<BinaryOperator>(operatorStack.back(), left, right);
operatorStack.pop_back();
nodeStack.emplace_back(std::move(root));

在調車場算法遍歷所有令牌后,我移動根:

root = std::move(nodeStack.back());

我有一個游戲“規則”向量(存儲為字符串),我試圖將它們存儲到我擁有的"Rule"類中。 問題出在"When"規則中。 我的解釋器是我使用樹構建器並構建“When”object 的地方:

ExpressionTree expressionTree;
    for (auto rule: rules_from_json->getVector()){
        if(ruleName == "when"){
        std::vector<std::pair<std::shared_ptr<ASTNode>, RuleVector>> conditionExpressionRulePairs;
        
        ElementVector cases = rule->getMapElement("cases")->getVector();
        for(auto caseRulePair : cases){
        
        std::string conditionString = caseRulePair->getMapElement("condition")->getString();
        expressionTree.build(conditionString);
        std::shared_ptr<ASTNode> conditionExpressionRoot = expressionTree.getRoot();
        
        RuleVector caseRules;
        toRuleVec(game, caseRulePair->getMapElement("rules"), caseRules);
        conditionExpressionRulePairs.push_back({conditionExpressionRoot, caseRules});
        }
        
        ruleObject = std::make_shared<When>(conditionExpressionRulePairs);
        }
    } //freed here

該錯誤表明 std::shared_ptr 在上述代碼段的最后一個大括號處被釋放。

這是 when 規則:

class When : public Rule {
    std::shared_ptr<ASTNode> conditionRoot;

    std::map<std::shared_ptr<ASTNode>, RuleVector> condition_rule_pairs;
    std::map<std::shared_ptr<ASTNode>, RuleVector>::iterator condition_rule_pair;
    
    RuleVector::iterator rule;
    bool match = false;

public: 
    When(std::map<std::shared_ptr<ASTNode>, RuleVector>& conditon_rule_pairs);
    bool executeImpl(ElementSptr element, ElementMap elementsMap) final;
    void resetImpl() final;
};

所有其他規則都有效,並且能夠正確地將訪問者傳遞給根。 這里唯一的區別是我將每個案例的根存儲在一個向量中並將其傳遞給:

//rules.cpp in the `execute` function of the `when` rule
for (; conditionExpression_rule_pair != conditionExpression_rule_pairs.end(); conditionExpression_rule_pair++) {
conditionRoot = conditionExpression_rule_pair->first; //**this line gives the error**
conditionRoot->accept(resolver, elementsMap);

錯誤:

AddressSanitizer: heap-use-after-free on address 0x00010a902690 at pc 0x000104f83ec4 bp 0x00016b488550 sp 0x00016b488548
#0 0x104f83ec0 in std::__1::shared_ptr<ASTNode>::shared_ptr(std::__1::shared_ptr<ASTNode> const&) memory:3125
#1 0x104f687a4 in std::__1::shared_ptr<ASTNode>::shared_ptr(std::__1::shared_ptr<ASTNode> const&) memory:3127
#2 0x104f716b8 in std::__1::shared_ptr<ASTNode>::operator=(std::__1::shared_ptr<ASTNode> const&) memory:3246
#3 0x104f6fe34 in When::executeImpl(std::__1::shared_ptr<ListElement>, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::shared_ptr<ListElement>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::shared_ptr<ListElement> > > >) rules.cpp:105

問題是,我試圖在構造函數中將訪問者傳遞給根,它起作用了:

When::When(std::vector<std::pair<std::shared_ptr<ASTNode>&,RuleVector>>& conditionExpression_rule_pairs)

: conditionExpression_rule_pairs(conditionExpression_rule_pairs), 

conditionExpression_rule_pair(conditionExpression_rule_pairs.begin()),

rule(conditionExpression_rule_pair->second.begin()) {

TreePrinter t; //a visitor just to pretty print nodes
ElementMap elementsMap;
for(auto it : conditionExpression_rule_pairs){
it.first->accept(t, elementsMap);
std::cout << std::endl;

}
}

因此,不知何故,root 存在於when constructor中,但不存在於when execute中,因為它已從堆中釋放出來。 我懷疑這與根都存儲在向量中這一事實有關,因為對於其他規則,我只是傳入一個單數根,然后構造函數將其分配給另一個根,例如foreach規則:

Foreach::Foreach(std::shared_ptr<ASTNode> listExpressionRoot, RuleVector _rules, std::string elementName)
: listExpressionRoot(listExpressionRoot), rules(_rules), elementName(elementName) {
}

foreach中,我可以在execute function 中訪問根並傳遞訪問者,等等。

我嘗試了一切,但似乎無法擺脫when規則中的這個錯誤。 請幫忙。

我無法相信這。 我為此花了一周時間,並在兩個不同的論壇上發帖。

結果:

rule(conditionExpression_rule_pair->second.begin())

在 When 構造函數的初始化列表中,正在使用構造函數參數中的conditionExpression_rule_pair

When::When(std::vector<std::pair<std::shared_ptr<ASTNode>&,RuleVector>>& conditionExpression_rule_pairs)

而不是 when 規則中的實際字段。 很明顯,當構造函數超出 scope 並且迭代器將指向任何內容時,向量被刪除。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM