[cgma-dev] [MOAB-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 cgma-dev mailing list