How can I validate a STEP file?

Hello,

I got great help from this forum before. Thank you!

We are using Open CASCADE to read step files. I followed the samples from OCCT and was able to read in good STEP files.

However, I also need to deal with the case that the user is providing corrupted STEP files.

Right now, it just crashes at "aReader.TransferRoot(n);". I was not able to catch anything even I used try...catch... I attached this corrupt STEP file as corrupt.step along with my question.

 

I tried the following ways:

1. As the document says, I used aReader.PrintCheckLoad() and aReader.PrintCheckTransfer() as samples do. Neither of those give me anything. Then it crashes at aReader.TransferRoot(n). From the comments, it seems those two functions will print something on stdout? I've directed stdout to file so I assume that all the printf/cout can be seen in that file.

2. I used "OSD::SetSignal(Standard_False);". By doing this, magically, for the same corrupted STEP file, aReader.TransferRoot(n) doesn't have problem (Actually I don't understand why it doesn't have problem. I even didn't use try...catch). Then I could use BRep_Tool::IsClosed(Sh) to test if the TopoDS_Shape is closed. If not, I can throw my own exception. This way seems working fine on Windows. However, on unix, this setting seems to have very big impact on our whole software. Other components (outside of STEP reader) started to throw for SIGSEGV. I cannot only scope the setting to our STEP reading functionality. Is there a way that I could undo "OSD::SetSignal" when I leave the STEP reader code area?

3. We used to have some legacy code that tries to do the validation work:

  Standard_Boolean stepValidator(const STEPControl_Reader& reader)
  {	
	  Handle_XSControl_WorkSession thesession = reader.WS();
	  Interface_CheckIterator checks;
	  if (!thesession->IsLoaded()) 
	  {
		  return false;
	  }
	  Interface_CheckTool cht(thesession->Graph());
	  checks = cht.CompleteCheckList();

	  Standard_Boolean noErrors = checks.IsEmpty(true);
	  
	  return noErrors;
  }

 However the problem is, it also catches some OK files. For example, for the file (attached : OK.step) if I do not use the validation code, I am able to read it without problem. The reason I am saying it is an OK file but good file is I am able to see some small problem when opening it using SolidWorks.

 

So what is the best way to validate a STEP before doing TransferRoot? 

Thank you very much!

-Xing

Attachments: 
Kirill Gavrilov's picture

Your question is confusing - "validating" STEP is quite complicated thing, and I suppose the only thing you are bothered with is a crash on broken file.
I would say:

  • In general, API should not crash even on corrupted file.
    You may register bugs on OCCT bugtracker if you can reproducing the issue on the latest release.
    There are Draw Harness commands for importing STEP files, which can be used for checking if this problem occurs only within application-specific code or also within Draw Harness.
  • OSD::SetSignal() has no magic in it - it activates redirection of asynchronous exceptions (like access violation errors) into synchronous C++ exceptions.
    This improves application robustness, survival in corner cases, but in general it protects from crashes in invalid code (which lacks protection from unexpected results),
    and this survival is not guarantied (application may still crash or work incorrectly).
  • There is no need to ask if STEP file is valid or not.
    Importing STEP/IGES/other file basically consists of 2 steps - file reading (parsing) and translation.
    Each step returns the state (enumeration), which should be checked for success before going further - it looks like you are ignoring this check.
xing gao's picture

Hi Kirill,

It is impressive that how prompt and good your reply is! Cannot thank you enough!

1. Yes, you are right. I am bothered with an un-catchable crash on broken STEP files.

2. I think I did check for the returned states. They catch a lot of broken files, but not all of them. My code is showing below:

STEPControl_Reader aReader;
aReader.WS()->TransferReader()->TransientProcess()->SetTraceLevel(2);
Interface_Static::SetCVal("xstep.cascade.unit", "M");
IFSelect_ReturnStatus status = aReader.ReadFile(fileNameStr);

if (status == IFSelect_RetError || status == IFSelect_RetFail || status == IFSelect_RetVoid)
  throw UnknownReadError(); //It is our own exception.

aReader.PrintCheckLoad(Standard_False, IFSelect_ItemsByEntity); //I still do not understand what it does

Standard_Integer nbr = aReader.NbRootsForTransfer();

aReader.PrintCheckTransfer(Standard_False, IFSelect_ItemsByEntity); //I still do not understand what it does
 
for (Standard_Integer n = 1; n <= nbr; n++)
{
  Standard_Boolean res = aReader.TransferRoot(n); // The problem is for the STEP file corrupt.STEP, it crashes within this.
  if (!res)
    throw UnknownReadError(); //It is our own exception.
}

// Collecting resulting entities
Standard_Integer nbs = aReader.NbShapes();

....

3. [Question] Thank you for the suggestion of submitting a bug report. I will be doing that. At the meantime, is it possible that I can have any workaround to catch/eliminate the crash from TransferRoot? (I know maybe this is not easy to answer without digging even deeper. Please ignore me if my question doesn't make sense to you...)

4. [Question] As I am not seeing anything from PrintCheckLoad and PrintCheckTransfer, do I still need those? Is it a way to deal with broken files?

Best Regards!

Xing

Kirill Gavrilov's picture

4. [Question] As I am not seeing anything from PrintCheckLoad and PrintCheckTransfer, do I still need those? Is it a way to deal with broken files?

Sorry, I have never used these functions, so have no idea what they do.

2. I think I did check for the returned states. They catch a lot of broken files, but not all of them. My code is showing below:

The function returns only one enum value on success, but you are enumerating fail codes instead, and not all of them, which looks strange.

3. [Question] Thank you for the suggestion of submitting a bug report. I will be doing that. At the meantime, is it possible that I can have any workaround to catch/eliminate the crash from TransferRoot?

If try/catch does not work, then it is an issue in code which might corrupt memory - there is no robust way for catching such thing in C/C++, the code should be fixed. Patches for OCCT are welcome!

Note that I don't see any crashes on the given model in Open CASCADE CAD Assistant - import fails without a crash.

xing gao's picture

Thank you so much Kirill!

If I use OSD::SetSignal() I could also catch error status for that file.

Our usage of OCCT is very simple. Pretty much like just 50 lines of code...

I will dig more into the OCCT source code and see if something is going wrong.

Many thanks!

Xing