Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
2310-Fail-early-when-calling_self.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2310-Fail-early-when-calling_self.patch of Package erlang
From 8cd993c4a072711eff54c3d100dfa59b48cc95be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= <jose.valim@dashbit.co> Date: Sun, 27 Jun 2021 17:21:40 +0200 Subject: [PATCH] Fail early when calling_self This provides early feedback in gen behaviours if a process attempts to call itself, which is especially important on infinity timeouts. The functionality was also implemented for the io module, which also errors with reason "calling_self" and is handled by the error formatter accordingly: 1> io:put_chars(self(), "123"). ** exception error: calling_self in function io:put_chars/2 called as io:put_chars(<0.83.0>,"123") *** argument 1: the device is not allowed to be the current process Closes #5005. --- lib/stdlib/src/erl_error.erl | 2 ++ lib/stdlib/src/erl_stdlib_errors.erl | 7 +++++++ lib/stdlib/src/gen.erl | 2 ++ lib/stdlib/src/io.erl | 3 +++ lib/stdlib/test/gen_server_SUITE.erl | 13 +++++++++++-- lib/stdlib/test/io_SUITE.erl | 10 ++++++++-- 6 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/stdlib/src/erl_error.erl b/lib/stdlib/src/erl_error.erl index f6870b875b..4c4c3338f0 100644 --- a/lib/stdlib/src/erl_error.erl +++ b/lib/stdlib/src/erl_error.erl @@ -269,6 +269,8 @@ explain_reason(restricted_shell_started, exit, [], _PF, _S, _Enc, _CL) -> <<"restricted shell starts now">>; explain_reason(restricted_shell_stopped, exit, [], _PF, _S, _Enc, _CL) -> <<"restricted shell stopped">>; +explain_reason(calling_self, exit, [], _PF, _S, _Enc, _CL) -> + <<"the current process attempted to call itself">>; %% Other exit code: explain_reason(Reason, Class, [], PF, S, _Enc, CL) -> {L, _} = PF(Reason, (iolist_size(S)+1) + exited_size(Class), CL), diff --git a/lib/stdlib/src/erl_stdlib_errors.erl b/lib/stdlib/src/erl_stdlib_errors.erl index a8c0744bc5..66f02a2b30 100644 --- a/lib/stdlib/src/erl_stdlib_errors.erl +++ b/lib/stdlib/src/erl_stdlib_errors.erl @@ -417,6 +417,11 @@ format_io_error(_, _, {io, arguments}, true) -> [device_arguments]; format_io_error(_, _, {io, arguments}, false) -> [{general,device_arguments}]; +%% calling_self, Io =:= self() +format_io_error(_, _, {io, calling_self}, true) -> + [calling_self]; +format_io_error(_, _, {io, calling_self}, false) -> + [{general,calling_self}]; %% terminated, monitor(Io) failed format_io_error(_, _, {io, terminated}, true) -> [device_terminated]; @@ -988,6 +993,8 @@ expand_error(bad_update_op) -> <<"not a valid update operation">>; expand_error(bitstring) -> <<"is a bitstring (expected a binary)">>; +expand_error(calling_self) -> + <<"the device is not allowed to be the current process">>; expand_error(counter_not_integer) -> <<"the value in the given position, in the object, is not an integer">>; expand_error(dead_process) -> diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl index 6a07eb34d8..604815d15a 100644 --- a/lib/stdlib/src/gen.erl +++ b/lib/stdlib/src/gen.erl @@ -201,6 +201,8 @@ call(Process, Label, Request, Timeout) -dialyzer({no_improper_lists, do_call/4}). +do_call(Process, _Label, _Request, _Timeout) when Process =:= self() -> + exit(calling_self); do_call(Process, Label, Request, infinity) when (is_pid(Process) andalso (node(Process) == node())) diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl index d93be2d997..956f1ad013 100644 --- a/lib/stdlib/src/io.erl +++ b/lib/stdlib/src/io.erl @@ -335,6 +335,7 @@ read(Io, Prompt, Pos0, Options) -> conv_reason(arguments) -> badarg; conv_reason(terminated) -> terminated; +conv_reason(calling_self) -> calling_self; conv_reason({no_translation,_,_}) -> no_translation; conv_reason(_Reason) -> badarg. @@ -596,6 +597,8 @@ request(Name, Request, ErrorTag) when is_atom(Name) -> request(Pid, Request, ErrorTag) end. +execute_request(Pid, _Tuple, ErrorTag) when Pid =:= self() -> + {ErrorTag, calling_self}; execute_request(Pid, {Convert,Converted}, ErrorTag) -> Mref = erlang:monitor(process, Pid), Pid ! {io_request,self(),Mref,Converted}, diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index 0a7cf80923..1da9845731 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -28,7 +28,7 @@ init_per_group/2,end_per_group/2]). -export([start/1, crash/1, call/1, send_request/1, cast/1, cast_fast/1, continue/1, info/1, abcast/1, multicall/1, multicall_down/1, - call_remote1/1, call_remote2/1, call_remote3/1, + call_remote1/1, call_remote2/1, call_remote3/1, calling_self/1, call_remote_n1/1, call_remote_n2/1, call_remote_n3/1, spec_init/1, spec_init_local_registered_parent/1, spec_init_global_registered_parent/1, @@ -65,7 +65,7 @@ suite() -> all() -> [start, {group,stop}, crash, call, send_request, cast, cast_fast, info, abcast, - continue, multicall, multicall_down, call_remote1, call_remote2, + continue, multicall, multicall_down, call_remote1, call_remote2, calling_self, call_remote3, call_remote_n1, call_remote_n2, call_remote_n3, spec_init, spec_init_local_registered_parent, @@ -720,6 +720,15 @@ call_remote_n3(Config) when is_list(Config) -> ok. +%% -------------------------------------- +%% Other bad calls +%% -------------------------------------- + +calling_self(Config) when is_list(Config) -> + {'EXIT', {calling_self, _}} = (catch gen_server:call(self(), oops)), + {'EXIT', {calling_self, _}} = (catch gen_server:call(self(), oops, infinity)), + ok. + %% -------------------------------------- %% Test gen_server:cast and handle_cast. %% Test all different return values from diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl index 6cf9d9f7d6..9f36c694d0 100644 --- a/lib/stdlib/test/io_SUITE.erl +++ b/lib/stdlib/test/io_SUITE.erl @@ -28,7 +28,7 @@ io_fread_newlines/1, otp_8989/1, io_lib_fread_literal/1, printable_range/1, bad_printable_range/1, io_lib_print_binary_depth_one/1, otp_10302/1, otp_10755/1, - otp_10836/1, io_lib_width_too_small/1, + otp_10836/1, io_lib_width_too_small/1, calling_self/1, io_with_huge_message_queue/1, format_string/1, format_neg_zero/1, maps/1, coverage/1, otp_14178_unicode_atoms/1, otp_14175/1, otp_14285/1, limit_term/1, otp_14983/1, otp_15103/1, otp_15076/1, @@ -63,7 +63,7 @@ all() -> io_fread_newlines, otp_8989, io_lib_fread_literal, printable_range, bad_printable_range, format_neg_zero, io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836, - io_lib_width_too_small, io_with_huge_message_queue, + io_lib_width_too_small, io_with_huge_message_queue, calling_self, format_string, maps, coverage, otp_14178_unicode_atoms, otp_14175, otp_14285, limit_term, otp_14983, otp_15103, otp_15076, otp_15159, otp_15639, otp_15705, otp_15847, otp_15875, github_4801, chars_limit, @@ -210,6 +210,10 @@ float_w(Config) when is_list(Config) -> ok. +calling_self(Config) when is_list(Config) -> + {'EXIT', {calling_self, _}} = (catch io:format(self(), "~p", [oops])), + ok. + %% OTP-5403. ~s formats I/O lists and a single binary. otp_5403(Config) when is_list(Config) -> "atom" = fmt("~s", [atom]), @@ -3034,6 +3038,8 @@ error_info(Config) -> {put_chars,[<<1:1>>], [{1,"not valid character data"}]}, {put_chars,[UnknownDev(),"test"], [{general,"unknown error: 'Спутник-1'"}]}, {put_chars,["test"], [{gl,UnknownDev()},{general,"unknown error: 'Спутник-1'"}]}, + {put_chars,[self(),"test"],[{1,"the device is not allowed to be the current process"}]}, + {put_chars,["test"],[{gl,self()},{general,"the device is not allowed to be the current process"}]}, {write,[DeadDev,"test"],[{1,"terminated"}]}, {write,["test"],[{gl,DeadDev},{general,"terminated"}]}, -- 2.31.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor