sbmlteam / libsbml

LibSBML is a native library for reading, writing and manipulating files and data streams containing the Systems Biology Markup Language (SBML). It offers language bindings for C, C++, C#, Java, JavaScript, MATLAB, Perl, PHP, Python, R and Ruby.

Home Page:https://sbml.org/software/libsbml

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Segmentation fault when doing function expansion and unit inference after conversion to L3V2

avandecreme opened this issue · comments

The following program segfault when fed the following uncompressed file

#include <stdio.h>
#include <sbml/SBMLTypes.h>
#include "util.h"

int main (int argc, char *argv[])
{
  if (argc != 2)
  {
    printf("Usage: readSBML filename\n");
    return 2;
  }

  const char * filename = argv[1];
  SBMLDocument_t *d = readSBML(filename);

  int success = SBMLDocument_setLevelAndVersion(d, 3, 2);
  printf("Success: %d\n", success);

  ConversionProperties_t* props;

  props = ConversionProperties_create();
  ConversionOption_t * expandFuncDefOpt = ConversionOption_create("expandFunctionDefinitions");
  ConversionProperties_addOption(props, expandFuncDefOpt);
  SBMLDocument_convert(d, props);
  ConversionOption_free(expandFuncDefOpt);
  ConversionProperties_free(props);

  props = ConversionProperties_create();
  ConversionOption_t * inferUnitsOpt = ConversionOption_create("inferUnits");
  ConversionProperties_addOption(props, inferUnitsOpt);
  SBMLDocument_convert(d, props);
  ConversionOption_free(inferUnitsOpt);
  ConversionProperties_free(props);

  SBMLDocument_free(d);
}

From what I gathered, it is because tempUD1 is set to NULL here:

UnitDefinition * tempUD1 = inverseFunctionOnUnits(tempUD, child1,

The reason for that is that inverseFunctionOnUnits calls UnitDefinition::divide on two UnitDefinitions having different level and version (L2V4 like the original doc and L3V2 like the converted one), so we are falling in the following branch:
else if ( (ud1->getLevel() != ud2->getLevel()) ||

I found two ways to avoid the crash:

  1. move the level/version conversion after function expansion and unit inference
  2. keep level/version conversion first but group function expansion and unit inference into one convert call like this:
  props = ConversionProperties_create();
  ConversionOption_t * expandFuncDefOpt = ConversionOption_create("expandFunctionDefinitions");
  ConversionProperties_addOption(props, expandFuncDefOpt);
  ConversionOption_t * inferUnitsOpt = ConversionOption_create("inferUnits");
  ConversionProperties_addOption(props, inferUnitsOpt);
  SBMLDocument_convert(d, props);
  ConversionOption_free(expandFuncDefOpt);
  ConversionOption_free(inferUnitsOpt);
  ConversionProperties_free(props);

Having level/version conversion in between function expansion and unit inference also segfault.

Thanks very much for this. As far as I know you are the first person to have used the UnitInference since I wrote it some years ago and there may well be undiscovered issues. But thank you for the detailed report this is very helpful