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

Maximum number of fun arguments #9113

Open
juhlig opened this issue Nov 26, 2024 · 3 comments · May be fixed by #9121
Open

Maximum number of fun arguments #9113

juhlig opened this issue Nov 26, 2024 · 3 comments · May be fixed by #9121
Assignees
Labels
bug Issue is reported as a bug team:VM Assigned to OTP team VM

Comments

@juhlig
Copy link
Contributor

juhlig commented Nov 26, 2024

Describe the bug
The documentation for System Limits states that the maximum number of arguments for a fun is 255. This is true in the sense that the compiler allows literal funs with up to 255 arguments and rejects literal funs with more arguments. However, this is not the entire story.

The following example module, which has a function test/1 which returns a fun with 255 arguments, compiles:

-module(test).

-export([test/1]).

test(Y) ->
    fun(_X01, _X02, _X03, _X04, _X05, _X06, _X07, _X08, _X09, _X0A, _X0B, _X0C, _X0D, _X0E, _X0F, _X10,
	_X11, _X12, _X13, _X14, _X15, _X16, _X17, _X18, _X19, _X1A, _X1B, _X1C, _X1D, _X1E, _X1F, _X20,
       	_X21, _X22, _X23, _X24, _X25, _X26, _X27, _X28, _X29, _X2A, _X2B, _X2C, _X2D, _X2E, _X2F, _X30,
       	_X31, _X32, _X33, _X34, _X35, _X36, _X37, _X38, _X39, _X3A, _X3B, _X3C, _X3D, _X3E, _X3F, _X40,
       	_X41, _X42, _X43, _X44, _X45, _X46, _X47, _X48, _X49, _X4A, _X4B, _X4C, _X4D, _X4E, _X4F, _X50,
       	_X51, _X52, _X53, _X54, _X55, _X56, _X57, _X58, _X59, _X5A, _X5B, _X5C, _X5D, _X5E, _X5F, _X60,
       	_X61, _X62, _X63, _X64, _X65, _X66, _X67, _X68, _X69, _X6A, _X6B, _X6C, _X6D, _X6E, _X6F, _X70,
       	_X71, _X72, _X73, _X74, _X75, _X76, _X77, _X78, _X79, _X7A, _X7B, _X7C, _X7D, _X7E, _X7F, _X80,
       	_X81, _X82, _X83, _X84, _X85, _X86, _X87, _X88, _X89, _X8A, _X8B, _X8C, _X8D, _X8E, _X8F, _X90,
       	_X91, _X92, _X93, _X94, _X95, _X96, _X97, _X98, _X99, _X9A, _X9B, _X9C, _X9D, _X9E, _X9F, _XA0,
       	_XA1, _XA2, _XA3, _XA4, _XA5, _XA6, _XA7, _XA8, _XA9, _XAA, _XAB, _XAC, _XAD, _XAE, _XAF, _XB0,
       	_XB1, _XB2, _XB3, _XB4, _XB5, _XB6, _XB7, _XB8, _XB9, _XBA, _XBB, _XBC, _XBD, _XBE, _XBF, _XC0,
       	_XC1, _XC2, _XC3, _XC4, _XC5, _XC6, _XC7, _XC8, _XC9, _XCA, _XCB, _XCC, _XCD, _XCE, _XCF, _XD0,
       	_XD1, _XD2, _XD3, _XD4, _XD5, _XD6, _XD7, _XD8, _XD9, _XDA, _XDB, _XDC, _XDD, _XDE, _XDF, _XE0,
       	_XE1, _XE2, _XE3, _XE4, _XE5, _XE6, _XE7, _XE8, _XE9, _XEA, _XEB, _XEC, _XED, _XEE, _XEF, _XF0,
       	_XF1, _XF2, _XF3, _XF4, _XF5, _XF6, _XF7, _XF8, _XF9, _XFA, _XFB, _XFC, _XFD, _XFE, _XFF) ->
          Y
    end.

But it cannot be loaded:

Erlang/OTP 27 [erts-15.1.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

Eshell V15.1.2 (press Ctrl+G to abort, type help(). for help)
1> l(test).
=ERROR REPORT==== 26-Nov-2024::12:01:29.657825 ===
beam/beam_load.c(632): Error loading function test:'-test/1-fun-0-'/256: op i_func_info: IaaI:
  too many arguments: 256


{error,badfile}

On closer inspection, it turns out that variables that were defined outside but used inside of the fun ( Y in the example above) are passed as "hidden" arguments, and thereby count towards the maximum number of arguments.

To Reproduce

  • Compile the above module
  • Load the compiled module

Expected behavior

  • The above module should not compile, instead of compiling to something that can't be loaded. On OTP 27.0 (but not earlier or later), trying to load this module even resulted in a segmentation fault.

  • The documentation should be augmented to say that variables defined outside and used inside a fun count towards the limit.

Affected versions
All versions, as far as I can tell.

Additional context
The cleanest solution would be to let such variables not count towards the limit, in accordance with what the documentation states. However, given that this is a very unlikely edge case (maybe it could happen in generated code, I don't know), a compilation error and augmentation of the documentation is probably fine.

@juhlig juhlig added the bug Issue is reported as a bug label Nov 26, 2024
@IngelaAndin IngelaAndin added the team:VM Assigned to OTP team VM label Nov 26, 2024
@jhogberg jhogberg self-assigned this Nov 27, 2024
@jhogberg
Copy link
Contributor

Thanks for the report! Making environment variables not count has some tricky implications elsewhere, so for now I've opted for updating the documentation and making the compiler reject these funs in #9121.

@mikpe
Copy link
Contributor

mikpe commented Nov 29, 2024

I assume the OTP team has considered but rejected the option of passing the closure (tuple) as a single "extra" parameter, and let the callee deal with extracting whatever free variables it wants?

@jhogberg
Copy link
Contributor

jhogberg commented Dec 2, 2024

Yes, we’ve considered that with the added twist of passing the fun itself, so that named anonymous funs with environment can reuse the called fun instead of having to create a new one. It’s been in the backlog for years and I’m not sure when we’ll get around to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue is reported as a bug team:VM Assigned to OTP team VM
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants