erlang / otp

Erlang/OTP
http://erlang.org
Apache License 2.0
11.39k stars 2.96k forks source link

ERL-38: erlang:loaded() incomplete with erl -noshell -s module function #3074

Closed OTP-Maintainer closed 3 years ago

OTP-Maintainer commented 9 years ago

Original reporter: crownedgrouse Affected version: OTP-18.0 Component: Not Specified Migrated from: https://bugs.erlang.org/browse/ERL-38


Hi,
I do not really know if it is a bug or a feature, but it create possible issues :

when launching a function  with  "erl  -noshell -s module function"  where module:function use the list of modules loaded (erlang:loaded/0) , very offen the list is incomplete.
Looks like all modules are not already loaded when launching the function.
It is maybe a start time optimization for interactive mode ?
I did not saw the issue when shell is started (without -noshell), but I cannot say if the problem can occur anyway (maybe hidden by a bigger start time ?).

Is there any way to know that all modules that have to be loaded at start are really loaded , without having to sleep for couple of second by security ?

I detected the issue on 18.0 but probably exists on many releases.
OTP-Maintainer commented 9 years ago

crownedgrouse said:

Same by starting a shell and quickly launching erlang:loaded() twice.
{code:erlang}
Erlang/OTP 18 [erts-7.0] [source] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V7.0  (abort with ^G)
1> erlang:loaded().
[erl_internal,otp_internal,erl_scan,io,sets,dict,ordsets,
 erl_lint,erl_anno,erl_parse,ram_file,beam_lib,
 file_io_server,orddict,erl_eval,file,c,error_logger_tty_h,
 kernel_config,shell,queue,io_lib_format,proplists,io_lib,
 edlin,group,user_drv,user_sup,supervisor_bridge|...]
2> erlang:loaded().
[epp,io_lib_pretty,erl_internal,otp_internal,erl_scan,io,
 sets,dict,ordsets,erl_lint,erl_anno,erl_parse,ram_file,
 beam_lib,file_io_server,orddict,erl_eval,file,c,
 error_logger_tty_h,kernel_config,shell,queue,io_lib_format,
 proplists,io_lib,edlin,group,user_drv|...]{code}
OTP-Maintainer commented 9 years ago

crownedgrouse said:

I tried by loading manually stdlib before, but returned 'already_loaded' while
first list is not complete compared to second ...
{code:erlang}
1> A=erlang:loaded(). application:load(stdlib). B=erlang:loaded(). B -- A.
[erl_internal,otp_internal,erl_scan,io,sets,dict,ordsets,
 erl_lint,erl_anno,erl_parse,ram_file,beam_lib,
 file_io_server,orddict,erl_eval,file,c,error_logger_tty_h,
 kernel_config,shell,queue,io_lib_format,proplists,io_lib,
 edlin,group,user_drv,user_sup,supervisor_bridge|...]
2> application:load(stdlib). B=erlang:loaded(). B -- A.
{error,{already_loaded,stdlib}}
3> B=erlang:loaded(). B -- A.
[epp,io_lib_pretty,erl_internal,otp_internal,erl_scan,io,
 sets,dict,ordsets,erl_lint,erl_anno,erl_parse,ram_file,
 beam_lib,file_io_server,orddict,erl_eval,file,c,
 error_logger_tty_h,kernel_config,shell,queue,io_lib_format,
 proplists,io_lib,edlin,group,user_drv|...]
4> B -- A.
[epp,io_lib_pretty]
{code}
OTP-Maintainer commented 9 years ago

kenneth said:

This is not a bug at all. The code loading in interactive mode means that each module is loaded on demand the first time it is called.

The different results you get from erlang:loaded depends on timing. I can imagine that the
module and function you are running with -s will execute earlier relative to other functions in other processes when you use -noshell comparer with when you have a shell that has to be started as well. This is why you see the difference easier when using -noshell. But the difference between 2 calls of erlang:loaded can occur at anytime when running in interactive mode (the default).

One interesting question is why you are calling erlang:loaded() in this function. What is the purpose of those calls? If I know that I might be able to propose an alternative solution that works reliably. 
OTP-Maintainer commented 9 years ago

crownedgrouse said:

Hi, thanks.
I supposed, too, it was not a bug. but it disturbed me.
For my culture, I suppose it is not the case in -mode embedded ? All modules are loaded before any action in such case ?

I needed this to create a database of erlang API evolution between release : https://github.com/crownedgrouse/geas/tree/master/priv/reldiffs/yaml
my goal is to enhance my  tool (geas) in order to tell on what (official) release a beam file is able to run on, by checking fonction calls in the abstract code . For instance using application:ensure_all_start cannot be run on release older than R16B02. But another story.

I found a workaround , by looking at  lib_dir content, calling application:load/1 on all applications/libraries and then using erlang:loaded/0. 

thanks for your help, you can then close the ticket.

PS: I guess from your explanation that erlang:loaded/0 use module epp and io_lib_pretty , probably.