ZBar is an open source software suite for reading bar codes from various sources, including webcams. As its development stopped in 2012, I took the task of keeping it updated with the V4L2 API. This is the main repository for it. There's a clone at at LinuxTV.org, and another one at gitlab.
We are using the ZBar library for continuous image analytics (i.e. scanning new frames 24/7) and when doing so we have found that the library is leaking memory when finding QR codes.
Problem description
I have identified the issue to the recycling of zbar_symbol_t. When a symbol is discarded with the _zbar_image_scanner_recycle_syms() function, it is not free'd, but rather added to the scanners recycle[i] bucket. There are 5 different buckets depending on the size of the discarded symbol. When allocating a new symbol with _zbar_image_scanner_alloc_sym() it will reuse a symbol that is in the same or smaller sized bucket (but never one from a bigger bucket).
The issue is that the QR decoder will in the qr_code_data_list_extract_text() function always request a symbol with size 0 (_zbar_image_scanner_alloc_sym(iscn, ZBAR_QRCODE, 0);) and then reallocate the data field to the size needed.
This means that whenever we free the symbol it will be placed in one of the buckets with index 1 to 4, but we only reuse symbols from bucket 0. Therefore, every time we find a QR code we allocate new memory which is then never free'd, but instead stored in the recycle list. Memory is therefore continuously increasing until the application crashes.
Technically, this is not a memory leak since we never loose the reference to the memory, therefore I could not find it with valgrind, but it is not free'd until we clean-up the scanner. This means that the number of scans we can do before running out of memory is limited.
Solution
I don't know if there is any simple fix to this since it seems like the QR decoder does not know from the start how big the buffer needs to be. We can therefore not allocate the symbols before we know that.
Our quick fix is to set RECYCLE_BUCKETS to 1, meaning that every recycled symbol will have its data field free'd and only the symbol struct will be recycled. Doing so we did however discover what seems like another bug in the _zbar_image_scanner_alloc_sym() function:
When a 0-sized symbol is requested, the first loop will exit with i=0 which makes sense (since these are in the 0:th index in the recycle array):
for (i = 0; i < RECYCLE_BUCKETS - 1; i++)
if (datalen <= 1 << (i * 2))
break;
But then the next for-loop will never enter, as i > 0 is false:
for (; i > 0; i--)
if ((sym = iscn->recycle[i].head)) {
STAT(sym_recycle[i]);
break;
}
This means that sym will still be zero, and a new symbol will be allocated:
We are using the ZBar library for continuous image analytics (i.e. scanning new frames 24/7) and when doing so we have found that the library is leaking memory when finding QR codes.
Problem description I have identified the issue to the recycling of
zbar_symbol_t
. When a symbol is discarded with the_zbar_image_scanner_recycle_syms()
function, it is not free'd, but rather added to the scannersrecycle[i]
bucket. There are 5 different buckets depending on the size of the discarded symbol. When allocating a new symbol with_zbar_image_scanner_alloc_sym()
it will reuse a symbol that is in the same or smaller sized bucket (but never one from a bigger bucket).The issue is that the QR decoder will in the
qr_code_data_list_extract_text()
function always request a symbol with size 0 (_zbar_image_scanner_alloc_sym(iscn, ZBAR_QRCODE, 0);
) and then reallocate the data field to the size needed.This means that whenever we free the symbol it will be placed in one of the buckets with index 1 to 4, but we only reuse symbols from bucket 0. Therefore, every time we find a QR code we allocate new memory which is then never free'd, but instead stored in the
recycle
list. Memory is therefore continuously increasing until the application crashes.Technically, this is not a memory leak since we never loose the reference to the memory, therefore I could not find it with valgrind, but it is not free'd until we clean-up the scanner. This means that the number of scans we can do before running out of memory is limited.
Solution I don't know if there is any simple fix to this since it seems like the QR decoder does not know from the start how big the buffer needs to be. We can therefore not allocate the symbols before we know that.
Our quick fix is to set
RECYCLE_BUCKETS
to1
, meaning that every recycled symbol will have its data field free'd and only the symbol struct will be recycled. Doing so we did however discover what seems like another bug in the_zbar_image_scanner_alloc_sym()
function:When a 0-sized symbol is requested, the first loop will exit with
i=0
which makes sense (since these are in the 0:th index in therecycle
array):But then the next for-loop will never enter, as
i > 0
is false:This means that
sym
will still be zero, and a new symbol will be allocated:Our complete quick-fix for this is therefore: