1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-19 14:25:11 +03:00

Prevent Lua from allocating all heap memory (Horus) (#4440)

* Fixes #4284: Prevent Lua from allocating all heap memory (Horus)
Lua bitmap functions cleanup and docs update
Added x or y < 0 check to drawBitmap()

* Proper float constant
This commit is contained in:
Damjan Adamic 2017-02-11 22:21:14 +01:00 committed by Bertrand Songis
parent be61e07939
commit e80c4c858e
8 changed files with 94 additions and 31 deletions

View file

@ -255,7 +255,7 @@ class BitmapBuffer: public BitmapBufferBase<uint16_t>
template<class T>
void drawBitmap(coord_t x, coord_t y, const T * bmp, coord_t srcx=0, coord_t srcy=0, coord_t w=0, coord_t h=0, float scale=0)
{
if (!data || !bmp || x >= width || y >= height)
if (!data || !bmp || x < 0 || x >= width || y < 0 || y >= height)
return;
coord_t srcw = bmp->getWidth();

View file

@ -325,10 +325,19 @@ static int luaLcdDrawSource(lua_State *L)
/*luadoc
@function Bitmap.open(name)
Loads a bitmap in memory, for later use with lcd.drawBitmap()
Loads a bitmap in memory, for later use with lcd.drawBitmap(). Bitmaps should be loaded only
once, returned object should be stored and used for drawing. If loading fails for whatever
reason the resulting bitmap object will have width and height set to zero.
Bitmap loading can fail if:
* File is not found or contains invalid image
* System is low on memory
* Combined memory usage of all Lua script bitmaps exceeds certain value
@param name (string) full path to the bitmap on SD card (i.e. /IMAGES/test.bmp)
@retval bitmap (object) a bitmap object that can be used with other bitmap functions
@notice Only available on Horus
@status current Introduced in 2.2.0
@ -337,18 +346,25 @@ static int luaOpenBitmap(lua_State * L)
{
const char * filename = luaL_checkstring(L, 1);
BitmapBuffer ** ptr = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *));
*ptr = BitmapBuffer::load(filename);
BitmapBuffer ** b = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *));
if (*ptr == NULL && G(L)->gcrunning) {
if (luaExtraMemoryUsage > LUA_MEM_EXTRA_MAX) {
// already allocated more than max allowed, fail
TRACE("luaOpenBitmap: Error, using too much memory %u/%u", luaExtraMemoryUsage, LUA_MEM_EXTRA_MAX);
*b = 0;
}
else {
*b = BitmapBuffer::load(filename);
if (*b == NULL && G(L)->gcrunning) {
luaC_fullgc(L, 1); /* try to free some memory... */
*ptr = BitmapBuffer::load(filename); /* try again */
*b = BitmapBuffer::load(filename); /* try again */
}
}
if (*ptr) {
uint32_t size = (*ptr)->getDataSize();
if (*b) {
uint32_t size = (*b)->getDataSize();
luaExtraMemoryUsage += size;
TRACE("luaOpenBitmap: %p (%u)", *ptr, size);
TRACE("luaOpenBitmap: %p (%u)", *b, size);
}
luaL_getmetatable(L, LUA_BITMAPHANDLE);
@ -364,13 +380,16 @@ static BitmapBuffer * checkBitmap(lua_State * L, int index)
return *b;
}
/*luadoc
@function Bitmap.getSize(name)
Return width, heigh of a bitmap in memory
Return width, height of a bitmap object
@param bitmap (pointer) point to a bitmap previously opened with Bipmap.open()
@param bitmap (pointer) point to a bitmap previously opened with Bitmap.open()
@retval multiple returns 2 values:
* (number) width in pixels
* (number) height in pixels
@notice Only available on Horus
@ -378,7 +397,7 @@ Return width, heigh of a bitmap in memory
*/
static int luaGetBitmapSize(lua_State * L)
{
BitmapBuffer * b = checkBitmap(L, 1);
const BitmapBuffer * b = checkBitmap(L, 1);
if (b) {
lua_pushinteger(L, b->getWidth());
lua_pushinteger(L, b->getHeight());
@ -392,11 +411,18 @@ static int luaGetBitmapSize(lua_State * L)
static int luaDestroyBitmap(lua_State * L)
{
BitmapBuffer * ptr = checkBitmap(L, 1);
uint32_t size = ptr->getDataSize();
TRACE("luaDestroyBitmap: %p (%u)", ptr, size);
if (luaExtraMemoryUsage > size) luaExtraMemoryUsage -= size;
delete ptr;
BitmapBuffer * b = checkBitmap(L, 1);
if (b) {
uint32_t size = b->getDataSize();
TRACE("luaDestroyBitmap: %p (%u)", b, size);
if (luaExtraMemoryUsage >= size) {
luaExtraMemoryUsage -= size;
}
else {
luaExtraMemoryUsage = 0;
}
delete b;
}
return 0;
}
@ -421,11 +447,12 @@ void registerBitmapClass(lua_State * L)
Displays a bitmap at (x,y)
@param bitmap (pointer) point to a bitmap previously opened with Bipmap.open()
@param bitmap (pointer) point to a bitmap previously opened with Bitmap.open()
@param x,y (positive numbers) starting coordinates
@param scale (positive numbers) scale in %, 50 divides size by two, 100 is unchanged, 200 doubles size
@param scale (positive numbers) scale in %, 50 divides size by two, 100 is unchanged, 200 doubles size.
Omitting scale draws image in 1:1 scale and is faster than specifying 100 for scale.
@notice Only available on Horus
@ -434,15 +461,19 @@ Displays a bitmap at (x,y)
static int luaLcdDrawBitmap(lua_State *L)
{
if (!luaLcdAllowed) return 0;
const BitmapBuffer * bitmap = checkBitmap(L, 1);
int x = luaL_checkinteger(L, 2);
int y = luaL_checkinteger(L, 3);
unsigned scale = luaL_optunsigned(L, 4, 0);
const BitmapBuffer * b = checkBitmap(L, 1);
if (bitmap) {
lcd->drawBitmap(x, y, bitmap, 0, 0, 0, 0, (float) scale/100);
if (b) {
unsigned int x = luaL_checkunsigned(L, 2);
unsigned int y = luaL_checkunsigned(L, 3);
unsigned int scale = luaL_optunsigned(L, 4, 0);
if (scale) {
lcd->drawBitmap(x, y, b, 0, 0, 0, 0, scale/100.0f);
}
else {
lcd->drawBitmap(x, y, b);
}
}
return 0;
}
#elif LCD_DEPTH > 1

View file

@ -165,7 +165,7 @@ void luaClose(lua_State ** L)
}
else {
// we can only disable Lua for the rest of the session
luaDisable();
if (*L == lsScripts) luaDisable();
}
UNPROTECT_LUA();
*L = NULL;
@ -954,6 +954,27 @@ bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage)
return scriptWasRun;
}
void checkLuaMemoryUsage()
{
#if (LUA_MEM_MAX > 0)
uint32_t totalMemUsed = luaGetMemUsed(lsScripts);
#if defined(COLORLCD)
totalMemUsed += luaGetMemUsed(lsWidgets);
totalMemUsed += luaExtraMemoryUsage;
#endif
if (totalMemUsed > LUA_MEM_MAX) {
TRACE("checkLuaMemoryUsage(): max limit reached (%u), killing Lua", totalMemUsed);
// disable Lua scripts
luaClose(&lsScripts);
luaDisable();
#if defined(COLORLCD)
// disable widgets
luaClose(&lsWidgets);
#endif
}
#endif
}
uint32_t luaGetMemUsed(lua_State * L)
{
return L ? (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0) : 0;

View file

@ -118,6 +118,7 @@ extern ScriptInternalData scriptInternalData[MAX_SCRIPTS];
extern ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS];
void luaClose(lua_State ** L);
bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage);
void checkLuaMemoryUsage();
void luaExec(const char * filename);
void luaDoGc(lua_State * L, bool full);
void luaError(lua_State * L, uint8_t error, bool acknowledge=true);

