/* * Copyright (C) 2015 Andrei Karas * * This file is part of Paranoid null checker. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "analysis/checks.h" #include "logger.h" #include "analysis/analysis.h" #include "analysis/expression.h" #include "analysis/reports.h" #include "analysis/walkitem.h" #include "nodes/cst/string_cst.h" #include "nodes/expr/addr_expr.h" #include "nodes/expr/call_expr.h" #include #include "localconsts.h" namespace Analysis { void getCallFunctionStringArgs(CallExprNode *node, std::vector &arr) { FOR_EACH (it, node->args) { Node *arg = skipNop(it); if (arg == ADDR_EXPR) { AddrExprNode *addr = static_cast(arg); if (!addr->args.empty() && addr->args[0] == STRING_CST) { arr.push_back(addr->args[0]->label); } } } } std::string mergeCollection(const std::set &col) { std::string str; FOR_EACH(it, col) { str.append("'").append(it).append("',"); } return str; } void reportCollections(Node *node, const std::string &name, std::set col1, std::set col2) { std::string str1 = mergeCollection(col1); std::string str2 = mergeCollection(col2); reportCollectionsDifferent(node, name, str1, str2); } void checkStateEqual(Node *node, const std::string &name, std::set col1, std::set col2) { FOR_EACH (it, col1) { if (isNotIn(it, col2)) { reportCollections(node, name, col1, col2); return; } } FOR_EACH (it, col2) { if (isNotIn(it, col1)) { reportCollections(node, name, col1, col2); return; } } } void checkStateIn(Node *node, const std::string &name, const std::set &col1, const std::set &col2) { } #define convertCollection(col) \ if (name == #col) \ { \ return wi.col; \ } std::set getCollection(Node *node, const std::string &name, const WalkItem &wi) { convertCollection(needCheckNullVars) else convertCollection(knownVars) else convertCollection(knownNullVars) else convertCollection(knownNonNullVars) else convertCollection(removeNullVarsAll) else convertCollection(removeNullVars) else convertCollection(addNullVars) else convertCollection(checkedThenNullVars) else convertCollection(checkedThenNonNullVars) else convertCollection(checkedElseNullVars) else convertCollection(checkedElseNonNullVars) else { reportWrongCheck(node); return std::set(); } } std::set getLinkedCollection(Node *node, const std::string &name, const std::string &var, WalkItem wi) { if (name == "linkedVars") { return wi.linkedVars[var]; } else if (name == "linkedReverseVars") { std::set tmpSet; if (isIn(var, wi.linkedReverseVars)) tmpSet.insert(wi.linkedReverseVars[var]); return tmpSet; } else { reportWrongCheck(node); return std::set(); } } std::set splitArgs(std::string args, const int startIndex) { std::set tokens; size_t idx = 0; int cnt = 0; while ((idx = args.find(" ")) != std::string::npos) { if (cnt >= startIndex) tokens.insert(args.substr(0, idx)); args = args.substr(idx + 1); cnt ++; } if (!args.empty()) tokens.insert(args); return tokens; } void checkState(CallExprNode *node, const WalkItem &wi) { if (!node) return; std::vector args; getCallFunctionStringArgs(node, args); if (args.size() != 3) { reportWrongCheck(node); return; } std::string name = args[1]; std::set col1; std::set col2; if (name == "linkedVars" || name == "linkedReverseVars") { const size_t idx = args[2].find(" "); std::string var; if (idx == std::string::npos) { var = args[2]; args[2] = std::string(); } else { var = args[2].substr(0, idx); args[2] = args[2].substr(idx + 1); } col1 = getLinkedCollection(node, name, var, wi); col2 = splitArgs(args[2], 0); } else { col1 = getCollection(node, name, wi); if (isIn("this", col1)) { col1.erase("this"); } col2 = splitArgs(args[2], 0); } if (args[0] == "=") checkStateEqual(node, name, col1, col2); else if (args[1] == "in") checkStateIn(node, name, col1, col2); else reportWrongCheck(node); } }