Fixed fb_alloc() with mark for recently re-worked code.

I also tested the firmware for about an hour to make sure there was no
stack leak.

Note that I prefer for fb_free() to still be called versus
fb_free_till_mark() doing that for you in the code.

For functions without this fix they will just free the entire fb_alloc
stack when an exception happens. For functions with this fix they will
only free up to and including the mark. Since there are no places in the
firmware where you could start building a second fb_alloc stack when one
is already in place this point is moot currently. But, if we do
something like that in the future the problem will have already been
solved.

Any new code or re-worked code should use the mark function.
This commit is contained in:
Kwabena W. Agyeman 2017-01-18 18:39:08 -05:00
parent 553f2bfcf3
commit 02af722fe8
4 changed files with 35 additions and 32 deletions

View File

@ -36,7 +36,7 @@ void fb_alloc_mark()
// Check if allocation overwrites the framebuffer pixels
if (new_pointer < (char *) FB_PIXELS()) {
fb_alloc_fail();
nlr_raise_for_fb_alloc_mark(mp_obj_new_exception_msg(&mp_type_MemoryError, "FB Alloc Collision!!!"));
}
// fb_alloc does not allow regions which are a size of 0 to be alloced,

View File

@ -11,6 +11,8 @@
#include <stdint.h>
void fb_alloc_init0();
uint32_t fb_avail();
void fb_alloc_mark();
void fb_alloc_free_till_mark();
void *fb_alloc(uint32_t size);
void *fb_alloc0(uint32_t size);
void *fb_alloc_all(uint32_t *size); // returns pointer and sets size

View File

