Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 9e1c525

Browse files
committed
[[ Bug 21080 ]] Check objc handler argument count matches
This patch ensures an error is thrown if the bound method and the arguuments of the handler do not have the same number of arguments.
1 parent 334e393 commit 9e1c525

File tree

3 files changed

+62
-23
lines changed

3 files changed

+62
-23
lines changed

docs/lcb/notes/21080.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# [21080] When binding Objective C methods throw an error if the parameter count is incorrect

libscript/src/script-instance.cpp

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,13 +1021,22 @@ __MCScriptResolveForeignFunctionBindingForObjC(MCScriptInstanceRef p_instance,
10211021
t_valid = false;
10221022
}
10231023

1024+
uindex_t t_required_args = 0;
1025+
10241026
/* Get the Method - either class or instance - from the class */
10251027
if (t_valid && !t_is_dynamic)
10261028
{
10271029
if (!t_is_class)
10281030
{
1029-
t_valid = class_respondsToSelector(t_objc_class, t_objc_sel);
1030-
1031+
Method t_method_info = class_getInstanceMethod(t_objc_class, t_objc_sel);
1032+
if (t_method_info != nullptr)
1033+
{
1034+
t_required_args = method_getNumberOfArguments(t_method_info);
1035+
}
1036+
else
1037+
{
1038+
t_valid = false;
1039+
}
10311040
/* If a lookup fails, then check to see if it could be a property
10321041
* binding. Classes such as NSUserNotification declare dynamic props
10331042
* which means that the methods aren't present until runtime, but
@@ -1048,6 +1057,7 @@ __MCScriptResolveForeignFunctionBindingForObjC(MCScriptInstanceRef p_instance,
10481057
t_valid = strstr(property_getAttributes(t_property), ",R,") == nullptr;
10491058
}
10501059
}
1060+
t_required_args = 3;
10511061
}
10521062
else if (!t_valid &&
10531063
MCStringCountChar(*t_selector_name, MCRangeMake(0, MCStringGetLength(*t_selector_name)), ':', kMCStringOptionCompareExact) == 0)
@@ -1057,11 +1067,17 @@ __MCScriptResolveForeignFunctionBindingForObjC(MCScriptInstanceRef p_instance,
10571067
{
10581068
t_valid = true;
10591069
}
1070+
t_required_args = 2;
10601071
}
10611072
}
10621073
else
10631074
{
1064-
if (class_getClassMethod(t_objc_class, t_objc_sel) == nullptr)
1075+
Method t_method_info = class_getClassMethod(t_objc_class, t_objc_sel);
1076+
if (t_method_info != nullptr)
1077+
{
1078+
t_required_args = method_getNumberOfArguments(t_method_info);
1079+
}
1080+
else
10651081
{
10661082
t_valid = false;
10671083
}
@@ -1090,13 +1106,15 @@ __MCScriptResolveForeignFunctionBindingForObjC(MCScriptInstanceRef p_instance,
10901106
MCTypeInfoRef t_return_type =
10911107
MCHandlerTypeInfoGetReturnType(t_signature);
10921108

1109+
t_valid = t_arg_count == t_required_args || t_is_dynamic;
1110+
10931111
MCResolvedTypeInfo t_resolved_return_type;
10941112
if (!MCTypeInfoResolve(t_return_type,
10951113
t_resolved_return_type))
10961114
{
10971115
t_valid = false;
10981116
}
1099-
else
1117+
else if (t_valid)
11001118
{
11011119
if (t_resolved_return_type.named_type == kMCNullTypeInfo)
11021120
{
@@ -1112,6 +1130,9 @@ __MCScriptResolveForeignFunctionBindingForObjC(MCScriptInstanceRef p_instance,
11121130
}
11131131
}
11141132

1133+
unsigned int t_user_arg_index = 0;
1134+
unsigned int t_arg_index = 0;
1135+
11151136
/* Allocate memory for the handler layout (array of ffi_type*) and
11161137
* ffi_cif. This is a single block which will contain the cif followed
11171138
* by the type array. */
@@ -1123,27 +1144,27 @@ __MCScriptResolveForeignFunctionBindingForObjC(MCScriptInstanceRef p_instance,
11231144
/* ERROR: OOM */
11241145
t_valid = false;
11251146
}
1126-
t_cif = static_cast<ffi_cif *>(*t_layout_cif);
1127-
t_cif_arg_types = reinterpret_cast<ffi_type **>(t_cif + 1);
1128-
}
1129-
1130-
unsigned int t_user_arg_index = 0;
1131-
unsigned int t_arg_index = 0;
1132-
1133-
/* The first argument is always of pointer type - the object ptr. This
1134-
* is only present in the user signature if it is an instance method.*/
1135-
t_cif_arg_types[t_arg_index] = &ffi_type_pointer;
1136-
t_arg_index += 1;
1137-
if (!t_is_class)
1138-
{
1139-
t_user_arg_index += 1;
1147+
else
1148+
{
1149+
t_cif = static_cast<ffi_cif *>(*t_layout_cif);
1150+
t_cif_arg_types = reinterpret_cast<ffi_type **>(t_cif + 1);
1151+
1152+
/* The first argument is always of pointer type - the object ptr. This
1153+
* is only present in the user signature if it is an instance method.*/
1154+
t_cif_arg_types[t_arg_index] = &ffi_type_pointer;
1155+
t_arg_index += 1;
1156+
if (!t_is_class)
1157+
{
1158+
t_user_arg_index += 1;
1159+
}
1160+
1161+
/* The second argument is always of pointer type - the SEL ptr. This is
1162+
* never present in the user signature. */
1163+
t_cif_arg_types[t_arg_index] = &ffi_type_pointer;
1164+
t_arg_index += 1;
1165+
}
11401166
}
11411167

1142-
/* The second argument is always of pointer type - the SEL ptr. This is
1143-
* never present in the user signature. */
1144-
t_cif_arg_types[t_arg_index] = &ffi_type_pointer;
1145-
t_arg_index += 1;
1146-
11471168
while(t_user_arg_index < t_user_arg_count && t_valid)
11481169
{
11491170
MCHandlerTypeFieldMode t_mode =

tests/lcb/vm/interop-objc.lcb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,4 +558,21 @@ public handler TestDelegateRequiredMethod()
558558
"Creating delegate throws error when required protocol method is not mapped")
559559
end handler
560560

561+
__safe foreign handler CallClassMethodWithInstance(in pInstance as ObjcObject) returns ObjcId binds to "objc:NSObject.+class"
562+
563+
private handler TestObjcInterop_CallClassMethodWithInstance()
564+
variable tObj as ObjcObject
565+
put NSObjectAlloc() into tObj
566+
put CallClassMethodWithInstance(tObj) into tObj
567+
end handler
568+
569+
public handler TestObjcInterop_ArgumentCountMatchesMethod()
570+
if not the operating system is in ["mac", "ios"] then
571+
skip test "objc binding succeeds" because "not implemented on" && the operating system
572+
return
573+
end if
574+
575+
MCUnitTestHandlerThrowsNamed(TestObjcInterop_CallClassMethodWithInstance, "livecode.lang.ForeignHandlerBindingError", "Failure to bind with incorrect arguments objc function throws error")
576+
end handler
577+
561578
end module

0 commit comments

Comments
 (0)