LLDB se trompe de struct

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

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(&reginfo, 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, &timestep);

    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 …

Édité par Luthaf

Mon Github — Tuto Homebrew — Article Julia

+0 -0
Auteur du sujet

Oui, en effet. En gros le code appelle le constructeur (sur le tas, au cas où cela ait une importance), puis la fonction read, qui cause cette segfault. Ces appels sont cachés dans une hiérarchie de classes, donc le code exact importe peu.

Mon Github — Tuto Homebrew — Article Julia

+0 -0
Auteur du sujet

Bon j'ai résolu ma segfault (les vecteurs n'était pas alloués, ou pas à la bonne taille …), mais le problème d'affichage dans LLDB reste le même.

Je marque comme résolu, mais je veux bien savoir ce qui se passe, si vous avez des idées !

Mon Github — Tuto Homebrew — Article Julia

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte