Ticket #1478 (closed defect: fixed)

Opened 2 years ago

Last modified 2 years ago

Corrupted method: segmentation fault

Reported by: josp Owned by: josp
Priority: highest Milestone: Mantainance
Component: Kernel Version: 3.1
Severity: blocker Keywords:
Cc:

Description

The following code give rise segmentation fault within tol:

#Require GuiTools;

Real RealSquare( Real x, Set args )
{
  Real sqX = x*x;
  WriteLn( "El cuadrado de " << x << " es " << sqX );
  sqX
};

Real GuiTools::MenuManager::defineMenuCommand
( "Real",
  [[ Text name = "Real_SQ",
     Text label = "Cuadrado del Real",
     Real flagGroup = 0,
     Code CmdInvoke = RealSquare ]]
);

Real a = 1;

GuiTools::MenuManager::invokeEntry( "Real_SQ", [[ a ]] );

the error is:

<E>
ERROR: [1] Corrupted method RealSquare
Possibly this problem is due to a non standard use of OOP, if this function was assigned to a member of type Code of a NameBlock or Class instance that has been destroyed already.</E>
[Call stack]
Segmentation fault

I will try to isolate it from GuiTools.

Change History

Changed 2 years ago by josp

valgrind output is:

==15625== 
==15625== Invalid read of size 4
==15625==    at 0x5A0D6F0: BNameBlock::EnsureIsAssigned() const (nameblock.cpp:303)
==15625==    by 0x5A4DAED: BSyntaxObject::FullName() const (syn.cpp:421)
==15625==    by 0x5A21A47: BUserFunction::FullName() const (oprimp.cpp:1521)
==15625==    by 0x59CA0C5: BUserFunction::ShowCallStack() (opr.cpp:973)
==15625==    by 0x5868C92: Error(BText const&) (out.cpp:455)
=

Changed 2 years ago by josp

The following code reproduce the error message but not the segmentation fault:

Class @A {
  Set _.commands = Copy( Empty );
  Real Invoke( Real x )
  {
    Code action = _.getCode( ? );
    action( x )
  };

  Code _.getCode( Real void )
  {
    _.commands::CmdInvoke
  };
  
  Static @A New( NameBlock args )
    {
      @A n = [[ Set _.commands = [[ Code CmdInvoke = args::CmdInvoke ]] ]]
    }
};

Real SQ_Real( Real x )
{
  Real x * x
};

@A opt = @A::New( [[ Code CmdInvoke = SQ_Real ]] );

Real opt::Invoke( 2 );

Changed 2 years ago by josp

This is even a smaller piece of code:

Real SetAA( NameBlock args )
{
  Real 1
};

Real SQ_Real( Real x )
{
  Real x * x
};

Real SetAA( [[ Code CMD = SQ_Real ]] );

Real SQ_Real( 1 );

Changed 2 years ago by vdebuen

  • status changed from new to closed
  • resolution set to fixed

(In [4341]) Fixes #1478
If BUserCode has different Name or Level than BOperator, it can't be a method

Changed 2 years ago by josp

(In [4342]) refs #1478, regressive test

Changed 2 years ago by pgea

