Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exec gen_server stops if too much data is sent in one command #186

Open
Juliusan opened this issue Feb 19, 2025 · 0 comments · May be fixed by #187
Open

exec gen_server stops if too much data is sent in one command #186

Juliusan opened this issue Feb 19, 2025 · 0 comments · May be fixed by #187

Comments

@Juliusan
Copy link

Juliusan commented Feb 19, 2025

The problem

Sending large message to stdin of running exec command stops the whole exec gen_server, which crashes erlexec application.

How to reproduce

102> exec:start().
{ok,<0.237.0>}
103> {ok, Pid, _} = exec:run("cat", [stdin, stdout, stderr]).
{ok,<0.239.0>,3296626}
104> exec:send(Pid, erlang:list_to_binary([A rem 250 || A <- lists:seq(1,65511)])).
ok
105> exec:send(Pid, erlang:list_to_binary([A rem 250 || A <- lists:seq(1,65512)])).
=ERROR REPORT==== 19-Feb-2025::14:31:01.717063 ===
** Generic server exec terminating 
** Last message in was {'EXIT',#Port<0.14>,einval}
** When Server state == {state,#Port<0.14>,0,{[],[]},[],exec_mon,false,false}
** Reason for termination ==
** einval

ok
=CRASH REPORT==== 19-Feb-2025::14:31:01.717300 ===
  crasher:
    initial call: exec:init/1
    pid: <0.237.0>
    registered_name: exec
    exception exit: einval
      in function  gen_server:handle_common_reply/8 (gen_server.erl, line 1226)
    ancestors: [<0.222.0>,<0.85.0>,<0.71.0>,<0.66.0>,<0.70.0>,<0.65.0>,
                  kernel_sup,<0.47.0>]
    message_queue_len: 0
    messages: []
    links: [<0.239.0>]
    dictionary: []
    trap_exit: true
    status: running
    heap_size: 2586
    stack_size: 28
    reductions: 5704
  neighbours:

Desired behaviour

Stopping exec gen_server should be avoided in such case, because it crashes erlexec application's main supervisor. The supervisor is started with hardcoded values {one_for_one, 3, 30}, meaning that it is enough only 4 such crashes in 30 seconds to shutdown an application. If erlexec is part of other application, that application is also restarted if 4 such cases occur in 30 seconds. Of course, this could be avoided by starting exec gen_server in application's own supervisor.

Furthermore exec:send could return error instead of ok.

Analysis

As Erlang port is started, {packet, 2} is provided as an option:

erlexec/src/exec.erl

Lines 841 to 842 in aea9448

PortOpts = Env ++ [binary, exit_status, {packet, 2}, hide],
Port = erlang:open_port({spawn, Exe}, PortOpts),

This results in 2 byte length message size parameter passed to C code. If message is longer than 65511 (I suspect, it is enriched with several bytes of metadata as the number should be 65535) its length no longer fits into 2 bytes and hence the error.

@kape1395 kape1395 linked a pull request Feb 20, 2025 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant