Mem checkup (#3083)

* clean up in testDatastructs

* avoid jump on unassigned mem in rxns

* set valgrind error exit code

* update suppressions

* clean up RDValue in testDict

* don't leak mol if parsing Maestro file fails

* don't leak mol if parsing PDB block fails

* cleanup leftover rxns in testReaction

* cleanup mol if CX extensions cannot be parsed

* cleanup leftover mols in smiTest1

* cleanup leftover mols in moldraw2DTest1

* cleanup leftover mols in testSubstructMatch

* make testEnumeration go easier on valgrind

* reduce R counts
This commit is contained in:
Ric
2020-04-17 11:48:58 -04:00
committed by GitHub
parent 66a38d3751
commit 39bcee635e
15 changed files with 351 additions and 116 deletions

View File

@@ -380,7 +380,7 @@ if(RDK_USE_BOOST_SERIALIZATION)
else()
set(Boost_LIBRARIES ${T_LIBS})
endif()
target_compile_definitions(rdkit_base INTERFACE -DRDK_USE_BOOST_SERIALIZATION)
target_compile_definitions(rdkit_base INTERFACE -DRDK_USE_BOOST_SERIALIZATION -DBOOST_SERIALIZATION_DYN_LINK)
endif()

View File

@@ -1,2 +1,2 @@
# For some reason, MEMORYCHECK_SUPPRESSIONS_FILE is not being caught, so I hardcoded it here
SET(MEMORYCHECK_COMMAND_OPTIONS "--tool=memcheck --time-stamp=yes --num-callers=20 --gen-suppressions=all --leak-check=full --show-reachable=no --trace-children=yes --suppressions=${RDKit_SOURCE_DIR}/Code/cmake/rdkit_valgrind.suppressions")
SET(MEMORYCHECK_COMMAND_OPTIONS "--tool=memcheck --error-exitcode=13 --time-stamp=yes --num-callers=20 --gen-suppressions=all --leak-check=full --show-reachable=no --trace-children=yes --suppressions=${RDKit_SOURCE_DIR}/Code/cmake/rdkit_valgrind.suppressions")

View File

@@ -1425,6 +1425,7 @@ void test16BitVectProps() {
RDValue newValue;
TEST_ASSERT(handler->read(ss, newValue));
TEST_ASSERT(from_rdvalue<ExplicitBitVect>(newValue) == bv);
newValue.destroy();
}
delete handlers[1];
}

View File

