Skip to content

Instantly share code, notes, and snippets.

@depthso
Last active March 23, 2026 09:26
Show Gist options
  • Select an option

  • Save depthso/9b99778a52b9fe7e497d8426d89c6e55 to your computer and use it in GitHub Desktop.

Select an option

Save depthso/9b99778a52b9fe7e497d8426d89c6e55 to your computer and use it in GitHub Desktop.
Check the types of arguments passed into a function to prevent type attacks such as table attacks mimicking Objects
--[[
Created by @depso (depthso)
Example usage:
local BindedFunction = Module:BindFunction(
{"string", "number"},
function(A: string, B: number)
print("Pass! Hello", A, "you are", B, "years old!")
end
)
BindedFunction("Max", 10) -- Correct
BindedFunction("Max", "10") -- Incorrect
local BindedFunctionMulti = Module:BindFunction(
{"string", {
{
"number"
},
"number",
"number",
}},
function(...)
print("Pass!")
end
)
BindedFunctionMulti("Max", {
{
10
},
20,
30
}) -- Correct
BindedFunctionMulti("Max", {
{
10
},
10
}) -- Incorrect
local BindedFunctionDict = Module:BindFunction(
{
"string",
{
"number",
{
["number"] = {
["string"] = "string",
},
["string"] = {
"string" -- probkem
}
}
}
},
function(...)
print("Pass!")
end
)
BindedFunctionDict("Max", {
10,
{
[20] = {
["Hello"] = "World",
},
["Hello"] = {
"World"
}
}
}) -- Correct
BindedFunctionDict("Max", {
10,
{
[20] = {
[10] = "World",
},
["Hello"] = {
"World"
}
},
}) -- Incorrect
BindedFunctionDict("Max", {
10,
{
[20] = {
["10"] = 10,
},
["Hello"] = {
"World"
}
},
}) -- Incorrect
BindedFunctionDict("Max", {
"string",
{
[20] = {
["H"] = "World",
},
["Hello"] = {
"World"
}
},
}) -- Incorrect
]]
--!native
-- Created by @depso (depthso)
local Module = {}
--// Types
type ArgumentTypes = {string | ArgumentTypes}
type Function = (...any) -> (...any)
function Module:_CompareArgs(A, B, ExpectedA, ExpectedB): boolean
--// Types
local AType = typeof(A)
local BType = typeof(B)
--// Check for args overflow
if not ExpectedB then return false end
--// String type comparsion
if typeof(ExpectedA) == "string" and AType ~= ExpectedA then return false end
if typeof(ExpectedB) == "string" and BType ~= ExpectedB then return false end
--// Recursive tables
if AType == "table" then
if not self:_Validate(ExpectedA, A) then
return false
end
end
if BType == "table" then
if not self:_Validate(ExpectedB, B) then
return false
end
end
return true
end
function Module:_Validate(ExpectedTypes: ArgumentTypes, Packed: {any}): boolean
local IsArray = typeof(next(ExpectedTypes)) == "number"
local Cursor = nil
for A, B in next, Packed do
local ExpectedA, ExpectedB
--// Fetch expected types
if IsArray then
ExpectedA, ExpectedB = next(ExpectedTypes, Cursor)
Cursor = ExpectedA
else
ExpectedB = ExpectedTypes[typeof(A)]
end
--// Compare entry to expected types
if not self:_CompareArgs(A, B, ExpectedA, ExpectedB) then
return false
end
end
--// Args count check (minium)
if IsArray and next(ExpectedTypes, Cursor) ~= nil then
return false
end
return true
end
function Module:BindFunction<t>(Args: ArgumentTypes, Func: t & Function): t
return @native function(...)
--if not self:_Validate(Args, {...}) then print("Args error") return end -- Without producing an error
assert(self:_Validate(Args, {...}), "Invalid arguments passed to function!")
return Func(...)
end
end
return Module
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment