#10144 closed defect (invalid)

Segfault only on macOS in sws_scale() for DCI 2K resolution

Reported by: LoadingByte Owned by:
Priority: normal Component: swscale
Version: 5.1.2 Keywords:
Cc: LoadingByte Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

Summary of the bug:

On macOS only, libswscale segfaults when converting certain pixel formats on frames with a width of 2048 pixels. This is unfortunate as the DCI 2K standard specifies exactly that width. The issue stems from libswscale reading 1 byte beyond the input frame's buffer. As such, the current best workaround is to enlarge that buffer by 1 byte. Notice that frames converted with the workaround on macOS and without the workaround on Windows or Linux exactly match.

How to reproduce:

Compile and run the following program on macOS. The h variable can be set to any value and the bug still persists. Other outPixFmts like YUV422P/YUV422P10LE/YUV444P10LE and other inPixFmts like BGR24 also provoke the issue. The workaround appends "+ 1" to the buffer length in the calloc() call.

#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>

AVFrame *alloc_frame(int w, int h, int pix_fmt) {
    AVFrame *frame = av_frame_alloc();
    frame->format = pix_fmt;
    frame->width = w;
    frame->height = h;
    return frame;
}

int main(void) {
    int w = 2048;
    int h = 858;
    int inPixFmt = AV_PIX_FMT_RGB24;
    int outPixFmt = AV_PIX_FMT_BGR24;

    AVFrame *inFrame = alloc_frame(w, h, inPixFmt);
    AVFrame *outFrame = alloc_frame(w, h, outPixFmt);
    struct SwsContext *swsCtx = sws_getContext(w, h, inPixFmt, w, h, outPixFmt, 0, NULL, NULL, NULL);

    av_frame_get_buffer(outFrame, 0);
    av_image_fill_arrays(inFrame->data, inFrame->linesize, calloc(w * h * 3, 1), inPixFmt, w, h, 1);

    sws_scale(swsCtx, inFrame->data, inFrame->linesize, 0, h, outFrame->data, outFrame->linesize);
}

Change History (4)

comment:1 by Balling, 15 months ago

Is this cause free() operation zeroes out all deallocated blocks in iOS 16.1 beta or later? They did it because "There’s also a performance improvement, because it makes the memory compressor work better", but of course their compressor is garbage then.

comment:2 by LoadingByte, 15 months ago

I have verified that the segfault occurs even on macOS 11, and as such, the allocator change in macOS 13 can't be the cause.

comment:3 by LoadingByte, 13 months ago

I just noticed the following piece of documentation on the data field in frame.h:

Some filters and swscale can read up to 16 bytes beyond the planes, if these filters are to be used, then 16 extra bytes must be allocated.

In accordance, the function get_video_buffer() in frame.c actually allocates these extra bytes (look for int plane_padding there).

As such, I presume that this "bug" is actually intended behavior (but maybe not sufficiently well documented)? Also, it's of course curious that it only occurs on macOS, but that could be related to different memory allocators between OSes.

Last edited 13 months ago by LoadingByte (previous) (diff)

comment:4 by LoadingByte, 10 months ago

Resolution: invalid
Status: newclosed

As this ticket is actually a user error as detailed in my previous comment, I'm closing it as invalid.

Note: See TracTickets for help on using tickets.