[MOAB-dev] [cgma-dev] Problems with ReadCGM
Steve Jackson
sjackson at cae.wisc.edu
Tue Nov 3 12:40:16 CST 2009
After some adventures in debugging, I have tracked down the ReadCGM
problem I described a few days ago. Recall that the problem occurred
when MOAB's ReadCGM::load_file() called CGM's
GeometryQueryEngine::get_graphics(). If the CGM library linked with
MOAB was originally built against CUBIT, the wrong GeometryQueryEngine
method would be called, resulting in strange behavior and a cryptic
error message.
The problem is that the interface for CGM's GeometryQueryEngine (and
its subclass AcisQueryEngine) differs in the CUBIT library and in the
CGM headers.
File I/O functions exported from CUBIT:
> > nm -C libcubiti19.so | grep -E 'AcisQueryEngine::(im|ex)
> port_solid_model'
> 0000000000ed91d0 T AcisQueryEngine::export_solid_model
> (DLIList<TopologyBridge*>&, char const*, char const*, CubitString
> const&, char const*)
> 0000000000eda040 T AcisQueryEngine::import_solid_model(char const*,
> char const*, DLIList<TopologyBridge*>&, bool, char const*, bool,
> bool, bool, bool, bool, bool)
The same functions exported in a CGM installation that was build on
Acis, not CUBIT:
> > nm -C libcgm.a | grep -E 'AcisQueryEngine::(im|ex)port_solid_model'
> 0000000000007020 T AcisQueryEngine::export_solid_model
> (DLIList<TopologyBridge*>&, char const*, char const*, CubitString
> const&, char const*)
> 0000000000000010 T AcisQueryEngine::export_solid_model
> (DLIList<TopologyBridge*>&, char*&, int&, bool)
> 0000000000010420 T AcisQueryEngine::import_solid_model(char const*,
> char const*, DLIList<TopologyBridge*>&, bool, char const*, bool,
> bool, bool, bool, bool, bool)
> 0000000000000020 T AcisQueryEngine::import_solid_model
> (DLIList<TopologyBridge*>&, char const*, int)
So two new (overloaded) functions have been added since libcubiti19.so
was built. These new functions were introduced to
GeometryQueryEngine.hpp in CGM svn revision 3108.
When CGM is compiled with these newer headers, and linked against
CUBIT, the vtable for any GeometryQueryEngine object is wrong. This
means that calls to virtual functions on such an object will execute
incorrect methods.
Jason has told me that MOAB's ReadCGM should not be using the
GeometryQueryEngine at all, and there should be a way to invoke the
same functionality without going through this wrongly-linked class.
I'll plan to make this change later today. CGM probably needs some
clear documentation about classes that users should avoid to ensure
their code works correctly with a CUBIT-based CGM. Alternatively, CGM
could use configure-time checks to avoid defining symbols which the
geometry library underneath it cannot provide.
Gory details for developers:
I came at this problem not knowing that the GeometryQueryEngine
interface has changed, and I discovered the changes by groveling over
the GeometryQueryEngine vtables in two different CGM installations
(one built with CUBIT, one with Acis). Since the headers were the
same, these vtables should have listed the class's virtual methods in
the same order. The Acis-based vtable had these two extra functions
near the beginning, so the indices of entries later in the vtable were
off by two with respect to the CUBIT-based vtable.
Viewing a C++ object's vtable is somewhat tricky. The following web
page that discusses how to do it from gdb (see the subsection
"Debugger? What's that?"): http://www.mikeash.com/?page=pyblog/hacking-c-from-c.html
For a refresher on vtable layout, Wikipedia has a good article: http://en.wikipedia.org/wiki/Virtual_method_table
This problem would not have manifested if the newly-added functions
appeared at the _end_ of the vtable, but as luck would have it, they
came at the beginning. Compilers build a vtable by adding functions in
the order they are encountered during compilation, and the import/
export solid model functions are the first ones declared in
GeometryQueryEngine.
Tim, let me know if you think this debugging experience merits a
Fathom blog post.
~S
On Oct 27, 2009, at 11:51 , Steve Jackson wrote:
> The backtrace is suspicious. The error message comes from the
> following context:
>
> (gdb) bt
> #0 0x00007f776266b54b in AcisQueryEngine::get_BODY ()
> from /home/cnerg/opt/cubit10.2/64/bin/libcubiti19.so
> #1 0x00007f77626757dc in AcisQueryEngine::rotate ()
> from /home/cnerg/opt/cubit10.2/64/bin/libcubiti19.so
> #2 0x0000000000510a21 in ReadCGM::load_file (this=0x1191790,
> cgm_file_name=0x57335c "out.sat", opts=@0x7fff6bdce050,
> subset_list=0x0,
> subset_list_length=0, file_id_tag=0x0) at ../../code/ReadCGM.cpp:
> 393
> #3 0x000000000041c74c in MBCore::serial_load_file (this=0x118f2d0,
> file_name=0x57335c "out.sat", file_set=@0x7fff6bdce0e8,
> opts=@0x7fff6bdce050, subsets=0x0, num_sets=0, id_tag=0x0)
> at ../../code/MBCore.cpp:442
> #4 0x000000000041cb88 in MBCore::load_file (this=0x118f2d0,
> file_name=0x57335c "out.sat", file_set=@0x7fff6bdce0e8,
> options=0x57335b "", set_tag_name=0x0, set_tag_vals=0x0,
> num_set_tag_vals=0) at ../../code/MBCore.cpp:411
> #5 0x0000000000410b51 in main () at test.cpp:18
>
> Stack frame #2 is the get_graphics call:
> 393 CubitStatus s = gqe->get_graphics( curve, count, &data,
> faceting_tol);
>
> So it seems like AcisQueryEngine::rotate() is being called instead
> of AcisQueryEngine::get_graphics(). These are both virtual
> functions within GeometryQueryEngine, so it's possible that there's
> some vtable corruption, but I'm not sure how to deal with that.
>
> For what it's worth, I'm compiling on a 64-bit host using gcc
> 4.3.2. Cubit is 64-bit version 10.2. Could this be related to the
> MOAB-CGM coupling issues being discussed on the cgm mailing list
> right now?
> ~S
>
>
> On Oct 26, 2009, at 10:07 PM, Tim Tautges wrote:
>
>> This might be related to calling the wrong overloaded function in
>> CGM, for get_graphics or something related to it.
>>
>> Could you run the cubit-based code under gdb, stop in
>> GeometryQueryEngine::get_graphics (all instances, if multiple), and
>> print a stack trace? That would help determine which variants are
>> being called on the way down to the function.
>>
>> - tim
>>
>> Steve Jackson wrote:
>>> I have an issue with ReadCGM that's been puzzling me for a couple
>>> of days. Perhaps someone on this list can help me determine the
>>> problem.
>>> Below is a simple program that loads an acis .sat geometry into
>>> MOAB. When MOAB is compiled with an acis-based CGM, the code
>>> below works fine. However, when MOAB is compiled against a cubit-
>>> based CGM, the code below fails.
>>>> #include "MBCore.hpp"
>>>> #include <iostream>
>>>>
>>>> int main(){
>>>>
>>>> MBErrorCode rval;
>>>> MBEntityHandle file_set;
>>>> MBCore* MBI = new MBCore();
>>>>
>>>> rval = MBI->load_file("geom.sat", file_set, "", NULL, 0, 0);
>>>> if (MB_SUCCESS != rval) {
>>>> std::cerr << "Couldn't read file. " << std::endl;
>>>> return rval;
>>>> }
>>>>
>>>> return 0;
>>>> }
>>> The initial failure occurs in ReadCGM::load_file, at line 393 of
>>> ReadCGM.cpp. The first call to gqe->get_graphics() produces an
>>> error message (below) and returns failure. This in turn causes
>>> ReadCGM::load_file() to fail.
>>> The error message produced within the get_graphics() call is:
>>>> ERROR: In AcisQueryEngine::get_Body
>>>> Body is not a BodyACIS.
>>> Note that get_graphics() is being called with a Curve object, not
>>> a Body.
>>> The error happens predictably and seems to occur with any .sat
>>> file I provide. My CGM is built against Cubit 10.22, and MOAB is
>>> the latest revision from SVN. I also tried compiling MOAB with
>>> svn revision 3005, just before the last major revision to
>>> ReadCGM.cpp, but got the same error.
>>> Has anyone encountered this issue before?
>>> Thanks,
>>> ~S
More information about the moab-dev
mailing list