Hello,
The following code results in memory error, particularly invalid free() when quality = 100.
#include <vector>
#include <memory>
#include <stdint.h>
#include <random>
#include <ctime>
#include <NvJpegEncoder.h>
int main()
{
int width = 512;
int height = 512;
std::srand(std::time(0));
std::vector<uint8_t> bufY(width * height);
for (int j = 0; j < width * height; j++) bufY[j] = std::rand() % 256;
std::vector<uint8_t> bufU(width * height / 4);
for (int k = 0; k < width * height / 4; k++) bufU[k] = std::rand() % 256;
std::vector<uint8_t> bufV(width * height / 4);
for (int l = 0; l < width * height / 4; l++) bufV[l] = std::rand() % 256;
int quality = 100;
auto m_encoder = std::unique_ptr<NvJPEGEncoder>(NvJPEGEncoder::createJPEGEncoder("jpenenc"));
NvBuffer buffer(V4L2_PIX_FMT_YUV420M, width, height, 0);
buffer.planes[0].data = bufY.data();
buffer.planes[0].bytesused = width * height;
buffer.planes[1].data = bufU.data();
buffer.planes[1].bytesused = width * height / 4;
buffer.planes[2].data = bufV.data();
buffer.planes[2].bytesused = width * height / 4;
uint64_t outBufSize = 3 * width * height / 2;
uint8_t *outBufPtr;
try
{
outBufPtr = new uint8_t [outBufSize];
}
catch(const std::bad_alloc& e)
{
printf("Allocation of memory for encoding failed \n");
return 1;
}
if (m_encoder->encodeFromBuffer(buffer,
JCS_YCbCr,
&outBufPtr,
outBufSize,
quality) < 0)
{
printf("Encoding failed");
delete[] outBufPtr;
return 1;
}
delete[] outBufPtr;
return 0;
}
However, empirically it was found out that when the buffer size is doubled (3 * width * height), errors disappear. In addition to that, when the code is compiled with the address sanitizer enabled, it seems that there is an unauthorized memory write inside encodeFromBuffer() (heap buffer overflow). Please see the logs below.
==112577==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xffff49a7d800 at pc 0xffff9778edc0 bp 0xffffebcc7730 sp 0xffffebcc77b8
WRITE of size 611703 at 0xffff49a7d800 thread T0
#0 0xffff9778edbc in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:790
#1 0xffff76d37fdc (/usr/lib/aarch64-linux-gnu/tegra/libnvjpeg.so+0x3efdc)
#2 0xffff4b9253f4 (/usr/lib/aarch64-linux-gnu/tegra/libnvmmlite_image.so+0x43f4)
#3 0xffff4b925690 (/usr/lib/aarch64-linux-gnu/tegra/libnvmmlite_image.so+0x4690)
#4 0xffff52d143b4 in NvMMLiteBlockDoWork (/usr/lib/aarch64-linux-gnu/tegra/libnvmmlite_utils.so+0x23b4)
#5 0xffff52d27bdc (/usr/lib/aarch64-linux-gnu/tegra/libnvmmlite.so+0xbdc)
#6 0xffff76d386a0 in jpegTegraEncoderCompress (/usr/lib/aarch64-linux-gnu/tegra/libnvjpeg.so+0x3f6a0)
#7 0xffff76cfec04 in jpeg_write_raw_data (/usr/lib/aarch64-linux-gnu/tegra/libnvjpeg.so+0x5c04)
#8 0xaaaaca21a394 in NvJPEGEncoder::encodeFromBuffer(NvBuffer&, J_COLOR_SPACE, unsigned char**, unsigned long&, int) /rootfs_arm64/usr/src/jetson_multimedia_api/samples/common/classes/NvJpegEncoder.cpp:267
#9 0xaaaac96b69a0 in main main.cpp:343
#10 0xffff52e16e0c in __libc_start_main ../csu/libc-start.c:308
#11 0xaaaac98636c4 (/usr/bin/process+0x3f36c4)
0xffff49a7d800 is located 0 bytes to the right of 393216-byte region [0xffff49a1d800,0xffff49a7d800)
allocated by thread T0 here:
#0 0xffff977f02b8 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cc:107
#1 0xaaaac96b6938 in main main.cpp:333
#2 0xffff52e16e0c in __libc_start_main ../csu/libc-start.c:308
#3 0xaaaac98636c4 (/usr/bin/process+0x3f36c4)
SUMMARY: AddressSanitizer: heap-buffer-overflow ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:790 in __interceptor_memcpy
Shadow bytes around the buggy address:
0x200fe934fab0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x200fe934fac0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x200fe934fad0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x200fe934fae0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x200fe934faf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x200fe934fb00:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x200fe934fb10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x200fe934fb20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x200fe934fb30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x200fe934fb40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x200fe934fb50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==112577==ABORTING
After experimenting a lot I saw the same crashes in production and I suspect that there is a memory bug inside encodeFromBuffer, which I could neither explain, nor eliminate as I can not see the code.
Could you please help to fix the bug?
In addition: I have opened a topic sometime ago, which did not received an answer. Could you please reopen and help to progress that as well? The link to the topic: Segmentation fault in NvJPEGEncoder::encodeFromBuffer when encoder accessed from multiple threads - Jetson & Embedded Systems / Jetson AGX Orin - NVIDIA Developer Forums
The jetpack version is 5.1.3.
Thank you!