libzimg: AddressSanitizer: SEGV

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(&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>
© 2024 Dagalaxy. All rights reserved.