libzimg: AddressSanitizer: SEGV

libzimg: AddressSanitizer: SEGV
typescript
Ethan Jackson

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(&params, 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, &params); 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 and dst_stride: Ensure these are calculated correctly for RGB images.
  • Correct Buffer Initialization: Properly set src_buf and dst_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(&params, 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, &params); 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>

Related Articles