@ -229,23 +229,18 @@ static mp_obj_t py_image_compress(uint n_args, const mp_obj_t *args, mp_map_t *k
{
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img), "Operation not supported on JPEG");
int arg_q = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), " 1 <= quality <= 100");
uint32_t size;
fb_alloc_mark();
uint8_t *buffer = fb_alloc_all(&size);
image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer };
if (jpeg_compress(arg_img, &out, arg_q, false)) { // JPEG overflow
fb_free();
nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, "Out of Memory!!!"));
}
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
PY_ASSERT_TRUE_MSG(out.bpp <= (((arg_img->w * arg_img->h)
+ UINT32_T_MASK) >> UINT32_T_SHIFT), "Can't compress in place!");
PY_ASSERT_TRUE_MSG(out.bpp <= (((arg_img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * arg_img->h), "Can't compress in place!");
break;
}
case IMAGE_BPP_GRAYSCALE: {
@ -264,6 +259,7 @@ static mp_obj_t py_image_compress(uint n_args, const mp_obj_t *args, mp_map_t *k
memcpy(arg_img->data, out.data, out.bpp);
arg_img->bpp = out.bpp;
fb_free();
fb_alloc_free_till_mark();
if (fb->pixels == arg_img->data) {
fb->bpp = arg_img->bpp;
@ -276,28 +272,19 @@ static mp_obj_t py_image_compressed(uint n_args, const mp_obj_t *args, mp_map_t
{
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img), "Operation not supported on JPEG");
int arg_q = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), " 1 <= quality <= 100");
uint32_t size;
fb_alloc_mark();
uint8_t *buffer = fb_alloc_all(&size);
image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer };
if (jpeg_compress(arg_img, &out, arg_q, false)) { // JPEG overflow
fb_free();
nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, "Out of Memory!!!"));
}
uint8_t *temp = xalloc_try_alloc(out.bpp);
if (temp == NULL) {
fb_free();
nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, "Out of Memory!!!"));
}
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
uint8_t *temp = xalloc(out.bpp);
memcpy(temp, out.data, out.bpp);
out.data = temp;
fb_free();
fb_alloc_free_till_mark();
return py_image_from_struct(&out);
}
@ -863,7 +850,9 @@ static mp_obj_t py_image_lens_corr(uint n_args, const mp_obj_t *args, mp_map_t *
(n_args > 2) ? mp_obj_get_float(args[2]) : 1.0);
PY_ASSERT_TRUE_MSG(zoom >= 1.0, "zoom must be > 1");
fb_alloc_mark();
imlib_lens_corr(arg_img, strength, zoom);
fb_alloc_free_till_mark();
return args[0];
}
@ -1258,6 +1247,7 @@ mp_obj_t py_histogram_get_percentile(mp_obj_t self_in, mp_obj_t percentile)
hist.LBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->LBins)->len;
hist.ABinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->ABins)->len;
hist.BBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->BBins)->len;
fb_alloc_mark();
hist.LBins = fb_alloc(hist.LBinCount * sizeof(float));
hist.ABins = fb_alloc(hist.ABinCount * sizeof(float));
hist.BBins = fb_alloc(hist.BBinCount * sizeof(float));
@ -1279,6 +1269,7 @@ mp_obj_t py_histogram_get_percentile(mp_obj_t self_in, mp_obj_t percentile)
if (hist.BBinCount) fb_free();
if (hist.ABinCount) fb_free();
if (hist.LBinCount) fb_free();
fb_alloc_free_till_mark();
py_percentile_obj_t *o = m_new_obj(py_percentile_obj_t);
o->base.type = &py_percentile_type;
@ -1297,6 +1288,7 @@ mp_obj_t py_histogram_get_statistics(mp_obj_t self_in)
hist.LBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->LBins)->len;
hist.ABinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->ABins)->len;
hist.BBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->BBins)->len;
fb_alloc_mark();
hist.LBins = fb_alloc(hist.LBinCount * sizeof(float));
hist.ABins = fb_alloc(hist.ABinCount * sizeof(float));
hist.BBins = fb_alloc(hist.BBinCount * sizeof(float));
@ -1318,6 +1310,7 @@ mp_obj_t py_histogram_get_statistics(mp_obj_t self_in)
if (hist.BBinCount) fb_free();
if (hist.ABinCount) fb_free();
if (hist.LBinCount) fb_free();
fb_alloc_free_till_mark();
py_statistics_obj_t *o = m_new_obj(py_statistics_obj_t);
o->base.type = &py_statistics_type;
@ -1388,7 +1381,6 @@ static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map
rectangle_t roi;
py_helper_lookup_rectangle(kw_args, arg_img, &roi);
// TODO: Need to set fb_alloc trap here to recover from any exception...
histogram_t hist;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
@ -1398,6 +1390,7 @@ static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map
PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2");
hist.ABinCount = 0;
hist.BBinCount = 0;
fb_alloc_mark();
hist.LBins = fb_alloc(hist.LBinCount * sizeof(float));
hist.ABins = NULL;
hist.BBins = NULL;
@ -1411,6 +1404,7 @@ static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map
PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2");
hist.ABinCount = 0;
hist.BBinCount = 0;
fb_alloc_mark();
hist.LBins = fb_alloc(hist.LBinCount * sizeof(float));
hist.ABins = NULL;
hist.BBins = NULL;
@ -1430,6 +1424,7 @@ static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map
PY_ASSERT_TRUE_MSG(b_bins >= 2, "bins must be >= 2");
hist.BBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_b_bins), b_bins);
PY_ASSERT_TRUE_MSG(hist.BBinCount >= 2, "b_bins must be >= 2");
fb_alloc_mark();
hist.LBins = fb_alloc(hist.LBinCount * sizeof(float));
hist.ABins = fb_alloc(hist.ABinCount * sizeof(float));
hist.BBins = fb_alloc(hist.BBinCount * sizeof(float));
@ -1464,6 +1459,7 @@ static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map
if (hist.BBinCount) fb_free();
if (hist.ABinCount) fb_free();
if (hist.LBinCount) fb_free();
fb_alloc_free_till_mark();
return o;
}
@ -1477,7 +1473,6 @@ static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_ma
rectangle_t roi;
py_helper_lookup_rectangle(kw_args, arg_img, &roi);
// TODO: Need to set fb_alloc trap here to recover from any exception...
histogram_t hist;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
@ -1487,6 +1482,7 @@ static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_ma
PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2");
hist.ABinCount = 0;
hist.BBinCount = 0;
fb_alloc_mark();
hist.LBins = fb_alloc(hist.LBinCount * sizeof(float));
hist.ABins = NULL;
hist.BBins = NULL;
@ -1500,6 +1496,7 @@ static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_ma
PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2");
hist.ABinCount = 0;
hist.BBinCount = 0;
fb_alloc_mark();
hist.LBins = fb_alloc(hist.LBinCount * sizeof(float));
hist.ABins = NULL;
hist.BBins = NULL;
@ -1519,6 +1516,7 @@ static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_ma
PY_ASSERT_TRUE_MSG(b_bins >= 2, "bins must be >= 2");
hist.BBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_b_bins), b_bins);
PY_ASSERT_TRUE_MSG(hist.BBinCount >= 2, "b_bins must be >= 2");
fb_alloc_mark();
hist.LBins = fb_alloc(hist.LBinCount * sizeof(float));
hist.ABins = fb_alloc(hist.ABinCount * sizeof(float));
hist.BBins = fb_alloc(hist.BBinCount * sizeof(float));
@ -1535,6 +1533,7 @@ static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_ma
if (hist.BBinCount) fb_free();
if (hist.ABinCount) fb_free();
if (hist.LBinCount) fb_free();
fb_alloc_free_till_mark();
py_statistics_obj_t *o = m_new_obj(py_statistics_obj_t);
o->base.type = &py_statistics_type;
@ -1739,12 +1738,13 @@ static mp_obj_t py_image_find_blobs(uint n_args, const mp_obj_t *args, mp_map_t
bool merge = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge), false);
int margin = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_margin), 0);
// TODO: Need to set fb_alloc trap here to recover from any exception...
list_t out;
fb_alloc_mark();
imlib_find_blobs(&out, arg_img, &roi, x_stride, y_stride, &thresholds, invert, area_threshold, pixels_threshold, merge, margin);
fb_alloc_free_till_mark();
list_free(&thresholds);
mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL);
mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL);
for (size_t i = 0; list_size(&out); i++) {
find_blobs_list_lnk_data_t lnk_data;
list_pop_front(&out, &lnk_data);
@ -1897,11 +1897,12 @@ static mp_obj_t py_image_find_qrcodes(uint n_args, const mp_obj_t *args, mp_map_
rectangle_t roi;
py_helper_lookup_rectangle(kw_args, arg_img, &roi);
// TODO: Need to set fb_alloc trap here to recover from any exception...
list_t out;
fb_alloc_mark();
imlib_find_qrcodes(&out, arg_img, &roi);
mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL);
fb_alloc_free_till_mark();
mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL);
for (size_t i = 0; list_size(&out); i++) {
find_qrcodes_list_lnk_data_t lnk_data;
list_pop_front(&out, &lnk_data);

View File

@ -66,7 +66,7 @@ static mp_obj_t py_sensor_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *
}
if (sensor_snapshot((struct image*) py_image_cobj(image), line_filter_func, line_filter_args)==-1) {
nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!"));
return mp_const_false;
}
@ -77,7 +77,7 @@ static mp_obj_t py_sensor_skip_frames(uint n_args, const mp_obj_t *args) {
int frames = (n_args == 1) ? mp_obj_get_int(args[0]) : 10; // OV Recommended.
for (int i = 0; i < frames; i++) {
if (sensor_snapshot(NULL, NULL, NULL) == -1) {
nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!"));
}
}
return mp_const_none;
@ -129,7 +129,7 @@ static mp_obj_t py_sensor_set_framerate(mp_obj_t framerate) {
fr = FRAMERATE_60FPS;
break;
default:
nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid framerate"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid framerate"));
break;
}
@ -199,7 +199,7 @@ static mp_obj_t py_sensor_set_gainceiling(mp_obj_t gainceiling) {
gain = GAINCEILING_128X;
break;
default:
nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid gainceiling"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid gainceiling"));
break;
}