@@ -108,8 +108,8 @@ ChemicalReaction *RxnSmartsToChemicalReaction(
std::vector<std::size_t> pos;
for (std::size_t i = 0; i < text.length(); i++) {
if (text[i] == '>' && text[i-1] != '-') {
for (std::size_t i = 0; i < text.length(); ++i) {
if (text[i] == '>' && (i == 0 || text[i - 1] != '-')) {
pos.push_back(i);
}
}

View File

@@ -130,20 +130,24 @@ void testSamplers() {
void testEvenSamplers() {
EnumerationTypes::BBS bbs;
bbs.resize(3);
boost::uint64_t R1 = 6000;
boost::uint64_t R2 = 500;
boost::uint64_t R3 = 10000;
boost::uint64_t R1 = 600;
boost::uint64_t R2 = 50;
boost::uint64_t R3 = 1000;
boost::shared_ptr<ROMol> m(SmilesToMol("C=CCN=C=S"));
boost::shared_ptr<ROMol> m2(SmilesToMol("NCc1ncc(Cl)cc1Br"));
boost::shared_ptr<ROMol> m3(SmilesToMol("NCCCc1ncc(Cl)cc1Br"));
for (unsigned long i = 0; i < R1; ++i) {
bbs[0].push_back(boost::shared_ptr<ROMol>(SmilesToMol("C=CCN=C=S")));
bbs[0].push_back(m);
}
for (unsigned long i = 0; i < R2; ++i) {
bbs[1].push_back(boost::shared_ptr<ROMol>(SmilesToMol("NCc1ncc(Cl)cc1Br")));
bbs[1].push_back(m2);
}
for (unsigned long i = 0; i < R3; ++i) {
bbs[2].push_back(
boost::shared_ptr<ROMol>(SmilesToMol("NCCCc1ncc(Cl)cc1Br")));
bbs[2].push_back(m3);
}
ChemicalReaction rxn;

View File

@@ -6949,7 +6949,7 @@ bool check_bond_stereo(const ROMOL_SPTR &mol, unsigned bond_idx,
ROMOL_SPTR run_simple_reaction(const std::string &reaction,
const ROMOL_SPTR &reactant) {
const auto rxn = RxnSmartsToChemicalReaction(reaction);
std::unique_ptr<ChemicalReaction> rxn{RxnSmartsToChemicalReaction(reaction)};
TEST_ASSERT(rxn);
TEST_ASSERT(rxn->getNumReactantTemplates() == 1);
TEST_ASSERT(rxn->getNumProductTemplates() == 1);
@@ -7135,7 +7135,8 @@ void testOtherBondStereo() {
{ // Reaction changes order of the stereo bond
const std::string reaction(R"([C:1]=[C:2]>>[C:1]-[C:2])");
const auto rxn = RxnSmartsToChemicalReaction(reaction);
std::unique_ptr<ChemicalReaction> rxn{
RxnSmartsToChemicalReaction(reaction)};
TEST_ASSERT(rxn);
TEST_ASSERT(rxn->getNumReactantTemplates() == 1);
TEST_ASSERT(rxn->getNumProductTemplates() == 1);
@@ -7161,7 +7162,8 @@ void testOtherBondStereo() {
// (no directed bonds enclosing the double bond)
const std::string reaction(
R"([C:1]/[C:2]=[C:3]/[Br:4]>>[C:1][C:2]=[C:3]-[Br:4])");
const auto rxn = RxnSmartsToChemicalReaction(reaction);
std::unique_ptr<ChemicalReaction> rxn{
RxnSmartsToChemicalReaction(reaction)};
TEST_ASSERT(rxn);
TEST_ASSERT(rxn->getNumReactantTemplates() == 1);
TEST_ASSERT(rxn->getNumProductTemplates() == 1);
@@ -7190,7 +7192,8 @@ void testOtherBondStereo() {
}
{ // Reaction with 2 product sets
const std::string reaction(R"([C:1]=[C:2]>>[Si:1]=[C:2])");
const auto rxn = RxnSmartsToChemicalReaction(reaction);
std::unique_ptr<ChemicalReaction> rxn{
RxnSmartsToChemicalReaction(reaction)};
TEST_ASSERT(rxn);
TEST_ASSERT(rxn->getNumReactantTemplates() == 1);
TEST_ASSERT(rxn->getNumProductTemplates() == 1);
@@ -7218,7 +7221,8 @@ void testOtherBondStereo() {
TEST_ASSERT(check_bond_stereo(mol2, 2, 0, 4, Bond::BondStereo::STEREOE));
const std::string reaction(R"([C:1]=[C:2][Br:3]>>[C:1]=[C:2].[Br:3])");
const auto rxn = RxnSmartsToChemicalReaction(reaction);
std::unique_ptr<ChemicalReaction> rxn{
RxnSmartsToChemicalReaction(reaction)};
TEST_ASSERT(rxn);
TEST_ASSERT(rxn->getNumReactantTemplates() == 1);
TEST_ASSERT(rxn->getNumProductTemplates() == 2);
@@ -7245,7 +7249,8 @@ void testOtherBondStereo() {
const std::string reaction(
R"([Cl:4][C:1]=[C:2][Br:3]>>[C:1]=[C:2].[Br:3].[Cl:4])");
const auto rxn = RxnSmartsToChemicalReaction(reaction);
std::unique_ptr<ChemicalReaction> rxn{
RxnSmartsToChemicalReaction(reaction)};
TEST_ASSERT(rxn);
TEST_ASSERT(rxn->getNumReactantTemplates() == 1);
TEST_ASSERT(rxn->getNumProductTemplates() == 3);

View File

@@ -297,8 +297,6 @@ void addAtoms(const mae::IndexedBlock &atom_block, RWMol &mol) {
const auto ys = atom_block.getRealProperty(mae::ATOM_Y_COORD);
const auto zs = atom_block.getRealProperty(mae::ATOM_Z_COORD);
std::shared_ptr<mae::IndexedIntProperty> atomic_charges;
// atomic numbers, and x, y, and z coordinates
const auto size = atomic_numbers->size();
auto conf = new RDKit::Conformer(size);
@@ -346,6 +344,42 @@ void addBonds(const mae::IndexedBlock &bond_block, RWMol &mol) {
mol.addBond(bond, true);
}
}
void build_mol(RWMol &mol, mae::Block &structure_block, bool sanitize,
bool removeHs) {
const auto &atom_block = structure_block.getIndexedBlock(mae::ATOM_BLOCK);
addAtoms(*atom_block, mol);
const auto &bond_block = structure_block.getIndexedBlock(mae::BOND_BLOCK);
addBonds(*bond_block, mol);
// These properties need to be set last, as stereochemistry is defined here,
// and it requires atoms and bonds to be available.
set_mol_properties(mol, structure_block);
if (sanitize) {
if (removeHs) {
MolOps::removeHs(mol, false, false);
} else {
MolOps::sanitizeMol(mol);
}
} else {
// we need some properties for the chiral setup
mol.updatePropertyCache(false);
}
// If there are 3D coordinates, try to read more chiralities from them, but do
// not override the ones that were read from properties
bool replaceExistingTags = false;
if (mol.getNumConformers() && mol.getConformer().is3D()) {
MolOps::assignChiralTypesFrom3D(mol, -1, replaceExistingTags);
}
// Find more stereo bonds, assign labels, but don't replace the existing ones
MolOps::detectBondStereochemistry(mol, replaceExistingTags);
MolOps::assignStereochemistry(mol, replaceExistingTags);
}
} // namespace
MaeMolSupplier::MaeMolSupplier(std::shared_ptr<std::istream> inStream,
@@ -415,40 +449,15 @@ ROMol *MaeMolSupplier::next() {
throw FileParseException("All structures read from Maestro file");
}
auto *mol = new RWMol();
auto mol = new RWMol;
const auto atom_block = d_next_struct->getIndexedBlock(mae::ATOM_BLOCK);
addAtoms(*atom_block, *mol);
const auto bond_block = d_next_struct->getIndexedBlock(mae::BOND_BLOCK);
addBonds(*bond_block, *mol);
// These properties need to be set last, as stereochemistry is defined here,
// and it requires atoms and bonds to be available.
set_mol_properties(*mol, *d_next_struct);
if (df_sanitize) {
if (df_removeHs) {
MolOps::removeHs(*mol, false, false);
} else {
MolOps::sanitizeMol(*mol);
}
} else {
// we need some properties for the chiral setup
mol->updatePropertyCache(false);
try {
build_mol(*mol, *d_next_struct, df_sanitize, df_removeHs);
} catch (...) {
delete mol;
throw;
}
// If there are 3D coordinates, try to read more chiralities from them, but do
// not override the ones that were read from properties
bool replaceExistingTags = false;
if (mol->getNumConformers() && mol->getConformer().is3D()) {
MolOps::assignChiralTypesFrom3D(*mol, -1, replaceExistingTags);
}
// Find more stereo bonds, assign labels, but don't replace the existing ones
MolOps::detectBondStereochemistry(*mol, replaceExistingTags);
MolOps::assignStereochemistry(*mol, replaceExistingTags);
try {
d_next_struct = d_reader->next(mae::CT_BLOCK);
} catch (const mae::read_exception &e) {

View File

@@ -30,7 +30,12 @@
// flavor & 2 : Read each MODEL into a separate molecule.
namespace RDKit {
static Atom *PDBAtomFromSymbol(const char *symb) {
namespace {
// This is a macro to allow its use for C++ constants
#define BCNAM(A, B, C) (((A) << 16) | ((B) << 8) | (C))
Atom *PDBAtomFromSymbol(const char *symb) {
PRECONDITION(symb, "bad char ptr");
if (symb[0] == 'D' && !symb[1]) {
auto *result = new Atom(1);
@@ -45,8 +50,8 @@ static Atom *PDBAtomFromSymbol(const char *symb) {
return elemno > 0 ? new Atom(elemno) : (Atom *)nullptr;
}
static void PDBAtomLine(RWMol *mol, const char *ptr, unsigned int len,
unsigned int flavor, std::map<int, Atom *> &amap) {
void PDBAtomLine(RWMol *mol, const char *ptr, unsigned int len,
unsigned int flavor, std::map<int, Atom *> &amap) {
PRECONDITION(mol, "bad mol");
PRECONDITION(ptr, "bad char ptr");
std::string tmp;
@@ -304,9 +309,8 @@ static void PDBAtomLine(RWMol *mol, const char *ptr, unsigned int len,
info->setTempFactor(bfactor);
}
static void PDBBondLine(RWMol *mol, const char *ptr, unsigned int len,
std::map<int, Atom *> &amap,
std::map<Bond *, int> &bmap) {
void PDBBondLine(RWMol *mol, const char *ptr, unsigned int len,
std::map<int, Atom *> &amap, std::map<Bond *, int> &bmap) {
PRECONDITION(mol, "bad mol");
PRECONDITION(ptr, "bad char ptr");
@@ -415,7 +419,7 @@ static void PDBBondLine(RWMol *mol, const char *ptr, unsigned int len,
}
}
static void PDBTitleLine(RWMol *mol, const char *ptr, unsigned int len) {
void PDBTitleLine(RWMol *mol, const char *ptr, unsigned int len) {
PRECONDITION(mol, "bad mol");
PRECONDITION(ptr, "bad char ptr");
std::string title;
@@ -435,8 +439,8 @@ static void PDBTitleLine(RWMol *mol, const char *ptr, unsigned int len) {
}
}
static void PDBConformerLine(RWMol *mol, const char *ptr, unsigned int len,
Conformer *&conf, int &conformer_atmidx) {
void PDBConformerLine(RWMol *mol, const char *ptr, unsigned int len,
Conformer *&conf, int &conformer_atmidx) {
PRECONDITION(mol, "bad mol");
PRECONDITION(ptr, "bad char ptr");
@@ -472,13 +476,10 @@ static void PDBConformerLine(RWMol *mol, const char *ptr, unsigned int len,
}
}
// This is a macro to allow its use for C++ constants
#define BCNAM(A, B, C) (((A) << 16) | ((B) << 8) | (C))
// This function determines whether a standard atom name in
// in a recognized PDB amino acid should be chiral or not.
// This is used to avoid chirality on VAL.CG and LEU.CG.
static bool StandardPDBChiralAtom(const char *resnam, const char *atmnam) {
bool StandardPDBChiralAtom(const char *resnam, const char *atmnam) {
switch (BCNAM(resnam[0], resnam[1], resnam[2])) {
case BCNAM('G', 'L', 'Y'):
return false;
@@ -510,7 +511,7 @@ static bool StandardPDBChiralAtom(const char *resnam, const char *atmnam) {
return false;
}
static void StandardPDBResidueChirality(RWMol *mol) {
void StandardPDBResidueChirality(RWMol *mol) {
for (ROMol::AtomIterator atomIt = mol->beginAtoms();
atomIt != mol->endAtoms(); ++atomIt) {
Atom *atom = *atomIt;
@@ -546,12 +547,11 @@ void BasicPDBCleanup(RWMol &mol) {
}
}
RWMol *PDBBlockToMol(const char *str, bool sanitize, bool removeHs,
unsigned int flavor, bool proximityBonding) {
void parsePdbBlock(RWMol *&mol, const char *str, bool sanitize, bool removeHs,
unsigned int flavor, bool proximityBonding) {
PRECONDITION(str, "bad char ptr");
std::map<int, Atom *> amap;
std::map<Bond *, int> bmap;
RWMol *mol = nullptr;
Utils::LocaleSwitcher ls;
bool multi_conformer = false;
int conformer_atmidx = 0;
@@ -639,14 +639,14 @@ RWMol *PDBBlockToMol(const char *str, bool sanitize, bool removeHs,
}
if (!mol) {
return (RWMol *)nullptr;
return;
}
if (proximityBonding) {
ConnectTheDots(mol, ctdIGNORE_H_H_CONTACTS);
}
// flavor & 8 doesn't encode double bonds
if (proximityBonding || ((flavor & 8) != 0)) {
if (proximityBonding || flavor & 8) {
StandardPDBResidueBondOrders(mol);
}
@@ -666,6 +666,18 @@ RWMol *PDBBlockToMol(const char *str, bool sanitize, bool removeHs,
/* Set tetrahedral chirality from 3D co-ordinates */
MolOps::assignChiralTypesFrom3D(*mol);
StandardPDBResidueChirality(mol);
}
} // namespace
RWMol *PDBBlockToMol(const char *str, bool sanitize, bool removeHs,
unsigned int flavor, bool proximityBonding) {
RWMol *mol = nullptr;
try {
parsePdbBlock(mol, str, sanitize, removeHs, flavor, proximityBonding);
} catch (...) {
delete mol;
throw;
}
return mol;
}

View File

@@ -1688,6 +1688,7 @@ void test11DrawMolGrid() {
}
delete m1;
delete m2;
delete m3;
std::cerr << " Done" << std::endl;
}
@@ -1746,6 +1747,8 @@ void test12DrawMols() {
outs.flush();
}
{
delete mols[2];
delete mols[4];
mols[2] = nullptr;
mols[4] = nullptr;
MolDraw2DSVG drawer(750, 400, 250, 200);

View File

@@ -368,6 +368,7 @@ RWMol *SmilesToMol(const std::string &smiles,
SmilesParseOps::parseCXExtensions(*res, cxPart, pos);
} catch (const SmilesParseException &) {
if (params.strictCXSMILES) {
delete res;
throw;
}
}

View File

@@ -173,6 +173,7 @@ void testFail() {
CHECK_INVARIANT(!mol, smi);
} else {
CHECK_INVARIANT(mol, smi);
delete mol;
}
i++;
}
@@ -833,16 +834,19 @@ void testStereochem() {
mol = SmilesToMol(smi);
smi = MolToSmiles(*mol, 1);
TEST_ASSERT(refSmi == smi);
delete mol;
smi = "Cl[C@@H](F)/C=C(\\F)";
mol = SmilesToMol(smi);
smi = MolToSmiles(*mol, 1);
TEST_ASSERT(refSmi == smi);
delete mol;
smi = "Cl[C@@H](F)\\C=C(/F)";
mol = SmilesToMol(smi);
smi = MolToSmiles(*mol, 1);
TEST_ASSERT(refSmi == smi);
delete mol;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
@@ -879,6 +883,7 @@ void testIssue127() {
// std::cout << refSmi << " : " << tempStr << std::endl;
TEST_ASSERT(refSmi == tempStr);
delete mol2;
delete mol;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
@@ -1327,6 +1332,7 @@ void testIssue159() {
TEST_ASSERT(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOE);
TEST_ASSERT(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOZ);
TEST_ASSERT(mol->getBondWithIdx(8)->getStereo() == Bond::STEREOE);
delete mol;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
@@ -1343,17 +1349,19 @@ void testIssue175() {
mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getBondWithIdx(1)->getStereo() == Bond::STEREOE);
delete mol;
smi = "Cl\\C=C1CN/1";
mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getBondWithIdx(1)->getStereo() == Bond::STEREOE);
delete mol;
smi = "C/1=C/F.F1";
mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOZ);
delete mol;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
@@ -1417,6 +1425,7 @@ void testIssue180() {
TEST_ASSERT(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOZ);
smi = MolToSmiles(*mol, 1);
TEST_ASSERT(refSmi == smi);
delete mol;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
@@ -1452,6 +1461,7 @@ void testIssue184() {
smi = MolToSmiles(*mol, 1);
TEST_ASSERT(refSmi == smi);
delete mol;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
@@ -1524,6 +1534,7 @@ void testIssue185() {
TEST_ASSERT((*bondIt)->getStereo() == Bond::STEREOE);
}
}
delete mol;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
@@ -1562,6 +1573,7 @@ void testIssue191() {
smi = MolToSmiles(*mol, 1);
// std::cout << "ref: " << refSmi << " -> " << smi << std::endl;
TEST_ASSERT(refSmi == smi);
delete mol;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
@@ -1766,6 +1778,7 @@ void testBug1670149() {
TEST_ASSERT(mol->getAtomWithIdx(1)->getNumImplicitHs() == 2);
smi = MolToSmiles(*mol, false, false, -1);
TEST_ASSERT(smi == "C1CC[NH2+]C1");
delete mol;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
@@ -2095,6 +2108,7 @@ void testBug1844959() {
TEST_ASSERT(label == "S");
smi2 = MolToSmiles(*mol, true);
TEST_ASSERT(smi == smi2);
delete mol;
// now make sure it works with a reversed chiral tag:
smi = "C[C@@]12CNOC2.F1";
@@ -2132,6 +2146,7 @@ void testBug1844959() {
TEST_ASSERT(label == "R");
smi2 = MolToSmiles(*mol, true);
TEST_ASSERT(smi == smi2);
delete mol;
// ^^^^^^^^^^^^^^^^^^^^^^
// end of the set
// ----------------------
@@ -2182,6 +2197,7 @@ void testBug1844959() {
TEST_ASSERT(label == "R");
smi2 = MolToSmiles(*mol, true);
TEST_ASSERT(smi == smi2);
delete mol;
// now make sure it works with a reversed chiral tag:
smi = "C[C@@]12CNOC2.[H]1";
@@ -3307,6 +3323,7 @@ void testBug253() {
std::string csmiles1 = MolToSmiles(*m, true);
std::cerr << "--" << csmiles1 << std::endl;
TEST_ASSERT(csmiles1 == "C1CCC2(CC1)CCCCC2CCC1CCCC1");
delete m;
}
BOOST_LOG(rdInfoLog) << "done" << std::endl;
@@ -3329,6 +3346,7 @@ void testBug257() {
m = SmilesToMol(csmiles);
TEST_ASSERT(m);
TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::UNSPECIFIED);
delete m;
}
BOOST_LOG(rdInfoLog) << "done" << std::endl;
@@ -3992,11 +4010,13 @@ void testSmilesParseParams() {
std::string smiles = "CCCC the_name";
ROMol *m = SmilesToMol(smiles);
TEST_ASSERT(m);
delete m;
{ // it's ignored
SmilesParserParams params;
m = SmilesToMol(smiles, params);
TEST_ASSERT(m);
TEST_ASSERT(!m->hasProp(common_properties::_Name));
delete m;
}
{
SmilesParserParams params;

View File

@@ -1724,6 +1724,7 @@ void testGithub2570() {
std::vector<MatchVectType> matches;
TEST_ASSERT(SubstructMatch(*mol, *query, matches, uniquify,
recursionPossible, useChirality));
delete query;
}
{
const auto mol = R"([C@H](O)(F)Cl)"_smiles;
@@ -1740,6 +1741,7 @@ void testGithub2570() {
std::vector<MatchVectType> matches;
TEST_ASSERT(SubstructMatch(*mol, *query, matches, uniquify,
recursionPossible, useChirality));
delete query;
}
{
const auto mol = R"([C@](O)(F)(Cl)C)"_smiles;
@@ -1805,6 +1807,7 @@ void testEZVsCisTransMatch() {
TEST_ASSERT(check.second == SubstructMatch(*mol, *query, match,
recursionPossible,
useChirality));
delete query;
}
// Symmetrize stereoatoms
for (const auto &check : checks) {
@@ -1825,6 +1828,7 @@ void testEZVsCisTransMatch() {
TEST_ASSERT(check.second == SubstructMatch(*mol, *query, match,
recursionPossible,
useChirality));
delete query;
}
// Flip one stereoatom and the label
for (const auto &check : checks) {
@@ -1848,6 +1852,7 @@ void testEZVsCisTransMatch() {
TEST_ASSERT(check.second == SubstructMatch(*mol, *query, match,
recursionPossible,
useChirality));
delete query;
}
}

View File

@@ -706,6 +706,7 @@ void testCustomProps() {
TEST_ASSERT(handler->read(ss, newValue));
TEST_ASSERT(from_rdvalue<const Foo &>(newValue).bar == f.bar);
TEST_ASSERT(from_rdvalue<const Foo &>(newValue).baz == f.baz);
newValue.destroy();
}
delete handlers[1];
}

View File

@@ -0,0 +1,214 @@
#ifndef BOOST_SERIALIZATION_SINGLETON_HPP
#define BOOST_SERIALIZATION_SINGLETON_HPP
/////////1/////////2///////// 3/////////4/////////5/////////6/////////7/////////8
// singleton.hpp
//
// Copyright David Abrahams 2006. Original version
//
// Copyright Robert Ramey 2007. Changes made to permit
// application throughout the serialization library.
//
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// The intention here is to define a template which will convert
// any class into a singleton with the following features:
//
// a) initialized before first use.
// b) thread-safe for const access to the class
// c) non-locking
//
// In order to do this,
// a) Initialize dynamically when used.
// b) Require that all singletons be initialized before main
// is called or any entry point into the shared library is invoked.
// This guarentees no race condition for initialization.
// In debug mode, we assert that no non-const functions are called
// after main is invoked.
//
// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
# pragma once
#endif
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/noncopyable.hpp>
#include <boost/serialization/force_include.hpp>
#include <boost/archive/detail/auto_link_archive.hpp>
#include <boost/serialization/config.hpp>
#include <boost/archive/detail/abi_prefix.hpp> // must be the last header
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable : 4511 4512)
#endif
namespace boost {
namespace serialization {
//////////////////////////////////////////////////////////////////////
// Provides a dynamically-initialized (singleton) instance of T in a
// way that avoids LNK1179 on vc6. See http://tinyurl.com/ljdp8 or
// http://lists.boost.org/Archives/boost/2006/05/105286.php for
// details.
//
// singletons created by this code are guarenteed to be unique
// within the executable or shared library which creates them.
// This is sufficient and in fact ideal for the serialization library.
// The singleton is created when the module is loaded and destroyed
// when the module is unloaded.
// This base class has two functions.
// First it provides a module handle for each singleton indicating
// the executable or shared library in which it was created. This
// turns out to be necessary and sufficient to implement the tables
// used by serialization library.
// Second, it provides a mechanism to detect when a non-const function
// is called after initialization.
// make a singleton to lock/unlock all singletons for alteration.
// The intent is that all singletons created/used by this code
// are to be initialized before main is called. A test program
// can lock all the singletons when main is entereed. This any
// attempt to retieve a mutable instances while locked will
// generate a assertion if compiled for debug.
// note usage of BOOST_DLLEXPORT. These functions are in danger of
// being eliminated by the optimizer when building an application in
// release mode. Usage of the macro is meant to signal the compiler/linker
// to avoid dropping these functions which seem to be unreferenced.
// This usage is not related to autolinking.
class BOOST_SYMBOL_VISIBLE singleton_module :
public boost::noncopyable
{
private:
BOOST_DLLEXPORT static bool & get_lock() BOOST_USED {
static bool lock = false;
return lock;
}
public:
BOOST_DLLEXPORT static void lock(){
get_lock() = true;
}
BOOST_DLLEXPORT static void unlock(){
get_lock() = false;
}
BOOST_DLLEXPORT static bool is_locked(){
return get_lock();
}
};
template <class T>
class singleton : public singleton_module
{
private:
static void cleanup_func() {
delete static_cast<singleton_wrapper*> (&get_instance());
}
// use a wrapper so that types T with protected constructors
// can be used
class singleton_wrapper : public T {
public:
singleton_wrapper () {
#if !defined(BOOST_ALL_DYN_LINK) && !defined(BOOST_SERIALIZATION_DYN_LINK)
/* Static builds: We're in a single module, use atexit() to
* ensure destruction in reverse of construction.
* (In static builds the compiler-generated order may be wrong...) */
atexit(&cleanup_func);
#endif
}
};
/* This wrapper ensures the instance is cleaned up when the
* module is wound down. (The cleanup of the static variable
* in get_instance() may happen at the wrong time.) */
struct instance_and_cleanup
{
T& x;
instance_and_cleanup(T& x) : x(x) {
}
~instance_and_cleanup() {
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_SERIALIZATION_DYN_LINK)
/* Shared builds: The ordering through global variables is
* sufficient.
* However, avoid atexit() as it may cause destruction order
* issues here. */
singleton<T>::cleanup_func();
#endif
}
};
static instance_and_cleanup m_instance_and_cleanup;
// include this to provoke instantiation at pre-execution time
static void use(T const *) {}
static T & get_instance() {
// Use a heap-allocated instance to work around static variable
// destruction order issues: this inner singleton_wrapper<>
// instance may be destructed before the singleton<> instance.
// Using a 'dumb' static variable lets us precisely choose the
// time destructor is invoked.
// The destruction itself is handled by m_instance_cleanup (for
// shared builds) or in an atexit() function (static builds).
static singleton_wrapper* t = new singleton_wrapper;
// refer to instance, causing it to be instantiated (and
// initialized at startup on working compilers)
BOOST_ASSERT(! is_destroyed());
// note that the following is absolutely essential.
// commenting out this statement will cause compilers to fail to
// construct the instance at pre-execution time. This would prevent
// our usage/implementation of "locking" and introduce uncertainty into
// the sequence of object initializaition.
use(& m_instance_and_cleanup.x);
return static_cast<T &>(*t);
}
static bool & get_is_destroyed(){
static bool is_destroyed;
return is_destroyed;
}
public:
BOOST_DLLEXPORT static T & get_mutable_instance(){
BOOST_ASSERT(! is_locked());
return get_instance();
}
BOOST_DLLEXPORT static const T & get_const_instance(){
return get_instance();
}
BOOST_DLLEXPORT static bool is_destroyed(){
return get_is_destroyed();
}
BOOST_DLLEXPORT singleton(){
get_is_destroyed() = false;
}
BOOST_DLLEXPORT ~singleton() {
get_is_destroyed() = true;
}
};
template<class T>
typename singleton< T >::instance_and_cleanup singleton< T >::m_instance_and_cleanup (
singleton< T >::get_instance());
} // namespace serialization
} // namespace boost
#include <boost/archive/detail/abi_suffix.hpp> // pops abi_suffix.hpp pragmas
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#endif // BOOST_SERIALIZATION_SINGLETON_HPP

View File

@@ -3,8 +3,8 @@
# inside a conda environment. Used relevant software was:
#
# - valgrind: v3.14.0 final, built from git sources under the same env.
# - Boost libs: conda package, v1.67.0 (py36_4)
# - Compiler: conda package, gxx_linux-64 7.2.0 (h550dcbe_27)
# - Boost libs: v1.68.0 (py36)
# - Compiler: gxx_linux-64 6.4.0
#
# CMake command/options was:
# cmake .. \
@@ -27,61 +27,21 @@
{
Avalon #1
Memcheck:Cond
fun:SmilesBranch
...
fun:SmilesBranch
fun:MOLToSMIExt
fun:CanSmilesStep
fun:CanSmiles
fun:_ZN11AvalonTools14getCanonSmilesERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEbi
fun:_ZN11AvalonTools14getCanonSmiles*
}
{
Avalon #2
Memcheck:Cond
fun:SmilesBranch
fun:MOLToSMIExt
fun:CanSmilesStep
fun:CanSmiles
fun:_ZN11AvalonTools14getCanonSmilesERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEbi
}
{
Avalon #3
Memcheck:Cond
fun:SmilesBranch
...
fun:SmilesBranch
fun:MOLToSMIExt
fun:MOLToSMI
fun:_ZN11AvalonTools14getCanonSmilesERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEbi
}
{
Avalon #4
Memcheck:Cond
fun:SmilesBranch
fun:MOLToSMIExt
fun:MOLToSMI
fun:_ZN11AvalonTools14getCanonSmilesERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEbi
}
{
Avalon #5
Memcheck:Cond
fun:SmilesBranch
fun:SmilesBranch
fun:SmilesBranch
fun:SmilesBranch
fun:MOLToSMIExt
fun:MOLToSMI
fun:_ZN11AvalonTools14getCanonSmilesERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEbi
}
{
Avalon #6
Memcheck:Cond
fun:SmilesBranch
fun:SmilesBranch
fun:SmilesBranch
fun:SmilesBranch
fun:MOLToSMIExt
fun:CanSmilesStep
fun:CanSmiles
fun:_ZN11AvalonTools14getCanonSmilesERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEbi
fun:_ZN11AvalonTools14getCanonSmiles*
}
{
boost::singleton #1