Opened 6 years ago

Last modified 6 years ago

#5196 new defect

Memory leak with inline arrays in when clauses

Reported by: anatoly.trosinenko@… Owned by: Lennart Ochel
Priority: high Milestone: Future
Component: FMI Version: v1.13.0-dev-nightly
Keywords: leak Cc:

Description

It seems there is a memory leak reproducible with a simple array defined inline in a while clause. I cannot say for sure, since it goes through the memory pool logic, but both valgrinding the FMUChecker with this FMU and looking at the generated source code suggest that the memory for this array is allocated but never freed.

How to reproduce

  • Take these files:

TestAllTrue.mo:

model TestAllTrue
  input Boolean x, y, z;
  output Boolean res;
equation
  when Modelica.Math.BooleanVectors.allTrue({x, y, z}) then
    res = true;
  end when;
end TestAllTrue;

TestAllTrue.mos:

print(buildModelFMU(TestAllTrue, "1.0", "me"));
print(getErrorString());
  • Compile it with omc TestAllTrue.mos Modelica TestAllTrue.mo
  • Run under Valgrind with
    mkdir -p /tmp/fmu # So valgrind can show symbols from .so-file from FMU
    valgrind --leak-check=full --show-leak-kinds=all ~/tmp/FMUChecker-2.0.3/build/fmuCheck.linux64 -z /tmp/fmu -h 0.01 -s 10000 -o /dev/null TestAllTrue.fmu
    

Among other, it will print

==32160== 29,360,128 bytes in 3 blocks are still reachable in loss record 24 of 24
==32160==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32160==    by 0x6C645EE: pool_malloc (in /tmp/fmu/binaries/linux64/TestAllTrue.so)
==32160==    by 0x6C58383: array_alloc_scalar_boolean_array (in /tmp/fmu/binaries/linux64/TestAllTrue.so)
==32160==    by 0x6C55301: TestAllTrue_eqFunction_4 (in /tmp/fmu/binaries/linux64/TestAllTrue.so)
==32160==    by 0x6C55869: TestAllTrue_functionAlgebraics (in /tmp/fmu/binaries/linux64/TestAllTrue.so)
==32160==    by 0x6C54FDC: TestAllTrue_fmiCompletedIntegratorStep (in /tmp/fmu/binaries/linux64/TestAllTrue.so)
==32160==    by 0x40C689: fmi1_me_simulate (in /home/trosinenko/tmp/FMUChecker-2.0.3/build/fmuCheck.linux64)
==32160==    by 0x40B99C: fmi1_check (in /home/trosinenko/tmp/FMUChecker-2.0.3/build/fmuCheck.linux64)
==32160==    by 0x408934: main (in /home/trosinenko/tmp/FMUChecker-2.0.3/build/fmuCheck.linux64)

this suggests where the leak is

  • Running the same command without Valgrind but with /usr/bin/time (not built-in time from bash) shows that
    with -s 10000   option -> 20536maxresident k
    with -s 1000000 option -> 1567340maxresident k
    
    this suggests that leak really exists :)

Analysis

Unpack the generated FMU and look at TestAllTrue.c:

/*
 equation index: 4
 type: SIMPLE_ASSIGN
 $whenCondition1 = Modelica.Math.BooleanVectors.allTrue({x, y, z})
 */
void TestAllTrue_eqFunction_4(DATA *data, threadData_t *threadData)
{
  TRACE_PUSH
  const int equationIndexes[2] = {1,4};
  boolean_array tmp0;
  array_alloc_scalar_boolean_array(&tmp0, 3, (modelica_boolean)data->localData[0]->booleanVars[2] /* x variable */, (modelica_boolean)data->localData[0]->booleanVars[3] /* y variable */, (modelica_boolean)data->localData[0]->booleanVars[4] /* z variable */);
  data->localData[0]->booleanVars[0] /* $whenCondition1 DISCRETE */ = omc_Modelica_Math_BooleanVectors_allTrue(threadData, tmp0);
  TRACE_POP
}

Looks like array_alloc_scalar_boolean_array was called but corresponding ..._free_... was not.

This was tested with FMU ME 1.0 and FMUChecker 2.0.3

Change History (2)

comment:1 by anatoly.trosinenko@…, 6 years ago

This seems to be reproducible without events:

package ArrayLeak
  function fillArray
    input Real x;
    output Real y[2];
  algorithm
    y := {x, 2 * x};
  end fillArray;
  
  model Test
    input Real u;
    output Real t[2];
  equation
    t = fillArray(u);
  end Test;
end ArrayLeak;

Is there any free_*_array_data(...) function implementations anywhere? I see only extern declarations in the sources/include/util/boolean_array.h inside unzipped FMU. On the other hand, it seems that simulation executable uses bounded amount of memory (or I run it incorrectly).

comment:2 by Martin Sjölund, 6 years ago

#5406 is the same bug. You just need to free the pool at some intervals like the regular simulations do.

Note: See TracTickets for help on using tickets.