metacall: metacallfmv uses iterator instead of index for signature_get_type, casting arguments to wrong parameter types
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 65/100
Research direction
The bug sits in metacallfmv (around line 1675 of source/metacall/source/metacall.c) and metacallfmv_await_s (around line 2018), where the parameter type lookup uses the loop variable iterator rather than the resolved index. Read how signature_get_index and signature_get_type are used together in those functions, then reproduce with a two-parameter function of different types called with reversed JSON keys via metacallfms. Done means the arguments are cast against the type at index and the args array is fully initialized before function_call.
Written by the indexing model from the issue text.
Description
🐛 Bug Report
In source/metacall/source/metacall.c, metacallfmv and metacallfmv_await_s use the loop variable iterator instead of the resolved signature parameter index when retrieving the target parameter's type.
As a result, whenever a function is called with map/dictionary arguments in an order different from its signature declaration (which is standard for JSON and dictionary calls in metacallfms), arguments are type-checked and cast against the wrong parameter types.
Expected Behavior
When calling a function with named arguments (e.g., via metacallfmv or metacallfms with JSON {"b": 42, "a": "hello"} for fn(a: string, b: int)):
index = signature_get_index(s, "b")resolves to1.- The argument value
42should be type-cast against the type of parameterindex(int). args[1]receives the value.
Current Behavior
In source/metacall/source/metacall.c at line 1675 (metacallfmv):
/* Obtain signature index */
if (type_id_string(key_id) == 0)
{
const char *key = value_to_string(keys[iterator]);
index = signature_get_index(s, key);
}
...
/* If index is valid, cast values and build arguments */
if (index < METACALL_ARGS_SIZE)
{
type t = signature_get_type(s, iterator); // <--- BUG: uses iterator instead of index!
if (t != NULL)
{
type_id id = type_index(t);
if (id != value_type_id((value)values[iterator]))
{
value cast_arg = value_type_cast((value)values[iterator], id);
if (cast_arg != NULL)
{
values[iterator] = cast_arg;
}
}
}
args[index] = values[iterator];
}
And identically at line 2018 in metacallfmv_await_s:
type t = signature_get_type(s, iterator); // <--- BUG: uses iterator instead of index!
Because iterator is the loop index across the caller's keys[] array rather than the parameter's position in the signature:
values[0](intended for parameter atindex = 1) is checked and cast againstsignature_get_type(s, 0).values[1](intended for parameter atindex = 0) is checked and cast againstsignature_get_type(s, 1).
If the parameter types differ (e.g. String and Int), MetaCall either attempts an invalid cast or passes the wrong type into args[index].
Additional Finding: Uninitialized Stack Pointer Exposure
In both metacallfmv (line 1618) and metacallfmv_await_s (line 1961):
void *args[METACALL_ARGS_SIZE];
args is declared without initialization. If the caller provides duplicate keys (mapping multiple times to the same index) or if keys do not cover all 0 .. args_count - 1 indices, any unpopulated slot in args contains uninitialized stack memory, which is then passed directly to function_call(f, args, args_count).
Steps to Reproduce
- Define a function in any loader (e.g., Python or Node) with two parameters of different types:
def greet(name: str, count: int): return f"{name} " * count - Call
greetviametacallfmswith JSON keys in reverse order:{"count": 3, "name": "hello"} metacallfmsparses the JSON map:iterator = 0:key = "count",value = 3.index = signature_get_index(s, "count")->1.t = signature_get_type(s, iterator)-> fetches type of parameter0(name, String)!value_type_cast(3, TYPE_STRING)is attempted for parameter 1.
- The call either fails type validation or passes corrupted argument types to the loader.
Proposed Solution
- Replace
signature_get_type(s, iterator)withsignature_get_type(s, index)in bothmetacallfmv(line 1675) andmetacallfmv_await_s(line 2018). - Zero-initialize
args:
and ensure all required positionsvoid *args[METACALL_ARGS_SIZE] = { NULL };0 .. args_count - 1are populated before callingfunction_call.
- Dominant language
- C
- Stars
- 1.8k
- Forks
- 266
- Avg merge
- 2d 16h
- Merged PRs (30d)
- 14
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from metacall/core
-
pre-push hook empties VERSION when the clone has no tagsPossibly taken @vedant21-oss claimed this 17 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
metacall/core#939 · 3 comments ·
Maintainers usually reply within 1 day
-
TOCTOU race condition vulnerability!Possibly taken @akshatchitransh claimed this 1 day ago. Openbug
Difficulty 4/5 3-5 days Newbie friendliness 35/100
metacall/core#961 · 2 comments ·
Maintainers usually reply within 1 day
-
bug
Difficulty 3/5 Half a day Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
Go Port Race Conditions on MacOSPossibly taken A pull request linked to this issue is open or already merged. Openbug
Difficulty 4/5 3-5 days Newbie friendliness 35/100
metacall/core#942 · 3 comments ·
Maintainers usually reply within 1 day
-
Stack buffer overflow in `metacall.c` — is the 16-argument limit intentional?Possibly taken @10vulture1005 claimed this 34 days ago. Openbug
Difficulty 4/5 3-5 days Newbie friendliness 28/100
metacall/core#923 · 2 comments ·
Maintainers usually reply within 1 day
Similar issues
-
agent:WSL code-review linux pri:low refactoring tooling
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
DOC BUG Missing
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SDL-Hercules-390/hyperion#911 ·
Maintainers usually reply within 1 day
-
build: man page directory doubledPossibly taken @zeusgoose claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
esp-mosaico/esp-mosaico-bsp#40 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 62/100