diff --git a/src/certificatemodel.cpp b/src/certificatemodel.cpp index a2ce65b7fb90966512d70dc9dffe3c97998955cb..9eac4930b8b32188661ff793ef80c2caf3521d28 100644 --- a/src/certificatemodel.cpp +++ b/src/certificatemodel.cpp @@ -237,8 +237,18 @@ void CertificateNode::setStrings(const QString& col1, const QVariant& col2, cons CertificateNode* CertificateModelPrivate::createCategory(const QString& name, const QString& col2, const QString& tooltip ) { + QMutexLocker l(&m_CertLoader); const int idx = m_lTopLevelNodes.size(); + // This should be avoided whenever possible. Having a duplicate would be + // both a memory leak and a potential collision attack (far fetched). + // This code avoids leak, but has side effects. + if (m_hStrToCat.contains(name)) { + qWarning() << "Trying to create a certificate node with an already used id." + " This can have unforneen consequences"; + return m_hStrToCat[name]; + } + CertificateNode* n = new CertificateNode(idx, CertificateModel::NodeType::CATEGORY, nullptr, nullptr); n->setStrings(name,col2,tooltip); @@ -297,7 +307,7 @@ void CertificateModelPrivate::removeFromTree(Certificate* c, CertificateNode* ca CertificateNode* CertificateModelPrivate::getCategory(const Account* a) { - CertificateNode* cat = m_hAccToCat[a]; + CertificateNode* cat = m_hAccToCat.value(a); if (!cat) { cat = createCategory(a->alias(),QString(),QString()); @@ -321,7 +331,7 @@ CertificateNode* CertificateModelPrivate::addToTree(Certificate* cert, Account* void CertificateModelPrivate::regenChecks(Certificate* cert) { - CertificateNode* n = m_hNodes[cert]; + CertificateNode* n = m_hNodes.value(cert); if (!n) return; @@ -334,6 +344,7 @@ void CertificateModelPrivate::regenChecks(Certificate* cert) //[Re]generate the checks void CertificateModelPrivate::loadChecks(CertificateNode* checks, Certificate* cert) { + QMutexLocker locker(&m_CertLoader); const QModelIndex checksI(q_ptr->createIndex(checks->m_Index,static_cast<int>(CertificateModel::Columns::NAME ),checks)); //Clear the existing nodes @@ -368,13 +379,14 @@ void CertificateModelPrivate::loadChecks(CertificateNode* checks, Certificate* c CertificateNode* CertificateModelPrivate::addToTree(Certificate* cert, CertificateNode* category) { - QMutexLocker locker(&m_CertLoader); - if (!category) category = defaultCategory(); + // defaultCategory(); can request the mutex + QMutexLocker locker(&m_CertLoader); + //Do not add it twice - CertificateNode* node = CertificateModel::instance().d_ptr->m_hNodes[cert]; + CertificateNode* node = CertificateModel::instance().d_ptr->m_hNodes.value(cert); if (isPartOf(node, category)) return node; @@ -391,24 +403,41 @@ CertificateNode* CertificateModelPrivate::addToTree(Certificate* cert, Certifica //Lazy loaded function to reduce the overhead of this (mostly hidden) model node->m_fLoader = [this,node,cert]() { + CertificateNode* checks = nullptr; + { // mutex node->m_Col1 = cert->detailResult(Certificate::Details::PUBLIC_KEY_ID).toString(); node->m_IsLoaded = true; const QModelIndex index = q_ptr->createIndex(node->m_Index,static_cast<int>(CertificateModel::Columns::NAME ),node); + CertificateNode* details = nullptr; + //Insert the check and details categories + { // mutex + QMutexLocker locker(&m_CertLoader); q_ptr->beginInsertRows(index, 0, 1); - CertificateNode* details = new CertificateNode(static_cast<int>(CertificateModel::Columns::NAME ), CertificateModel::NodeType::DETAILS_CATEGORY, node, nullptr); - CertificateNode* checks = new CertificateNode(static_cast<int>(CertificateModel::Columns::VALUE), CertificateModel::NodeType::DETAILS_CATEGORY, node, nullptr); + details = new CertificateNode(static_cast<int>(CertificateModel::Columns::NAME ), CertificateModel::NodeType::DETAILS_CATEGORY, node, nullptr); + checks = new CertificateNode(static_cast<int>(CertificateModel::Columns::VALUE), CertificateModel::NodeType::DETAILS_CATEGORY, node, nullptr); details->setStrings(QObject::tr("Details"),QString(),QObject::tr("The content of the certificate") ); checks ->setStrings(QObject::tr("Checks") ,QString(),QObject::tr("Various security related information") ); node->m_lChildren << details; node->m_lChildren << checks; q_ptr->endInsertRows(); + } // mutex static const int detailsC(enum_class_size<Certificate::Details>()); - //Insert the details const QModelIndex detailsI(q_ptr->createIndex(details->m_Index,static_cast<int>(CertificateModel::Columns::NAME ),details)); + + // Make sure the lazy-loaded details have been created (otherwise it will deadlock) + for (const Certificate::Details detail : EnumIterator<Certificate::Details>()) { + cert->getName (detail); + cert->detailResult (detail); + cert->getDescription(detail); + } + + //Insert the details + { // mutex + QMutexLocker locker(&m_CertLoader); q_ptr->beginInsertRows(detailsI, 0, detailsC - 1); for (const Certificate::Details detail : EnumIterator<Certificate::Details>()) { CertificateNode* d = new CertificateNode(details->m_lChildren.size(), CertificateModel::NodeType::DETAILS, details, nullptr); @@ -419,6 +448,9 @@ CertificateNode* CertificateModelPrivate::addToTree(Certificate* cert, Certifica details->m_lChildren << d; } q_ptr->endInsertRows(); + } // mutex + + } // mutex //Insert the checks this->loadChecks(checks, cert); @@ -592,7 +624,7 @@ Certificate* CertificateModel::getCertificateFromPath(const QString& path, Accou CertificateNode* cat = d_ptr->getCategory(a); - Certificate* cert = d_ptr->m_hCertificates[path]; + Certificate* cert = d_ptr->m_hCertificates.value(path); if (!cert) { cert = new Certificate(path, Certificate::Type::NONE); @@ -603,7 +635,7 @@ Certificate* CertificateModel::getCertificateFromPath(const QString& path, Accou d_ptr->addToTree(cert,a); } - CertificateNode* node = d_ptr->m_hNodes[cert]; + CertificateNode* node = d_ptr->m_hNodes.value(cert); if (node) { if (node->m_pParent != cat) { @@ -618,7 +650,7 @@ Certificate* CertificateModel::getCertificateFromPath(const QString& path, Certi { const QString id = path; - Certificate* cert = d_ptr->m_hCertificates[id]; + Certificate* cert = d_ptr->m_hCertificates.value(id); //The certificate is not loaded yet if (!cert) { @@ -635,7 +667,7 @@ Certificate* CertificateModel::getCertificateFromPath(const QString& path, Certi Certificate* CertificateModel::getCertificateFromId(const QString& id, Account* a, const QString& category) { - Certificate* cert = d_ptr->m_hCertificates[id]; + Certificate* cert = d_ptr->m_hCertificates.value(id); //The certificate is not loaded yet if (!cert) { @@ -643,7 +675,7 @@ Certificate* CertificateModel::getCertificateFromId(const QString& id, Account* d_ptr->m_hCertificates[id.toLatin1()] = cert; if ((!a) && (!category.isEmpty())) { - CertificateNode* cat = d_ptr->m_hStrToCat[category]; + CertificateNode* cat = d_ptr->m_hStrToCat.value(category); if (!cat) { cat = d_ptr->createCategory(category, a?QString("%1 certificates").arg(a->alias()):QString(), QString()); @@ -760,7 +792,7 @@ QAbstractItemModel* CertificateModelPrivate::model(const Certificate* cert) cons { if (!cert) return nullptr; - return const_cast<CertificateModelPrivate*>(this)->getModelCommon(m_hNodes[cert]); + return const_cast<CertificateModelPrivate*>(this)->getModelCommon(m_hNodes.value(cert)); } /** @@ -771,7 +803,7 @@ QAbstractItemModel* CertificateModelPrivate::checksModel(const Certificate* cert if (!cert) return nullptr; - CertificateNode* node = m_hNodes[cert]; + CertificateNode* node = m_hNodes.value(cert); if (!node) return nullptr; @@ -827,7 +859,7 @@ QAbstractItemModel* CertificateModelPrivate::createKnownList(const Account* a) c QAbstractItemModel* CertificateModelPrivate::createBannedList(const Account* a) const { - QAbstractItemModel* m = m_hAccBan[a]; + QAbstractItemModel* m = m_hAccBan.value(a); if (m) return m; @@ -844,7 +876,7 @@ QAbstractItemModel* CertificateModelPrivate::createBannedList(const Account* a) QAbstractItemModel* CertificateModelPrivate::createAllowedList(const Account* a) const { - QAbstractItemModel* m = m_hAccAllow[a]; + QAbstractItemModel* m = m_hAccAllow.value(a); if (m) return m; @@ -868,9 +900,9 @@ bool CertificateModelPrivate::allowCertificate(Certificate* c, Account* a) createAllowedList(a); createBannedList(a); - CertificateNode* allow = m_hAccAllowCat [ a ]; - CertificateNode* ban = m_hAccBanCat [ a ]; - CertificateNode* sibling = m_hNodes [ c ]; + CertificateNode* allow = m_hAccAllowCat .value( a ); + CertificateNode* ban = m_hAccBanCat .value( a ); + CertificateNode* sibling = m_hNodes .value( c ); //Check if it's already there if (isPartOf(sibling, allow)) @@ -907,9 +939,9 @@ bool CertificateModelPrivate::banCertificate(Certificate* c, Account* a) createAllowedList(a); createBannedList(a); - CertificateNode* allow = m_hAccAllowCat [ a ]; - CertificateNode* ban = m_hAccBanCat [ a ]; - CertificateNode* sibling = m_hNodes [ c ]; + CertificateNode* allow = m_hAccAllowCat .value( a ); + CertificateNode* ban = m_hAccBanCat .value( a ); + CertificateNode* sibling = m_hNodes .value( c ); //Check if it's already there if (isPartOf(sibling, ban))