If an exception happens, the detachThread() never happens, which would
leave the interpreter in an inconsistent state. The best fix would be to
write a small class with a destructor method that will do the detach thread
when the variable leaves the scope.

Rick

On Sun, Jul 27, 2025 at 6:51 AM Rony G. Flatscher <rony.flatsc...@wu.ac.at>
wrote:

> It seems that the following patch fixes the reported crash:
>
> Index: interpreter/runtime/Interpreter.cpp
> ===================================================================
> --- interpreter/runtime/Interpreter.cpp (revision 12998)
> +++ interpreter/runtime/Interpreter.cpp (working copy)
> @@ -235,11 +235,15 @@
>          // to shut down so that the package manager can unload
>          // the libraries (it needs to pass a RexxThreadContext
>          // pointer out to package unloaders, if they are defined)
> -        InstanceBlock instance;
> +        InstanceBlock tmpInstance;
> +        tmpInstance.instance->InterpreterInstance::attachThread();
> +
>          // run whatever uninits we can before we start releasing the 
> libraries
>          memoryObject.lastChanceUninit();
>
>          PackageManager::unload();
> +
> +        tmpInstance.instance->InterpreterInstance::detachThread();
>      }
>      catch (ActivityException)
>      {
>
> Any comments, suggestions?
>
> ---rony
>
>
> On 23.12.2023 18:03, Rony G. Flatscher wrote:
>
> Since last August a crash got reported in
> <https://sourceforge.net/p/oorexx/bugs/1872/>
> <https://sourceforge.net/p/oorexx/bugs/1872/> which can be easily
> reproduced by following the directions there. Using the supplied simple
> C++-only program will work flawlessly if invoked simply as
>
> testTerminate.exe
>
> it will run flawlessly using 250 Rexx interpreter instances to execute a
> simple script (issuing a single dot on stdout) and then terminate it on the
> same thread.
>
> However if supplying an argument to that test program (source got uploaded
> with #1872 as well), then the termination of the Rexx interpreter instance
> occurs on a separate thread and will cause the crash upon terminating the
> second Rexx interpreter instance on a separate thread:
>
> testTerminate.exe 
> anyArgumentSufficesToRunTheRIIOnSeparateThreadAndCauseTheCrash
>
> The relevant Windows code is:
>
> ... cut ...
> // from 
> <https://stackoverflow.com/questions/1981459/using-threads-in-c-on-windows-simple-example>
>  
> <https://stackoverflow.com/questions/1981459/using-threads-in-c-on-windows-simple-example>,
> // also 
> <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread>
>  
> <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread>
> // #include <windows.h>
>
> DWORD WINAPI ThreadFunc(void* data) {
>   // Do stuff.  This will be the first function called on the new thread.
>   // When this function returns, the thread goes away.  See MSDN for more 
> details.
>
>     RexxInstance *instance = (RexxInstance *) data;
>     // uncommenting the following statement, makes it run
>     *// fprintf(stderr, "ThreadFunc(), arrived: terminating instance [%p]\n", 
> instance);fflush(stderr);
> *
>     // Now wait for the interpreter to terminate and we are done.
>     instance->Terminate();
>
>     // fprintf(stderr, "ThreadFunc(), leaving: terminating instance [%p]\n", 
> instance);fflush(stderr);
>
>   return 0;
>
> ... cut ...
>
>         if (argc>1) // if argument given terminate on separate thread
>         {
>             void *data = interpreter;
>             HANDLE thread = CreateThread(NULL, 0, ThreadFunc, data, 0, NULL);
>             if (thread)
>             {
>                 fprintf(stderr, "Created [%d], thread [%p] for terminating 
> instance [%p]\n", i, thread, interpreter);fflush(stderr);
>             }
>
>         }
>         else        // terminate on main thread
>         {
>             // Now wait for the interpreter to terminate and we are done.
>             interpreter->Terminate();
>         }
>
> ... cut ...
>
> Uncommenting the blue fprintf statement makes the crash go away *most* of
> the time such that all 250 Rexx interpreter instances can be terminated on
> a separate thread. Reducing that to just fflush(stderr) makes it go away
> *most* of the time as well (whereas using fflush(stdout) instead does not
> have any effect. So accessing stderr in that thread somehow influences the
> behaviour).
> ---
>
> Originally this crash occurred in the context of BSF4ooRexx and I reported
> it in <https://sourceforge.net/p/oorexx/feature-requests/806/>
> <https://sourceforge.net/p/oorexx/feature-requests/806/>. It seems that
> Rick thought it had to do with the code in BSF4ooRexx and not with ooRexx.
> Eventually this thread led to a new, small C++ (supplied with #1872 above)
> only (only creates a RII, runs a simple Rexx script, terminates the RII)
> showcase in which no external dependency could be made responsible for the
> crash, such that it becomes clear that the cause lies in ooRexx itself.
>
> As the crash occurs rather early, if using "testTerminate.exe someArg" I
> had hoped that some of the C++ gurus would be able to locate (and hopfeully
> fix) the cause relatively quickly (realizing that multithreaded bugs can be
> extremely hard to trace down and to fix). Unfortunately, this has not
> happened to this day (after almost 16 months). As this is a showstopper and
> inhibits using this great ooRexx feature, namely being able to create any
> number of different Rexx interpreter instances (each having its own .local)
> in a process and terminate them.
>
> Therefore I kindly request any of the C++ experts to look into this matter
> if possible. Maybe the upcoming vacation time allows for a few time slots
> to use for analyzing, finding and hopefully fixing the cause of this
> showstopper crash!
>
> ---rony
>
> P.S.: Have simplified the test code a little bit, also allowing the test
> program to run with all three reported scenarios; it is enclosed as (also
> slightly stripped down) "testTerminate2.cpp" and "Makefile2.windows"
> ("nmake /f Makefil2.windows" will create testTerminate2.exe) which after
> successful compilation can be invoked as:
>
>    - testTerminate2.exe
>
>    - no arguments: will create and terminate all 250 Rexx interpreter
>       instances (RII) on the same (main) thread without any crash
>
>       - testTerminate2.exe oneArg
>
>    - any single argument will cause the crash to always occur while
>       terminating the *second* RII on a separate thread (as if terminating the
>       previous RII on a separate thread left something in an unbalanced state)
>
>       - testTerminate2.exe oneArg secondArg
>
>    - any two arguments will cause fflush(stderr) in the terminating
>       thread to be issued and as a result most of the time all 250 Rexx
>       interpreter instances can be terminated on a separate thread without a
>       crash; running it a couple of times may however cause that crash to 
> occur
>       at different RIIs
>
> Terminate() will kick off the garbage collector and the crash seems to
> occur during its run.
>
> P.P.S.: Would it be possible to have the termination of a RII carried out
> on the same thread as its creation (which seems to run stably) by ooRexx
> itself (e.g. having a specific thread to create and to terminate RIIs)?
>
> This may need a function to learn about whether a RII is currently
> running/blocked and only terminate it on the creation thread if not in use
> so not to block the creation thread. Maybe also (an asynchroneous?) a
> function to force termination of a RII would be helpful in such a scenario,
> maybe with an option that indicates whether running/blocking Rexx code on
> that RII should be forcefully halted or not.
>
>
> _______________________________________________
> Oorexx-devel mailing list
> Oorexx-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/oorexx-devel
>
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to