PETScSNESSolver crashes when initialised and deleted without being used

Issue #417 resolved
Simone Pezzuto created an issue

Run this few times (crashes are random):

from fenics import PETScSNESSolver
solver = PETScSNESSolver()
del solver

The problem is a PETSc raw Vec, called f_tmp, which is not initialised but it is destroyed by the destructor. Now, this is actually odd, because VecDestroy tries to deallocate the memory even if the vector has not been VecCreated, and that's because the pointer (Vec is a pointer in PETSc internals) looks valid.

The solution is simple, i.e. set it to NULL during the construction:

diff --git a/dolfin/nls/PETScSNESSolver.cpp b/dolfin/nls/PETScSNESSolver.cpp
index 532df94..5a37c9c 100644
--- a/dolfin/nls/PETScSNESSolver.cpp
+++ b/dolfin/nls/PETScSNESSolver.cpp
@@ -124,6 +124,7 @@ PETScSNESSolver::PETScSNESSolver(std::string nls_type) :
   _snes_ctx.nonlinear_problem = NULL;
   _snes_ctx.xl = NULL;
   _snes_ctx.xu = NULL;
+  _snes_ctx.f_tmp = NULL;

   // Check that the requested method is known
   if (_methods.count(nls_type) == 0)

You can reproduce the problem outside DOLFIN with the following code (if you uncomment the commented line it works):

#include <petsc.h>
struct mysolver { Vec f; };
int main(void)
{
    PetscInitializeNoArguments();
    std::unique_ptr<mysolver> s(new mysolver);
    //s->f = NULL;
    if (s->f != NULL) VecDestroy(&s->f);
    PetscFinalize();
    return EXIT_SUCCESS;
}

Comments (4)

  1. Prof Garth Wells

    The initialisation of _snes_ctx member data should be done in a snes_ctx_t constructor. It should also have a destructor.

    That said, I can't see from the code in PETScSNESSolver why we need snes_ctx_t .

  2. Johan Hake

    We need this fix. I implemented a destructor and constructor to the private class (struct).

    Also the snes_ctx_t is needed to keep track of the original PETScVector, apparently for updating ghost values. Have a look at the comments in:

    PETScSNESSolver::FormFunction
    
  3. Log in to comment