libzimg: AddressSanitizer: SEGV
I have a collection of JPEG files that I would like to scale down by a specific size with zimg (aka z.lib) library:
This is my code snippet:
#include <cstdio> // fopen, fseek, ftell, fread, fwrite
#include <cstdint> // uint8_t
#include <cstdlib> // aligned_alloc, free
#include <cstring> // strlen, strtok, strcat
#include <cerrno> // errno
#include <jpeglib.h> // jpeg compression/decompression routines
#include <zimg.h> // colorspace and scaling routines
static void print_zimg_error(const char *function_name)
{
char err_msg[1024];
int err_code = zimg_get_last_error(err_msg, sizeof(err_msg));
if (err_code != ZIMG_ERROR_SUCCESS)
fprintf(stderr, "%s(): %s\n", function_name, err_msg);
zimg_clear_last_error();
return;
}
static int width_to_stride(int w)
{
return ((w + 31) & ~31);
}
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "usage: %s <filename>.JPG\n", argv[0]);
return 1;
}
const char *src_name = argv[1];
char *src_name_2 = strdup(src_name);
const char *delim = "/";
char *tok;
char *dst_name;
strtok(src_name_2, delim);
while ((tok = strtok(NULL, delim)) != NULL)
dst_name = tok;
dst_name = strcat(strtok(dst_name, "."), ".JPG");
// Define input sizes
int src_width = 5152;
int src_height = 3864;
int src_stride = width_to_stride(src_width) + (width_to_stride(src_width / 2) * 2);
int src_pixel_count = (src_stride * src_height) + (src_stride * (src_height / 2)) + (src_stride * (src_height / 2));
// Define output sizes
int dst_width = 2560;
int dst_height = 1400;
int dst_stride = width_to_stride(dst_width) + (width_to_stride(dst_width / 2) * 2);
int dst_pixel_count = (dst_stride * dst_height) + (dst_stride * (dst_height / 2)) + (dst_stride * (dst_height / 2));
uint8_t *src_jpeg_buf = (uint8_t *) aligned_alloc(32, ((src_pixel_count) + 32 - 1) & ~(32 - 1));
if (src_jpeg_buf == NULL) {
fprintf(stderr, "aligned_alloc(): src_jpeg_buf is NULL\n");
return 1;
}
uint8_t *dst_jpeg_buf = (uint8_t *) aligned_alloc(32, ((dst_pixel_count) + 32 - 1) & ~(32 - 1));
if (dst_jpeg_buf == NULL) {
fprintf(stderr, "aligned_alloc(): dst_jpeg_buf is NULL\n");
return 1;
}
FILE *src_file = fopen(src_name, "rb");
if (src_file == NULL) {
perror("fopen()");
return 1;
}
struct jpeg_decompress_struct jpeg_dec;
struct jpeg_error_mgr jpeg_err;
jpeg_dec.err = jpeg_std_error(&jpeg_err);
jpeg_create_decompress(&jpeg_dec);
jpeg_stdio_src(&jpeg_dec, src_file);
jpeg_read_header(&jpeg_dec, TRUE);
jpeg_start_decompress(&jpeg_dec);
int row_stride = jpeg_dec.output_width * jpeg_dec.output_components;
JSAMPARRAY scanline_buffer = (*jpeg_dec.mem->alloc_sarray)((j_common_ptr) &jpeg_dec, JPOOL_IMAGE, row_stride, 1);
while (jpeg_dec.output_scanline < jpeg_dec.output_height) {
jpeg_read_scanlines(&jpeg_dec, scanline_buffer, 1);
memcpy(src_jpeg_buf + (jpeg_dec.output_scanline - 1) * row_stride, scanline_buffer[0], row_stride);
}
jpeg_finish_decompress(&jpeg_dec);
jpeg_destroy_decompress(&jpeg_dec);
fclose(src_file);
// Initialize zimg structures to defaults
zimg_filter_graph *graph = 0;
zimg_image_buffer_const src_buf = { ZIMG_API_VERSION };
zimg_image_buffer dst_buf = { ZIMG_API_VERSION };
zimg_image_format src_format;
zimg_image_format dst_format;
zimg_graph_builder_params params;
size_t tmp_size;
void *tmp = 0;
zimg_image_format_default(&src_format, ZIMG_API_VERSION);
print_zimg_error("zimg_image_format_default");
zimg_image_format_default(&dst_format, ZIMG_API_VERSION);
print_zimg_error("zimg_image_format_default");
zimg_graph_builder_params_default(¶ms, ZIMG_API_VERSION);
params.resample_filter = ZIMG_RESIZE_BICUBIC;
params.filter_param_a = -0.5;
params.filter_param_b = 0.25;
params.resample_filter_uv = ZIMG_RESIZE_BICUBIC;
params.filter_param_a_uv = -0.5;
params.filter_param_b_uv = 0.25;
src_format.width = src_width;
src_format.height = src_height;
src_format.pixel_type = ZIMG_PIXEL_BYTE;
src_format.subsample_w = 1;
src_format.subsample_h = 0;
src_format.color_family = ZIMG_COLOR_YUV;
dst_format.width = dst_width;
dst_format.height = dst_height;
dst_format.pixel_type = ZIMG_PIXEL_BYTE;
dst_format.subsample_w = 1;
dst_format.subsample_h = 1;
dst_format.color_family = ZIMG_COLOR_YUV;
graph = zimg_filter_graph_build(&src_format, &dst_format, ¶ms);
if (graph == NULL) {
fprintf(stderr, "zimg_filter_graph_build(): graph is NULL\n");
return 1;
}
print_zimg_error("zimg_filter_graph_build");
zimg_filter_graph_get_tmp_size(graph, &tmp_size);
print_zimg_error("zimg_filter_graph_get_tmp_size");
tmp = aligned_alloc(32, tmp_size);
if (tmp == NULL) {
fprintf(stderr, "aligned_alloc(): tmp is NULL\n");
return 1;
}
src_buf.plane[0].data = src_jpeg_buf;
src_buf.plane[0].stride = src_stride;
src_buf.plane[0].mask = ZIMG_BUFFER_MAX;
src_buf.plane[0].data = dst_jpeg_buf;
src_buf.plane[0].stride = dst_stride;
src_buf.plane[0].mask = ZIMG_BUFFER_MAX;
zimg_filter_graph_process(graph, &src_buf, &dst_buf, tmp, 0, 0, 0, 0);
print_zimg_error("zimg_filter_graph_process");
zimg_filter_graph_free(graph);
print_zimg_error("zimg_filter_graph_free");
free(tmp);
FILE *dst_file = fopen(dst_name, "wb");
fwrite(dst_jpeg_buf, dst_pixel_count, 1, dst_file);
fclose(dst_file);
free(src_jpeg_buf);
free(dst_jpeg_buf);
return 0;
}
but I get this severity error from the terminal:
==136680==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7e3914dcd808 bp 0x7fff56f8efa0 sp 0x7fff56f8de00 T0)
==136680==The signal is caused by a WRITE memory access.
==136680==Hint: address points to the zero page.
#0 0x7e3914dcd808 in _mm_storeu_si128(long long __vector(2)*, long long __vector(2)) /usr/lib/gcc/x86_64-linux-gnu/11/include/emmintrin.h:739
#1 0x7e3914dcd808 in store16 src/zimg/depth/x86/dither_avx2.cpp:66
#2 0x7e3914dcd808 in ordered_dither_avx2_impl<zimg::depth::(anonymous namespace)::LoadU16, zimg::depth::(anonymous namespace)::StoreU8> src/zimg/depth/x86/dither_avx2.cpp:149
#3 0x7e3914dcd808 in zimg::depth::ordered_dither_w2b_avx2(float const*, unsigned int, unsigned int, void const*, void*, float, float, unsigned int, unsigned int, unsigned int) src/zimg/depth/x86/dither_avx2.cpp:178
#4 0x7e3914c7f666 in process src/zimg/depth/dither.cpp:281
#5 0x7e3914c4d544 in process graphengine/graphengine/node.cpp:635
#6 0x7e3914c3cdde (/usr/local/lib/libzimg.so.2+0x3cdde)
#7 0x7e3914c3e67d (/usr/local/lib/libzimg.so.2+0x3e67d)
#8 0x7e3914c39566 in graphengine::zimg::GraphImpl::run(graphengine::Graph::Endpoint const*, void*) const graphengine/graphengine/graph.cpp:877
#9 0x7e3914c8706d in zimg::graph::FilterGraph::process(std::array<graphengine::BufferDescriptor, 4ul> const&, std::array<graphengine::BufferDescriptor, 4ul> const&, void*, int (*)(void*, unsigned int, unsigned int, unsigned int), void*, int (*)(void*, unsigned int, unsigned int, unsigned int), void*) const src/zimg/graph/filtergraph.cpp:85
#10 0x7e3914c536d1 in zimg_filter_graph_process src/zimg/api/zimg.cpp:645
#11 0x5b5fabb4b8e6 in main /home/gianluca/Informatica/Programmazione/C/aws-lambda-cpp-samples/aws-lambda-jpeg-zimg/test.c:167
#12 0x7e3914429d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#13 0x7e3914429e3f in __libc_start_main_impl ../csu/libc-start.c:392
#14 0x5b5fabb4a544 in _start (/home/gianluca/Informatica/Programmazione/C/aws-lambda-cpp-samples/aws-lambda-jpeg-zimg/test+0x2544)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /usr/lib/gcc/x86_64-linux-gnu/11/include/emmintrin.h:739 in _mm_storeu_si128(long long __vector(2)*, long long __vector(2))
==136680==ABORTING
Code snippet was compiled with:
g++ -Wall -Werror -fsanitize=address -g -std=gnu++11 -o test test.cpp $(pkg-config --cflags --libs libjpeg zimg)
and run with ./test <filename>
Any suggestion ?
Gianluca
PS: I need to write this sentence because my post is mostly code...
Answer
i think incorrect use of zimg
library or incorrect memory handling leads to segmentation
fault
key changes :
- Adjust
src_stride
anddst_stride
: Ensure these are calculated correctly for RGB images. - Correct Buffer Initialization: Properly set
src_buf
anddst_buf
planes. - Error Checking and Printing: Added print statements to aid debugging.
revised code:
#include <cstdio> // fopen, fseek, ftell, fread, fwrite
#include <cstdint> // uint8_t
#include <cstdlib> // aligned_alloc, free
#include <cstring> // strlen, strtok, strcat
#include <cerrno> // errno
#include <jpeglib.h> // jpeg compression/decompression routines
#include <zimg.h> // colorspace and scaling routines
static void print_zimg_error(const char *function_name)
{
char err_msg[1024];
int err_code = zimg_get_last_error(err_msg, sizeof(err_msg));
if (err_code != ZIMG_ERROR_SUCCESS)
fprintf(stderr, "%s(): %s\n", function_name, err_msg);
zimg_clear_last_error();
}
static int width_to_stride(int w)
{
return ((w + 31) & ~31);
}
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "usage: %s <filename>.JPG\n", argv[0]);
return 1;
}
const char *src_name = argv[1];
char *src_name_2 = strdup(src_name);
const char *delim = "/";
char *tok;
char *dst_name;
strtok(src_name_2, delim);
while ((tok = strtok(NULL, delim)) != NULL)
dst_name = tok;
dst_name = strcat(strtok(dst_name, "."), "_resized.JPG");
// Define input sizes
int src_width = 5152;
int src_height = 3864;
int src_stride = width_to_stride(src_width) * 3; // Adjusted for RGB
int src_pixel_count = src_stride * src_height;
// Define output sizes
int dst_width = 2560;
int dst_height = 1400;
int dst_stride = width_to_stride(dst_width) * 3; // Adjusted for RGB
int dst_pixel_count = dst_stride * dst_height;
uint8_t *src_jpeg_buf = (uint8_t *) aligned_alloc(32, src_pixel_count);
if (src_jpeg_buf == NULL) {
fprintf(stderr, "aligned_alloc(): src_jpeg_buf is NULL\n");
return 1;
}
uint8_t *dst_jpeg_buf = (uint8_t *) aligned_alloc(32, dst_pixel_count);
if (dst_jpeg_buf == NULL) {
fprintf(stderr, "aligned_alloc(): dst_jpeg_buf is NULL\n");
return 1;
}
FILE *src_file = fopen(src_name, "rb");
if (src_file == NULL) {
perror("fopen()");
return 1;
}
struct jpeg_decompress_struct jpeg_dec;
struct jpeg_error_mgr jpeg_err;
jpeg_dec.err = jpeg_std_error(&jpeg_err);
jpeg_create_decompress(&jpeg_dec);
jpeg_stdio_src(&jpeg_dec, src_file);
jpeg_read_header(&jpeg_dec, TRUE);
jpeg_start_decompress(&jpeg_dec);
int row_stride = jpeg_dec.output_width * jpeg_dec.output_components;
JSAMPARRAY scanline_buffer = (*jpeg_dec.mem->alloc_sarray)((j_common_ptr) &jpeg_dec, JPOOL_IMAGE, row_stride, 1);
while (jpeg_dec.output_scanline < jpeg_dec.output_height) {
jpeg_read_scanlines(&jpeg_dec, scanline_buffer, 1);
memcpy(src_jpeg_buf + (jpeg_dec.output_scanline - 1) * row_stride, scanline_buffer[0], row_stride);
}
jpeg_finish_decompress(&jpeg_dec);
jpeg_destroy_decompress(&jpeg_dec);
fclose(src_file);
// Initialize zimg structures to defaults
zimg_filter_graph *graph = 0;
zimg_image_buffer_const src_buf = { ZIMG_API_VERSION };
zimg_image_buffer dst_buf = { ZIMG_API_VERSION };
zimg_image_format src_format;
zimg_image_format dst_format;
zimg_graph_builder_params params;
size_t tmp_size;
void *tmp = 0;
zimg_image_format_default(&src_format, ZIMG_API_VERSION);
print_zimg_error("zimg_image_format_default");
zimg_image_format_default(&dst_format, ZIMG_API_VERSION);
print_zimg_error("zimg_image_format_default");
zimg_graph_builder_params_default(¶ms, ZIMG_API_VERSION);
params.resample_filter = ZIMG_RESIZE_BICUBIC;
params.filter_param_a = -0.5;
params.filter_param_b = 0.25;
params.resample_filter_uv = ZIMG_RESIZE_BICUBIC;
params.filter_param_a_uv = -0.5;
params.filter_param_b_uv = 0.25;
src_format.width = src_width;
src_format.height = src_height;
src_format.pixel_type = ZIMG_PIXEL_BYTE;
src_format.subsample_w = 1;
src_format.subsample_h = 0;
src_format.color_family = ZIMG_COLOR_RGB; // Adjusted for RGB
dst_format.width = dst_width;
dst_format.height = dst_height;
dst_format.pixel_type = ZIMG_PIXEL_BYTE;
dst_format.subsample_w = 1;
dst_format.subsample_h = 1;
dst_format.color_family = ZIMG_COLOR_RGB; // Adjusted for RGB
graph = zimg_filter_graph_build(&src_format, &dst_format, ¶ms);
if (graph == NULL) {
fprintf(stderr, "zimg_filter_graph_build(): graph is NULL\n");
return 1;
}
print_zimg_error("zimg_filter_graph_build");
zimg_filter_graph_get_tmp_size(graph, &tmp_size);
print_zimg_error("zimg_filter_graph_get_tmp_size");
tmp = aligned_alloc(32, tmp_size);
if (tmp == NULL) {
fprintf(stderr, "aligned_alloc(): tmp is NULL\n");
return 1;
}
src_buf.plane[0].data = src_jpeg_buf;
src_buf.plane[0].stride = src_stride;
src_buf.plane[0].mask = ZIMG_BUFFER_MAX;
dst_buf.plane[0].data = dst_jpeg_buf;
dst_buf.plane[0].stride = dst_stride;
dst_buf.plane[0].mask = ZIMG_BUFFER_MAX;
zimg_filter_graph_process(graph, &src_buf, &dst_buf, tmp, 0, 0, 0, 0);
print_zimg_error("zimg_filter_graph_process");
zimg_filter_graph_free(graph);
print_zimg_error("zimg_filter_graph_free");
free(tmp);
FILE *dst_file = fopen(dst_name, "wb");
fwrite(dst_jpeg_buf, dst_pixel_count, 1, dst_file);
fclose(dst_file);
free(src_jpeg_buf);
free(dst_jpeg_buf);
return 0;
}
Compile and run with:
g++ -Wall -Werror -fsanitize=address -g -std=gnu++11 -o test test.cpp $(pkg-config --cflags --libs libjpeg zimg)
./test <filename>