View file

@ -519,6 +519,7 @@ void luaInitThemesAndWidgets()
// if we got panic during registration
// we disable Lua for this session
// luaDisable();
luaClose(&lsWidgets);
lsWidgets = 0;
}
UNPROTECT_LUA();

View file

@ -138,6 +138,9 @@ void periodicTick_1s()
void periodicTick_10s()
{
checkBatteryAlarms();
#if defined(LUA)
checkLuaMemoryUsage();
#endif
}
void periodicTick()

View file

@ -83,6 +83,10 @@ extern "C" {
#define BOOTLOADER_SIZE 0x8000
#define FIRMWARE_ADDRESS 0x08000000
#define MB *1024*1024
#define LUA_MEM_EXTRA_MAX (2 MB) // max allowed memory usage for Lua bitmaps (in bytes)
#define LUA_MEM_MAX (6 MB) // max allowed memory usage for complete Lua (in bytes), 0 means unlimited
// HSI is at 168Mhz (over-drive is not enabled!)
#define PERI1_FREQUENCY 42000000
#define PERI2_FREQUENCY 84000000

View file

@ -91,6 +91,8 @@ extern "C" {
#define BOOTLOADER_SIZE 0x8000
#define FIRMWARE_ADDRESS 0x08000000
#define LUA_MEM_MAX (0) // max allowed memory usage for complete Lua (in bytes), 0 means unlimited
#if defined(PCBX9E)
#define PERI1_FREQUENCY 42000000
#define PERI2_FREQUENCY 84000000