Dans le cadre de ma bibliothèque Chemharp, j'essaye d'intégrer un bibliothèque externe à la mienne. Cette bibliothèque est un plugin de VMD, dont l'interface est décrite dans ce fichier.
Seulement, quand je lance mon test, j'ai une segfault. J'utilise LLDB pour débugger, et voici la transcription d'une session :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | $ lldb ./tests/molfile (lldb) target create "./tests/molfile" Current executable set to './tests/molfile' (x86_64). (lldb) run Process 13976 launched: './tests/molfile' (x86_64) Process 13976 stopped * thread #1: tid = 0xef61, 0x00000001001988d6 libchemharp.0.1.0.dylib`harp::Molfile<(this=0x0000000100810420, timestep=0x00007fff5fbfd050, frame=0x00007fff5fbfd428)0>::molfile_to_frame(molfile_timestep_t const&, harp::Frame&) + 310 at Molfile.cpp:178, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0) frame #0: 0x00000001001988d6 libchemharp.0.1.0.dylib`harp::Molfile<(this=0x0000000100810420, timestep=0x00007fff5fbfd050, frame=0x00007fff5fbfd428)0>::molfile_to_frame(molfile_timestep_t const&, harp::Frame&) + 310 at Molfile.cpp:178 175 176 auto& positions = frame.positions(); 177 for (size_t i=0; i<static_cast<size_t>(natoms); i++) { -> 178 positions[i][0] = timestep.coords[3*i]; 179 positions[i][1] = timestep.coords[3*i + 1]; 180 positions[i][2] = timestep.coords[3*i + 2]; 181 } (lldb) print timestep (molfile_timestep_t) $0 = { abiversion = 16834048 type = 0x0000000000000000 name = 0x4170000041700000 "" prettyname = 0x42b4000041700000 "" author = 0x42b4000042b40000 "" majorv = 0 minorv = 0 is_reentrant = 1606407208 } (lldb) print timestep (molfile_timestep_t) $1 = { coords = 0x000000010100de00 velocities = 0x0000000000000000 A = 15 B = 15 C = 15 alpha = 90 beta = 90 gamma = 90 physical_time = 0 } |
Le problème, c'est que LLDB m'interprete le même objet comme provenant de 2 struct différentes … En effet le premier affichage correspond à un vmd_plugin_t
, décrit ici.
Mon code appelant (Attention, c'est encore en cours et pas finalisé!) : (Molfile.hpp)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | /* * Chemharp, an efficient IO library for chemistry file formats * Copyright (C) 2015 Guillaume Fraux * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/ */ #ifndef HARP_FORMAT_MOLFILE_HPP #define HARP_FORMAT_MOLFILE_HPP #include "Format.hpp" #include "Dynlib.hpp" #include "TrajectoryFactory.hpp" #include <memory> extern "C" { #include "vmdplugin.h" #include "molfile_plugin.h" } namespace harp { enum MolfileFormat { PDB, LAMMPS, }; /*! * @class Molfile formats/Molfile.hpp formats/Molfile.cpp * * Use of VMD Molfile plugins as format reader/writer. */ template <MolfileFormat F> class Molfile : public Format { public: Molfile(); ~Molfile(); virtual void read(File* file, Frame& frame) override; virtual std::string description() const override; virtual size_t nsteps(File* file) const override; private: /// Convert a molfile timestep to a chemharp frame void molfile_to_frame(const molfile_timestep_t& timestep, Frame& frame); /// Open the file at the given path if needed void open_file_if_needed(const std::string& path) const; /// Dynamic library associated with the VMD plugin Dynlib lib; /// VMD molfile plugin molfile_plugin_t* plugin; typedef int (*init_function_t)(void); typedef int (*register_function_t)(void*, vmdplugin_register_cb); /// Function to call at in the destructor init_function_t fini_fun; /// The last file name mutable std::string last_file_name; /// The file handler mutable void* file_handler; /// The number of atoms in the last trajectory read mutable int natoms; REGISTER_FORMAT; }; } #endif |
Et Molfile.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | #include <map> #include <cstdlib> #include "formats/Molfile.hpp" #include "Frame.hpp" using namespace harp; /******************************************************************************/ struct plugin_data_t { std::string format; std::string lib_name; bool have_velocities; }; static std::map<MolfileFormat, plugin_data_t> molfile_plugins { {PDB, {"PDB", "pdbplugin.so", false}}, }; struct plugin_reginfo_t { void* plugin; }; static int register_plugin(void *v, vmdplugin_t *p) { plugin_reginfo_t *r = static_cast<plugin_reginfo_t *>(v); if (std::string(MOLFILE_PLUGIN_TYPE) != std::string(p->type)) throw PluginError("Wrong plugin type"); r->plugin = static_cast<void *>(p); return VMDPLUGIN_SUCCESS; } static std::string libpath(const std::string& lib_name){ // First look for the CHRP_MOLFILES environement variable if(const char* MOLFILE_DIR = std::getenv("CHRP_MOLFILES")) { return MOLFILE_DIR + lib_name; } else { // Use the compile-time macro CHRP_MOLFILES_DIR return CHRP_MOLFILES_DIR + lib_name; } } /******************************************************************************/ template <MolfileFormat F> Molfile<F>::Molfile() : plugin(nullptr), fini_fun(nullptr), last_file_name(""), file_handler(nullptr), natoms(0){ // Open the library lib = Dynlib(libpath(molfile_plugins[F].lib_name)); // Get the pointer to the initialization function auto init_fun = lib.symbol<init_function_t>("vmdplugin_init"); if (init_fun()) throw PluginError("Could not initialize the " + molfile_plugins[F].format + " plugin."); // Get the pointer to the registration function auto register_fun = lib.symbol<register_function_t>("vmdplugin_register"); // Get the pointer to the freeing function fini_fun = lib.symbol<init_function_t>("vmdplugin_fini"); plugin_reginfo_t reginfo; reginfo.plugin = nullptr; // The first argument here is passed as the first argument to register_plugin ... if (register_fun(®info, register_plugin)) throw PluginError("Could not register the " + molfile_plugins[F].format + " plugin."); plugin = static_cast<molfile_plugin_t*>(reginfo.plugin); // Check the ABI version of the loaded plugin if (plugin->abiversion != vmdplugin_ABIVERSION) throw PluginError("The ABI version does not match! Please recompile " "chemharp or provide another plugin"); // Check that needed functions are here if ((plugin->open_file_read == NULL) || (plugin->read_next_timestep == NULL) || (plugin->close_file_read == NULL)) throw PluginError("The " + molfile_plugins[F].format + " plugin does not have read capacities"); } template <MolfileFormat F> Molfile<F>::~Molfile(){ if (file_handler) { plugin->close_file_read(file_handler); } fini_fun(); } template <MolfileFormat F> std::string Molfile<F>::description() const { return "Molfile-based reader for the " + molfile_plugins[F].format + "format"; } template <MolfileFormat F> void Molfile<F>::open_file_if_needed(const std::string& path) const { if (path != last_file_name){ last_file_name = path; // Cleanup if (file_handler) { plugin->close_file_read(file_handler); file_handler = nullptr; } file_handler = plugin->open_file_read(last_file_name.c_str(), plugin->name, &natoms); } if (!file_handler) { throw FileError("Could not open the file: " + path + " with VMD molfile"); } } template <MolfileFormat F> void Molfile<F>::read(File* file, Frame& frame){ open_file_if_needed(file->filename()); molfile_timestep_t timestep; timestep.coords = new float[natoms]; if (molfile_plugins[F].have_velocities) timestep.velocities = new float[natoms]; if (timestep.coords == NULL || (molfile_plugins[F].have_velocities && timestep.velocities) ) throw FormatError("Error allocating memory. Sorry ..."); int result = plugin->read_next_timestep(file_handler, natoms, ×tep); if (result != MOLFILE_SUCCESS){ delete[] timestep.coords; delete[] timestep.velocities; throw FormatError("Error while reading the file " + last_file_name + " using Molfile format " + molfile_plugins[F].format); } molfile_to_frame(timestep, frame); delete[] timestep.coords; delete[] timestep.velocities; } template <MolfileFormat F> size_t Molfile<F>::nsteps(File* file) const { open_file_if_needed(file->filename()); size_t n = 0; int result = MOLFILE_SUCCESS; while (true) { result = plugin->read_next_timestep(file_handler, natoms, NULL); if (result == MOLFILE_SUCCESS) n++; else break; } // We need to close and re-open the file plugin->close_file_read(file_handler); file_handler = plugin->open_file_read(last_file_name.c_str(), plugin->name, &natoms); return n; } template <MolfileFormat F> void Molfile<F>::molfile_to_frame(const molfile_timestep_t& timestep, Frame& frame){ auto cell = UnitCell(timestep.A, timestep.B, timestep.C, timestep.alpha, timestep.beta, timestep.gamma); frame.cell(cell); auto& positions = frame.positions(); for (size_t i=0; i<static_cast<size_t>(natoms); i++) { positions[i][0] = timestep.coords[3*i]; positions[i][1] = timestep.coords[3*i + 1]; positions[i][2] = timestep.coords[3*i + 2]; } if (molfile_plugins[F].have_velocities){ auto& velocities = frame.velocities(); for (size_t i=0; i<static_cast<size_t>(natoms); i++) { velocities[i][0] = timestep.velocities[3*i]; velocities[i][1] = timestep.velocities[3*i + 1]; velocities[i][2] = timestep.velocities[3*i + 2]; } } // TODO: topology } /******************************************************************************/ // Instanciate the templates template class harp::Molfile<PDB>; // Redefine the registering macros #undef REGISTER #undef REGISTER_EXTENSION #define REGISTER(format_t, name) \ template<> bool format_t::_registered_format_ = \ TrajectoryFactory::register_format(name, { \ FORMAT_CREATOR(format_t), \ nullptr \ }); #define REGISTER_EXTENSION(format_t, extension) \ template<> bool format_t::_registered_extension_ = \ TrajectoryFactory::register_extension(extension, { \ FORMAT_CREATOR(format_t), \ nullptr \ }); /******************************************************************************/ REGISTER(Molfile<PDB>, "PDB"); REGISTER_EXTENSION(Molfile<PDB>, ".pdb"); |
Et dans le même goût, mais encore plus fort, une autre session LLDB :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $ lldb ./tests/molfile (lldb) target create "./tests/molfile" Current executable set to './tests/molfile' (x86_64). (lldb) run Process 14008 launched: './tests/molfile' (x86_64) Process 14008 stopped * thread #1: tid = 0xf878, 0x00000001001988d6 libchemharp.0.1.0.dylib`harp::Molfile<(this=0x0000000100908510, timestep=0x00007fff5fbfd050, frame=0x00007fff5fbfd428)0>::molfile_to_frame(molfile_timestep_t const&, harp::Frame&) + 310 at Molfile.cpp:178, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0) frame #0: 0x00000001001988d6 libchemharp.0.1.0.dylib`harp::Molfile<(this=0x0000000100908510, timestep=0x00007fff5fbfd050, frame=0x00007fff5fbfd428)0>::molfile_to_frame(molfile_timestep_t const&, harp::Frame&) + 310 at Molfile.cpp:178 175 176 auto& positions = frame.positions(); 177 for (size_t i=0; i<static_cast<size_t>(natoms); i++) { -> 178 positions[i][0] = timestep.coords[3*i]; 179 positions[i][1] = timestep.coords[3*i + 1]; 180 positions[i][2] = timestep.coords[3*i + 2]; 181 } (lldb) print timestep.coords[0] error: no member named 'coords' in '<anonymous struct>' error: 1 errors parsing expression (lldb) print timestep.coords[0] (float) $0 = 0.416999996 (lldb) |
Voilà, je me demandais si vous aviez une idée pour avoir d'où pouvait provenir ce genre de bug, que je soupçonne d'être relié à ma segfault …