File indexing completed on 2024-05-12 05:43:26

0001 /*
0002     Copyright (C) 2015 Volker Krause <vkrause@kde.org>
0003 
0004     This program is free software; you can redistribute it and/or modify it
0005     under the terms of the GNU Library General Public License as published by
0006     the Free Software Foundation; either version 2 of the License, or (at your
0007     option) any later version.
0008 
0009     This program is distributed in the hope that it will be useful, but WITHOUT
0010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
0012     License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program.  If not, see <https://www.gnu.org/licenses/>.
0016 */
0017 
0018 #include "config-elf-dissector.h"
0019 #include "virtualdtorcheck.h"
0020 
0021 #include <elf/elffileset.h>
0022 #if HAVE_DWARF
0023 #include <dwarf/dwarfinfo.h>
0024 #include <dwarf/dwarfdie.h>
0025 #include <dwarf/dwarfcudie.h>
0026 #include <dwarf/dwarftypes.h>
0027 
0028 #include <dwarf.h>
0029 #endif
0030 
0031 #include <algorithm>
0032 #include <iostream>
0033 
0034 void VirtualDtorCheck::findImplicitVirtualDtors(ElfFileSet* fileSet)
0035 {
0036 #if HAVE_DWARF
0037     for (int i = 0; i < fileSet->size(); ++i) {
0038         const auto file = fileSet->file(i);
0039         if (!file->dwarfInfo())
0040             continue;
0041         foreach (const auto die, file->dwarfInfo()->compilationUnits())
0042             findImplicitVirtualDtors(die);
0043     }
0044 
0045     // implicit virtual dtors in implementation files are not a problem
0046     m_results.erase(
0047         std::remove_if(m_results.begin(), m_results.end(), [](const Result &res) {
0048             return res.sourceFilePath.endsWith(QLatin1String(".cpp"))
0049                 || res.sourceFilePath.endsWith(QLatin1String(".c"))
0050                 || res.sourceFilePath.endsWith(QLatin1String(".cxx"));
0051         }), m_results.end()
0052     );
0053 #endif
0054 }
0055 
0056 void VirtualDtorCheck::findImplicitVirtualDtors(DwarfDie* die)
0057 {
0058 #if HAVE_DWARF
0059     const bool isCandidate =
0060         die->tag() == DW_TAG_subprogram &&
0061         die->attribute(DW_AT_external).toBool() &&
0062         die->attribute(DW_AT_declaration).toBool() &&
0063         die->attribute(DW_AT_artificial).toBool() &&
0064         die->attribute(DW_AT_virtuality).value<DwarfVirtuality>() == DwarfVirtuality::Virtual &&
0065         die->name().startsWith('~');
0066 
0067     if (isCandidate) {
0068         const auto fullName = die->fullyQualifiedName();
0069         const auto it = std::find_if(m_results.begin(), m_results.end(), [&fullName](const Result& res) {
0070             return res.fullName == fullName;
0071         });
0072         const auto *typeDie = die->attribute(DW_AT_containing_type).value<DwarfDie*>();
0073         if (it == m_results.end()) {
0074             const Result res = {
0075                 fullName,
0076                 typeDie ? typeDie->sourceFilePath() : QString(),
0077                 typeDie ? typeDie->attribute(DW_AT_decl_line).toInt() : 0
0078             };
0079             m_results.push_back(res);
0080         } else if ((*it).sourceFilePath.isEmpty() && typeDie) {
0081             (*it).sourceFilePath = typeDie->sourceFilePath();
0082             (*it).lineNumber = typeDie->attribute(DW_AT_decl_line).toInt();
0083         }
0084     }
0085 
0086     const auto children = die->children();
0087     for (const auto child : children) {
0088         if (child->tag() != DW_TAG_subprogram &&
0089             child->tag() != DW_TAG_class_type &&
0090             child->tag() != DW_TAG_structure_type &&
0091             child->tag() != DW_TAG_namespace)
0092             continue;
0093         findImplicitVirtualDtors(child);
0094     }
0095 #endif
0096 }
0097 
0098 void VirtualDtorCheck::printResults() const
0099 {
0100     for (const auto &res : m_results) {
0101         std::cout << res.fullName.constData() << " at " << qPrintable(res.sourceFilePath);
0102         if (res.lineNumber)
0103             std::cout << ':' << res.lineNumber;
0104         std::cout << std::endl;
0105     }
0106 }
0107 
0108 void VirtualDtorCheck::clear()
0109 {
0110     m_results.clear();
0111 }
0112 
0113 const QVector< VirtualDtorCheck::Result >& VirtualDtorCheck::results() const
0114 {
0115     return m_results;
0116 }