From owner-freebsd-multimedia@FreeBSD.ORG Sun Dec 12 20:40:16 2010 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A127C106566B; Sun, 12 Dec 2010 20:40:16 +0000 (UTC) (envelope-from avg@freebsd.org) Received: from citadel.icyb.net.ua (citadel.icyb.net.ua [212.40.38.140]) by mx1.freebsd.org (Postfix) with ESMTP id 9DAE68FC19; Sun, 12 Dec 2010 20:40:15 +0000 (UTC) Received: from porto.topspin.kiev.ua (porto-e.starpoint.kiev.ua [212.40.38.100]) by citadel.icyb.net.ua (8.8.8p3/ICyb-2.3exp) with ESMTP id WAA06933; Sun, 12 Dec 2010 22:40:14 +0200 (EET) (envelope-from avg@freebsd.org) Received: from localhost.topspin.kiev.ua ([127.0.0.1]) by porto.topspin.kiev.ua with esmtp (Exim 4.34 (FreeBSD)) id 1PRsiL-000C9g-IR; Sun, 12 Dec 2010 22:40:13 +0200 Message-ID: <4D05332C.7010208@freebsd.org> Date: Sun, 12 Dec 2010 22:40:12 +0200 From: Andriy Gapon User-Agent: Mozilla/5.0 (X11; U; FreeBSD amd64; en-US; rv:1.9.2.12) Gecko/20101029 Lightning/1.0b2 Thunderbird/3.1.6 MIME-Version: 1.0 To: =?x-viet-vps?Q?Martin_Matus=28ka?= , freebsd-multimedia@freebsd.org X-Enigmail-Version: 1.1.2 Content-Type: text/plain; charset=X-VIET-VPS Content-Transfer-Encoding: 7bit Cc: Subject: ffmpeg and mmap X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 12 Dec 2010 20:40:16 -0000 I've been getting some crash dumps in libswscale.so code. The stack trace is always like this: #0 0x000000083a6abf10 in ?? () #1 0x000000080a717dc6 in hyscale_fast_MMX2 #2 0x000000080a71bd64 in swScale_MMX2 #3 0x000000080a71ebf9 in sws_scale ... >From disassembling I've identified that the crash happens as soon as inline assembly in hyscale_fast_MMX2 calls code pointed to by lumMmx2FilterCode pointer. The following code in libswscale/utils.c, function sws_getContext() is of interest: #if ARCH_X86 && (HAVE_MMX2 || CONFIG_RUNTIME_CPUDETECT) // can't downscale !!! if (c->canMMX2BeUsed && (flags & SWS_FAST_BILINEAR)) { c->lumMmx2FilterCodeSize = initMMX2HScaler( dstW, c->lumXInc, NULL, NULL, NULL, 8); c->chrMmx2FilterCodeSize = initMMX2HScaler(c->chrDstW, c->chrXInc, NULL, NULL, NULL, 4); #ifdef MAP_ANONYMOUS c->lumMmx2FilterCode = mmap(NULL, c->lumMmx2FilterCodeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); c->chrMmx2FilterCode = mmap(NULL, c->chrMmx2FilterCodeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #elif HAVE_VIRTUALALLOC c->lumMmx2FilterCode = VirtualAlloc(NULL, c->lumMmx2FilterCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); c->chrMmx2FilterCode = VirtualAlloc(NULL, c->chrMmx2FilterCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); #else c->lumMmx2FilterCode = av_malloc(c->lumMmx2FilterCodeSize); c->chrMmx2FilterCode = av_malloc(c->chrMmx2FilterCodeSize); #endif if (!c->lumMmx2FilterCode || !c->chrMmx2FilterCode) goto fail; FF_ALLOCZ_OR_GOTO(c, c->hLumFilter , (dstW /8+8)*sizeof(int16_t), fail); FF_ALLOCZ_OR_GOTO(c, c->hChrFilter , (c->chrDstW /4+8)*sizeof(int16_t), fail); FF_ALLOCZ_OR_GOTO(c, c->hLumFilterPos, (dstW /2/8+8)*sizeof(int32_t), fail); FF_ALLOCZ_OR_GOTO(c, c->hChrFilterPos, (c->chrDstW/2/4+8)*sizeof(int32_t), fail); initMMX2HScaler( dstW, c->lumXInc, c->lumMmx2FilterCode, c->hLumFilter, c->hLumFilterPos, 8); initMMX2HScaler(c->chrDstW, c->chrXInc, c->chrMmx2FilterCode, c->hChrFilter, c->hChrFilterPos, 4); #ifdef MAP_ANONYMOUS mprotect(c->lumMmx2FilterCode, c->lumMmx2FilterCodeSize, PROT_EXEC | PROT_READ); mprotect(c->chrMmx2FilterCode, c->chrMmx2FilterCodeSize, PROT_EXEC | PROT_READ); #endif } else #endif /* ARCH_X86 && (HAVE_MMX2 || CONFIG_RUNTIME_CPUDETECT) */ I've noticed that in our port lumMmx2FilterCode and chrMmx2FilterCode buffers are allocated using av_malloc() (which is a wrapper around libc malloc) and that's the source of the problem - on amd64 heap memory is not executable. So the attempt to execute code in the heap buffer results in a page fault and in the crash (SIGBUS). The buffer should be actually allocated via mmap() and then get proper permissions via mprotect(). That doesn't happen because MAP_ANONYMOUS is not defined in that context. MAP_ANONYMOUS/MAP_ANON is not defined, because it is not specified in POSIX and it is under _BSD_VISIBLE in sys/mman.h, but the code at hand is compiled with _POSIX_SOURCE defined. On FreeBSD _POSIX_SOURCE implies !_BSD_VISIBLE. To get around that issue _on Linux_, ffmpeg folks have put explicit _SVID_SOURCE definition right into the libswscale/utils.c file: #define _SVID_SOURCE //needed for MAP_ANONYMOUS For much the same reason we need to add the following for FreeBSD (as hackish as it is): #define __BSD_VISIBLE 1 With that addition the code buffer is allocated properly and the code in it can be executed. P.S. this page talks about a similar issue: http://ubuntuforums.org/showthread.php?t=1547726 -- Andriy Gapon