El problema con los Code es el mismo que con los TimeSet, (véanse #1451, #1470 y #1471) por el empeño de no gestionar los objetos mediante referencias (véase #1431) sino a través de nuevos objetos que se apoyan en otros existentes previos.

Compárense los dos ejemplos siguientes:

Real fun1(Real x) { x*x };
NameBlock m = {
  NameBlock n1 = [[
    Code fun2 = fun1
  ]];
  NameBlock n2 = [[
    Code fun = n1::fun2
  ]]
};
Real m::fun(1);

que a pesar de funcionar da el error:

ERROR: [1] Corrupted method fun1
Possibly this problem is due to a non standard use of OOP, if this function was assigned to a member of type Code of a NameBlock or Class instance that has been destroyed already.

y (válido para v3.1 en adelante):

Real fun1(Real x) { x*x };
NameBlock m = {
  NameBlock n1 = [[
    @Code fun2 = @Code(fun1)
  ]];
  NameBlock n2 = [[
    @Code fun = @Code($(n1::fun2))
  ]]
};
Real {
  @Code aux = m::fun;
  $aux(1)
};

Changed 2 years ago by vdebuen

Partamos de la base de que aquí nadie se empeña en nada, porque eso es faltar al respeto y dudar de la profesionalidad de los desarrolladores de TOL.

Con todos mis respetos debo decirte que estás mezclando churras con meninas, pues no tiene nada que ver una cosa con la otra y además no se puede pretender que los objetos sean a la vez referencias.

Para empezar no tenemos punteros ni referencias como en C u otros lenguajes porque para eso hubiéramos hecho todo en C++ desde el principio y que lo aprendiera todo el mundo y a ver a dónde hubiéramos llegado.

Pero en cualquier caso es tautológicamente imposible que un objeto sea una referencia de otro del mismo tipo. Un objeto puede contener una referencia pero no puede serlo. Los lenguajes que admiten punteros y referencias lo hacen como tipos distintos nominados mediante prefijos u operadores.

Los conjuntos son la única forma de gestionar los objetos como referencias en TOL y no puede haber ninguna otra. En particular los @<type> son más prácticos y elegantes pero no dejan de ser un Set.

Este error se debe a que en el momento de la creación de un NameBlock resulta terriblemente complicado distinguir un miembro Code de un método. Sólo es posible aplicar reglas heurísticas y con las últimas añadidas se resuelve el problema.

Changed 2 years ago by vdebuen

(In [4353]) Refs #1478
Removing traces

Changed 2 years ago by vdebuen

(In [4354]) Fixes #1478 in 3.1

Changed 2 years ago by josp

(In [4361]) refs #1478, los campos CmdInvoke y CmdCheckState se pueden pasar como Code o @Code.

Changed 2 years ago by josp

  • status changed from closed to reopened
  • resolution fixed deleted

El siguiente código, todavía genera una caída en TOL (solo en linux)

#Require GuiTools;

Real {
  Real RealSquare( Real x, Set args )
  {
    Real sqX = x*x;
    WriteLn( "El cuadrado de " << x << " es " << sqX );
    sqX
  };
  
  // con esto se genera el segmentation fault 
  NameBlock auxiliar = [[
    Code RealSquare
  ]];
  
  Real GuiTools::MenuManager::defineMenuCommand("Real", 
    [[ Text name = "Real_SQ",
       Text label = "Cuadrado del Real",
       Real flagGroup = 0,
       Code CmdInvoke = RealSquare ]])
};

Real GuiTools::MenuManager::invokeEntry( "Real_SQ", [[ 3 ]] );

genera la salida ya vista en el enunciado del ticket:

<E>
ERROR: [1] Corrupted method RealSquare
Possibly this problem is due to a non standard use of OOP, if this function was assigned to a member of type Code of a NameBlock or Class instance that has been destroyed already.</E>
[Call stack]
Segmentation fault

prestar atención al mensaje de Segmentation fault emitido justo en el momento de sacar la traza del error.

Un código parecido pero que si logra a sacar la traza del stack es este:

#Require GuiTools;

Real {
  Real F1( Real x, Set args )
  {
    WriteLn( "Ejecutando F1 " << x );
    Real 1
  };

  // para fastidiar
  NameBlock auxiliar = [[
    Code F1
  ]];
  
  Real GuiTools::MenuManager::defineMenuCommand("Real", 
    [[ Text name = "MnuF1",
       Text label = "Solo F1",
       Code CmdInvoke = F1 ]])
};

Real GuiTools::MenuManager::invokeEntry( "MnuF1", [[ 3 ]] );

genera la traza siguiente:

<E>
ERROR: [1] Corrupted method F1
Possibly this problem is due to a non standard use of OOP, if this function was assigned to a member of type Code of a NameBlock or Class instance that has been destroyed already.</E>
[Call stack]
[3] Real F1 (Real x, Set args)
[2] Real option::option::inst::invoke (Anything objOrSelection)
[1] Real GuiTools::MenuManager::invokeEntry (Text optionName, Set objOrSelection)
Ejecutando F1 3

Changed 2 years ago by josp

  • owner changed from vdebuen to josp
  • status changed from reopened to accepted

Changed 2 years ago by josp

(In [4370]), al limpiar un NameBlock se debe establecer a NULL el NameBlock del BOperator si este comparte el NameBlock con el miembro Code que lo referencia.

Changed 2 years ago by josp

(In [4372]) refs #1478, more check on the test

Changed 2 years ago by josp

(In [4373]) refs #1478, porting test to branch 3.1

Changed 2 years ago by josp

(In [4375]) refs #1478, porting [4370] from trunk.

Changed 2 years ago by vdebuen

  • status changed from accepted to closed
  • resolution set to fixed
Note: See TracTickets for help on using tickets.