lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Roberto Ierusalimschy <roberto@...> wrote

A crash occurs under these circumstances:
- a program is in the final phase of its execution where its state is closed
- a library module (=userdata) is unloaded in the cleanup (__gc=gctm)
- a userdata calls its __gc method where it needs a function in the library just unloaded
- segmentation fault results

So, the userdata is being finalized after the module, right? Either it was created after the module, and then we have a bug in Lua (that should finalize it before the module), or it was created before the module, and then we have a weird program (where a userdata needs in its finalizer a function from a module that was not loaded yet). Can you tell what is your case?
It is a bit more complicated than creating userdata either before or after loading the library module, though I would not go sofar as calling my program 'weird'. Let me explain.

I am developing an upwards compatible io-module, where the lowlevel calls (those to the stdio functions) are split off into a submodule or backend. The higher level functions like open, read, etc. rely on submodule functions for the bare minimum of reading and writing. This setup allows for different backends, which then operate transparently to the file commands in Lua programs; an optional parameter on the open call can select the backend. At the moment I have three submodules: for stdio, for reading and writing zlib compressed files and for in-memory files.

Calling open(filename,...) in the main module allocates userdata to hold the information and then proceeds to open the file in the submodule's open function. In retrieving that open function the submodule is loaded, if not yet in memory (a not uncommon tactics of lazy loading). After that, new userdata in the same filetype finds the submodule loaded already. Thus, at no point in the program are there userdata finalizing through a module not yet loaded at that moment. But yes, the first userdata is created before the library module it needs, is loaded by the main module.

In a previous post you mentioned the fact that the userdata unloading is done in reverse order of creation:
In the cleanup phase, references do not prevent a module from being finalized; otherwise the clean up would be a regular collection and would not collect everything. However, finalizers are not called in arbitrary order, but in reverse order of their creation. If module A is loaded before module B (so that B may depend on A), then module A will be unloaded after module B.
In the expectation that this does not only applies to modules but to all userdata as a whole, I changed my program to force submodule loading before the creation of the first userdata that depends on it. Then indeed all is well. So, thank you for your helpful remarks that now completely solve the problem, without a need to change the Lua- code. By the way, in the process I learned a lot about Lua!

However, allow me one final remark. It all depends on the reverse order of calling the userdata __gc functions. If at any time in the future a new implementation of the collection/clearing phase changes that, then programs like this will break again. How certain can one be that this will not happen? I therefore suggest that a change is made to unload libraries in a last separate step, possibly in Lua 5.2.

Hans van der Meer