Skip to content

Commit 86c4155

Browse files
committed
Now detecting non-cached angles and vectors; Added support for LuaJIT 2.1 bytecode
1 parent 39cd258 commit 86c4155

3 files changed

Lines changed: 78 additions & 33 deletions

File tree

lua/badcoderz/sh_code_smells.lua

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,14 @@ local function _hook()
6161
return
6262
end
6363

64-
if calledFunc == Color then
65-
local callingContext = debug.getinfo(curStackLevel + 1, "fS")
66-
if callingContext.what == "C" then return end -- C could be calling Color() for some reason
64+
--threats functions like Color/Angle/Vector in a different way since the way it's called matters
65+
local heavyObject = BadCoderz.heavy_funcs_objects[calledFunc]
66+
if heavyObject then
67+
local callingContext = debug.getinfo(curStackLevel + 1, "fSl")
68+
if callingContext.what == "C" then return end -- C could be calling it for some reason
6769
local callingContextFunc = callingContext.func
6870

69-
local found = BadCoderz.find_color_call_static_args(callingContextFunc)
71+
local found = BadCoderz.find_call_static_args(callingContextFunc, heavyObject, callingContext.currentline)
7072
if not found then
7173
return
7274
end

lua/badcoderz/sh_data.lua

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,52 @@ BadCoderz.heavy_funcs = {
1515
[file.Size] = "file.Size",
1616
[file.Time] = "file.Time",
1717
[file.Write] = "file.Write",
18-
[Color] = "Color"
18+
[Color] = "Color",
19+
[Vector] = "Vector",
20+
[Angle] = "Angle",
1921
--[[
2022
candidates for "dumb fuckers" update :
2123
CompileString
2224
RunString
2325
RunStringEx
2426
ents.Create
2527
surface.CreateFont
28+
table.HasValue
2629
]]
2730
}
2831

32+
-- bool is represending a required(true) knum/kshort or an optional one (false), it's used when inspecting the bytecode
33+
BadCoderz.heavy_funcs_objects = {
34+
[Color] = {
35+
{
36+
["Color"] = true,
37+
["SetDrawColor"] = true
38+
},
39+
{true, true, true, false}
40+
},
41+
[Vector] = {
42+
{
43+
["Vector"] = true
44+
},
45+
{true, true, true}
46+
},
47+
[Angle] = {
48+
{
49+
["Angle"] = true
50+
},
51+
{true, true, true}
52+
}
53+
}
2954

3055

3156
BadCoderz.toolTips = {
3257
["player.GetAll"] = "This function is used to find all players, it depends of the implementation and what the dev is doing with it but there is good chances he's doing CPU Intensive things in this loop",
3358
["ents.GetAll"] = "This function is used to find all entities (A LOT), it depends of the implementation and what the dev is doing with it but there is good chances he's doing CPU Intensive things in this loop",
3459
["file.Append"] = "Working with files is always slow, doing it a lot is a TERRIBLE IDEA",
35-
["Color"] = "This functions creates a new Color object on each call, it takes ram, cpu time to be allocated in the memory and cpu time by the garbage collector, so the dev is supposed to cache it. Only the Color() calls with static values (not vars) are detected."
60+
["Color"] = "You NEVER need to create a color on each frame with static arguments, cache it out of your rendering context.",
61+
["Vector"] = "You NEVER need to create a vector with static arguments on each tick, cache it outside of the hook and if you need to, use the Vectors metamethods.\nEx :\n\tpos:Add(posOffset)\ninstead of :\n\tpos1+Vector(4,0,9)\n",
62+
["Angle"] = "You NEVER need to create an angle with static arguments on each tick, cache it outside of the hook and if you need to, use the Angles metamethods.\nEx :\n\tang1:Add(ang2)\ninstead of :\n\tang1+Vector(4,0,9)\n"
63+
3664
}
3765

3866
BadCoderz.toolTips["file.CreateDir"] = BadCoderz.toolTips["file.Append"]

lua/badcoderz/sh_luajit_decompiler.lua

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,27 @@ https://gist.github.com/meepen/807dd81a572ffb0f28a8c44c04922fdd
77
88
]]
99

