ANTICHAT

ANTICHAT (https://forum.antichat.xyz/index.php)
-   Общие вопросы программирования (https://forum.antichat.xyz/forumdisplay.php?f=206)
-   -   Вызов lua калбека через sol внутри обработчика хука без обработки C++ исключений (https://forum.antichat.xyz/showthread.php?t=1537625)

Tema05 13.06.2025 17:56

Вот упрощённый вариант частей моей dll-ки. Я ставлю хук на функцию игры и из lua устанавливаю калбек, который будет вызываться из оригинального C++ калбека. Всё отлично работает, но есть проблема с обработкой ошибок.

C++:





Код:

// установка lua калбека для вызова из хука
void
set_callback
(
sol
::
this_state ts
,
sol
::
unsafe_function func
)
{
gHandler
=
func
;
}
// вызывается при подключении библиотеки из lua через require
sol
::
table
open
(
sol
::
this_state ts
)
{
sol
::
state_view
lua
(
ts
)
;
installHook
(
)
;
module
.
set_function
(
"set_callback"
,
&
set_cb
)
;
return
module
;
}
extern
"C"
__declspec
(
dllexport
)
int
luaopen_lib
(
lua_State
*
L
)
{
return
(
sol
::
c_call

)
(
L
)
;
}
sol
::
unsafe_function gHandler
;
// тут будет хранится функция lua калбека
kthook
::
kthook_simple

mHookedFunc
;
// объект хука
// функция установки C++ хука
void
installHook
(
)
{
mHookedFunc
.
set_dest
(
0x123456
)
;
// адрес функции в игре на которую нужно поставить хук
mHookedFunc
.
set_cb
(
handleHookedFunc
)
;
// калбек, который будет срабатывать при вызове функции
mHookedFunc
.
install
(
)
// устанавливает хук
}
// калбек захуканной функции
bool
handleHookedFunc
(
const
kthook
::
kthook_simple

&
hook
,
void
*
ptr
)
{
gHandler
(
)
;
// вызов lua калбека. Если он пройдёт с ошибкой управление текущему потоку не вернётся и код ниже не выполнится
return
hook
.
call_trampoline
(
ptr
)
;
// трамплин на оригинальную функцию
}



Lua:





Код:

local
lib
=
require
'lib'
lib
.
set_callback
(
function
(
)
error
(
"LUA ERROR"
)
-- условно какая-то ошибка.
end
)



Если внутри lua калбека происходит какая-то ошибка (у меня искуственно при помощи
Код:

error("CRASH")
) то lua скрипт закономерно должен крашнуться. Где-то внутри вызова
Код:

gHandler()
выполнится lua_error (через sol) и ошибка дойдёт до lua. Но, проблема в том что в этом случаи управление потоку не будет возвращено и весь код после вызова неудачно выполненной lua функции
Код:

gHandler()
не отработает. Соответственно в представленном варианте
Код:

return hook.call_trampoline(ptr);
не выполнится, а это нарушает хука и игра разумеется умирает.

Я могу заменить sol::unsafe_function на sol::protected_function, тогда sol обернёт вызов lua функции в pcall, который отловит ошибку в lua калбеке и трамплин выполнится. Но, в этом случаи lua скрипт не крашнется. Ошибка была отловлена и "проглочена" при помощи pcall, в C++ мы её дальше никак не обрабатываем. А это мне не подходит, я хочу получать краш lua скрипта при ошибках в lua калбеке.

Если добавить проброс пойманной ошибки через throw это ни к чему хорошему не приведёт. Оригинальный C++ калбек хука handleHookedFunc выполняется непосредственно в том же потоке что и захуканная функция, т.е. в потоке игры, а это значит что исключение пробрасывается внутрь игры, это если не брать в расчёт что трамплин, который идёт позже также не вызывается. Игра также умирает.

C++:





Код:

bool
handleHookedFunc
(
const
kthook
::
kthook_simple

&
hook
,
void
*
ptr
)
{
sol
::
protected_function_result result
=
gHandler
(
)
;
// вызов lua калбека. Если он пройдёт с ошибкой управление текущему потоку не вернётся и код ниже не выполнится
if
(
!
result
.
valid
(
)
)
{
sol
::
error err
=
result
;
throw
err
;
}
return
hook
.
call_trampoline
(
ptr
)
;
// трамплин на оригинальную функцию
}



Теперь смотрим на moonloader. Там через addEventHandler можно установить калбека на всякие события, например "onReceivePacket" (событие отправки пакета данный на сервер). Эти события по сути также хуки каких-то функций/методов в игре. И внутри этих lua калбеков ошибки обрабатываются так как я хочу. Они крашат lua скрипт, при этом это никак не мешает работе игры, несмотря на то что вызов lua калбека идёт из хука.

Lua:





Код:

addEventHandler
(
'onReceivePacket'
,
function
(
id
,
bs
)
error
(
'LUA ERROR'
)
end
)



Как мне реализовать такую же обработку ошибок как в moonloader? Чтобы ошибки внутри lua калбека крашили скрипт, а не игнорировались, но не ломали хук из которого они вызываются?

вайега52 13.06.2025 18:08

Цитата:

Сообщение от Tema05

Вот упрощённый вариант частей моей dll-ки. Я ставлю хук на функцию игры и из lua устанавливаю калбек, который будет вызываться из оригинального C++ калбека. Всё отлично работает, но есть проблема с обработкой ошибок.

C++:





Код:

// установка lua калбека для вызова из хука
void
set_callback
(
sol
::
this_state ts
,
sol
::
unsafe_function func
)
{
gHandler
=
func
;
}
// вызывается при подключении библиотеки из lua через require
sol
::
table
open
(
sol
::
this_state ts
)
{
sol
::
state_view
lua
(
ts
)
;
installHook
(
)
;
module
.
set_function
(
"set_callback"
,
&
set_cb
)
;
return
module
;
}
extern
"C"
__declspec
(
dllexport
)
int
luaopen_lib
(
lua_State
*
L
)
{
return
(
sol
::
c_call

)
(
L
)
;
}
sol
::
unsafe_function gHandler
;
// тут будет хранится функция lua калбека
kthook
::
kthook_simple

mHookedFunc
;
// объект хука
// функция установки C++ хука
void
installHook
(
)
{
mHookedFunc
.
set_dest
(
0x123456
)
;
// адрес функции в игре на которую нужно поставить хук
mHookedFunc
.
set_cb
(
handleHookedFunc
)
;
// калбек, который будет срабатывать при вызове функции
mHookedFunc
.
install
(
)
// устанавливает хук
}
// калбек захуканной функции
bool
handleHookedFunc
(
const
kthook
::
kthook_simple

&
hook
,
void
*
ptr
)
{
gHandler
(
)
;
// вызов lua калбека. Если он пройдёт с ошибкой управление текущему потоку не вернётся и код ниже не выполнится
return
hook
.
call_trampoline
(
ptr
)
;
// трамплин на оригинальную функцию
}



Lua:





Код:

local
lib
=
require
'lib'
lib
.
set_callback
(
function
(
)
error
(
"LUA ERROR"
)
-- условно какая-то ошибка.
end
)



Если внутри lua калбека происходит какая-то ошибка (у меня искуственно при помощи
Код:

error("CRASH")
) то lua скрипт закономерно должен крашнуться. Где-то внутри вызова
Код:

gHandler()
выполнится lua_error (через sol) и ошибка дойдёт до lua. Но, проблема в том что в этом случаи управление потоку не будет возвращено и весь код после вызова неудачно выполненной lua функции
Код:

gHandler()
не отработает. Соответственно в представленном варианте
Код:

return hook.call_trampoline(ptr);
не выполнится, а это нарушает хука и игра разумеется умирает.

Я могу заменить sol::unsafe_function на sol::protected_function, тогда sol обернёт вызов lua функции в pcall, который отловит ошибку в lua калбеке и трамплин выполнится. Но, в этом случаи lua скрипт не крашнется. Ошибка была отловлена и "проглочена" при помощи pcall, в C++ мы её дальше никак не обрабатываем. А это мне не подходит, я хочу получать краш lua скрипта при ошибках в lua калбеке.

Если добавить проброс пойманной ошибки через throw это ни к чему хорошему не приведёт. Оригинальный C++ калбек хука handleHookedFunc выполняется непосредственно в том же потоке что и захуканная функция, т.е. в потоке игры, а это значит что исключение пробрасывается внутрь игры, это если не брать в расчёт что трамплин, который идёт позже также не вызывается. Игра также умирает.

C++:





Код:

bool
handleHookedFunc
(
const
kthook
::
kthook_simple

&
hook
,
void
*
ptr
)
{
sol
::
protected_function_result result
=
gHandler
(
)
;
// вызов lua калбека. Если он пройдёт с ошибкой управление текущему потоку не вернётся и код ниже не выполнится
if
(
!
result
.
valid
(
)
)
{
sol
::
error err
=
result
;
throw
err
;
}
return
hook
.
call_trampoline
(
ptr
)
;
// трамплин на оригинальную функцию
}



Теперь смотрим на moonloader. Там через addEventHandler можно установить калбека на всякие события, например "onReceivePacket" (событие отправки пакета данный на сервер). Эти события по сути также хуки каких-то функций/методов в игре. И внутри этих lua калбеков ошибки обрабатываются так как я хочу. Они крашат lua скрипт, при этом это никак не мешает работе игры, несмотря на то что вызов lua калбека идёт из хука.

Lua:





Код:

addEventHandler
(
'onReceivePacket'
,
function
(
id
,
bs
)
error
(
'LUA ERROR'
)
end
)



Как мне реализовать такую же обработку ошибок как в moonloader? Чтобы ошибки внутри lua калбека крашили скрипт, а не игнорировались, но не ломали хук из которого они вызываются?

Я подозреваю, что обертка sol'а над луа функциями в случае ошибки кидает исключение, которое можешь попробовать поймать внутри C++ каллбека на хук

вайега52 13.06.2025 18:30

кстати, наверное тебе лучше использовать std::function, т.к. он более безопасный, но при этом, насколько помню, не оборачивает в pcall

Tema05 13.06.2025 19:10

Цитата:

Сообщение от вайега52

Я подозреваю, что обертка sol'а над луа функциями в случае ошибки кидает исключение, которое можешь попробовать поймать внутри C++ каллбека на хук

Оно не кидает исключение. При ошибке с sol::unsafe_function там идёт longjmp из-за lua_error и управление уйдёт, даже если в try catch завернуть, а при sol::protected_function исключение не передаётся, только статус и текст ошибки если есть.

Цитата:

Сообщение от вайега52

кстати, наверное тебе лучше использовать std::function, т.к. он более безопасный, но при этом, насколько помню, не оборачивает в pcall

std::function (видимо ты имел ввиду sol::function) это и есть sol::unsafe_function или sol::protected_function в зависимости от наличия
Код:

#define SOL_NO_EXCEPTIONS 1
https://forum.antichat.xyz/attachments/28614074/

Я когда дебаггером пытался разобраться как оно в moonloader работает заметил, что иногда скрипт может крашнуться одновременно из-за нескольких ошибок. Что по идеи невозможно из-за однопоточного устройства lua или происходит из-за гонки потоков. Причём это не одно и то же событие и разные. Значит moonloader как-то в отдельных потоках или корутиных выполняет все эти события. Это скорее всего и позволяет обрабатывать ошибки на месте без потери управления потоком

https://forum.antichat.xyz/attachments/28614074/


Время: 23:59