10-
local instructions_db = {
11-
CALL = 62,
12-
KSHORT = 39,
13-
GGET = 52,
14-
UGET = 43,
15-
FUNCF = 85
16-
}
10+
local instructions_db;
11+
12+
if jit.version_num < 20100 then
13+
instructions_db = {
14+
CALL = 62,
15+
KSHORT = 39,
16+
GGET = 52,
17+
UGET = 43,
18+
FUNCF = 85,
19+
KNUM = 40
20+
}
21+
else -- bytecode changes
22+
instructions_db = {
23+
CALL = 66,
24+
KSHORT = 41,
25+
GGET = 54,
26+
UGET = 45,
27+
FUNCF = 89,
28+
KNUM = 42
29+
}
30+
end
1731

1832
local function disassemble_function(fn)
1933
local upvalues = {}
@@ -26,7 +40,7 @@ local function disassemble_function(fn)
2640
end
2741

2842

29-
-- consts are BELLOW zero, const integers are ABOVE zero
43+
-- consts are BELLOW zero, 64bits nums (KNUMS) are ABOVE zero but we don't need them here, we're just looking for the functions call names
3044
local consts = {}
3145
n = -1
3246
local value = jit.util.funck(fn, n)
@@ -53,11 +67,6 @@ local function disassemble_function(fn)
5367
D = bit.rshift(ins, 16),
5468
OP_CODE = bit.band(ins, 0xFF)
5569
}
56-
--[[instruction.C = bit.rshift(bit.band(ins, 0x00ff0000), 16)
57-
instruction.B = bit.rshift(ins, 24)
58-
instruction.A = bit.rshift(bit.band(ins, 0x0000ff00), 8)
59-
instruction.D = bit.rshift(ins, 16)
60-
instruction.OP_CODE = bit.band(ins, 0xFF)]]
6170
instructions[n] = instruction
6271
n = n + 1
6372
end
@@ -71,25 +80,31 @@ local function disassemble_function(fn)
7180
return ret
7281
end
7382

74-
local Color_calls = {}
75-
Color_calls["Color"] = true
76-
Color_calls["SetDrawColor"] = true
77-
78-
-- searchs for Color(KSHORT,KSHORT,KSHORT,[KSHORT])
79-
function BadCoderz.find_color_call_static_args(fn)
83+
function BadCoderz.find_call_static_args(fn, definition, expectedLine)
8084
-- to fix : it just find any Color() with static short int call, doesn't return the line
85+
local minNums = 0
86+
local maxNums = 0
87+
for k, v in ipairs(definition[2]) do
88+
if v == true then
89+
minNums = minNums + 1
90+
end
91+
maxNums = maxNums + 1
92+
end
93+
94+
95+
8196
local disassembled_code = disassemble_function(fn)
8297
local targeted_consts = {}
8398
local targeted_upvalues = {}
8499

85100
for k, v in pairs(disassembled_code.consts) do
86-
if Color_calls[v] then
101+
if definition[1][v] then
87102
targeted_consts[k] = true
88103
end
89104
end
90105

91106
for k, v in pairs(disassembled_code.upvalues) do
92-
if Color_calls[v] then
107+
if definition[1][v] then
93108
targeted_upvalues[k] = true
94109
end
95110
end
@@ -104,20 +119,20 @@ function BadCoderz.find_color_call_static_args(fn)
104119
while (i <= count) do
105120
local instruction = disassembled_code.instructions[i]
106121

107-
if ((instruction.OP_CODE == instructions_db.GGET) and (targeted_consts[instruction.D] == true) or
122+
if (((instruction.OP_CODE == instructions_db.GGET) and (targeted_consts[instruction.D] == true) or
108123
(instruction.OP_CODE == instructions_db.UGET) and (targeted_upvalues[instruction.D] == true))
109-
and (i + 4) < count then
110-
local KSHORT_count = 0
124+
and ((i + minNums) < count) and jit.util.funcinfo(fn, i).currentline == expectedLine) then
125+
local NUMBER_count = 0
111126
local i2 = i + 1
112127
local cur_instruction = disassembled_code.instructions[i2]
113128

114-
while ((i2 <= count) and (cur_instruction.OP_CODE == instructions_db.KSHORT)) do
115-
KSHORT_count = KSHORT_count + 1
129+
while ((i2 <= count) and ((cur_instruction.OP_CODE == instructions_db.KSHORT) or (cur_instruction.OP_CODE == instructions_db.KNUM))) do
130+
NUMBER_count = NUMBER_count + 1
116131
i2 = i2 + 1
117132
cur_instruction = disassembled_code.instructions[i2]
118133
end
119134

120-
if (KSHORT_count ~= 3 and KSHORT_count ~= 4) then
135+
if (NUMBER_count < minNums or NUMBER_count > maxNums) then
121136
i = i + 1
122137
continue
123138
end

0 commit comments

Comments
 (0)