149 changed files with 3713 additions and 3393 deletions
@ -1,139 +0,0 @@
@@ -1,139 +0,0 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-โ
|
||||
โvi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :viโ |
||||
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโก |
||||
โ Copyright 2020 Justine Alexandra Roberts Tunney โ |
||||
โ โ |
||||
โ This program is free software; you can redistribute it and/or modify โ |
||||
โ it under the terms of the GNU General Public License as published by โ |
||||
โ the Free Software Foundation; version 2 of the License. โ |
||||
โ โ |
||||
โ This program is distributed in the hope that it will be useful, but โ |
||||
โ WITHOUT ANY WARRANTY; without even the implied warranty of โ |
||||
โ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU โ |
||||
โ General Public License for more details. โ |
||||
โ โ |
||||
โ You should have received a copy of the GNU General Public License โ |
||||
โ along with this program; if not, write to the Free Software โ |
||||
โ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA โ |
||||
โ 02110-1301 USA โ |
||||
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ*/ |
||||
#include "dsp/mpeg/mpeg.h" |
||||
#include "dsp/mpeg/ycbcrio.h" |
||||
#include "libc/bits/bits.h" |
||||
#include "libc/calls/calls.h" |
||||
#include "libc/calls/struct/stat.h" |
||||
#include "libc/log/check.h" |
||||
#include "libc/macros.h" |
||||
#include "libc/runtime/runtime.h" |
||||
#include "libc/str/str.h" |
||||
#include "libc/sysv/consts/map.h" |
||||
#include "libc/sysv/consts/o.h" |
||||
#include "libc/sysv/consts/prot.h" |
||||
|
||||
static void CheckPlmFrame(const struct plm_frame_t *frame) { |
||||
CHECK_NE(0, frame->width); |
||||
CHECK_NE(0, frame->height); |
||||
CHECK_GE(frame->y.width, frame->width); |
||||
CHECK_GE(frame->y.height, frame->height); |
||||
CHECK_EQ(frame->cr.width, frame->cb.width); |
||||
CHECK_EQ(frame->cr.height, frame->cb.height); |
||||
CHECK_EQ(frame->y.width, frame->cr.width * 2); |
||||
CHECK_EQ(frame->y.height, frame->cr.height * 2); |
||||
CHECK_NOTNULL(frame->y.data); |
||||
CHECK_NOTNULL(frame->cr.data); |
||||
CHECK_NOTNULL(frame->cb.data); |
||||
} |
||||
|
||||
static size_t GetHeaderBytes(const struct plm_frame_t *frame) { |
||||
return MAX(sizeof(struct Ycbcrio), ROUNDUP(frame->y.width, 16)); |
||||
} |
||||
|
||||
static size_t GetPlaneBytes(const struct plm_plane_t *plane) { |
||||
/*
|
||||
* planes must be 16-byte aligned, but due to their hugeness, and the |
||||
* recommendation of intel's 6,000 page manual, it makes sense to have |
||||
* planes on isolated 64kb frames for multiprocessing. |
||||
*/ |
||||
return ROUNDUP(ROUNDUP(plane->height, 16) * ROUNDUP(plane->width, 16), |
||||
FRAMESIZE); |
||||
} |
||||
|
||||
static size_t CalcMapBytes(const struct plm_frame_t *frame) { |
||||
return ROUNDUP(GetHeaderBytes(frame) + GetPlaneBytes(&frame->y) + |
||||
GetPlaneBytes(&frame->cb) + GetPlaneBytes(&frame->cb), |
||||
FRAMESIZE); |
||||
} |
||||
|
||||
static void FixupPointers(struct Ycbcrio *map) { |
||||
map->frame.y.data = (unsigned char *)map + GetHeaderBytes(&map->frame); |
||||
map->frame.cr.data = map->frame.y.data + GetPlaneBytes(&map->frame.y); |
||||
map->frame.cb.data = map->frame.cr.data + GetPlaneBytes(&map->frame.cr); |
||||
} |
||||
|
||||
static struct Ycbcrio *YcbcrioOpenNew(const char *path, |
||||
const struct plm_frame_t *frame) { |
||||
int fd; |
||||
size_t size; |
||||
struct stat st; |
||||
struct Ycbcrio *map; |
||||
CheckPlmFrame(frame); |
||||
size = CalcMapBytes(frame); |
||||
CHECK_NE(-1, (fd = open(path, O_CREAT | O_RDWR, 0644))); |
||||
CHECK_NE(-1, fstat(fd, &st)); |
||||
if (st.st_size < size) { |
||||
CHECK_NE(-1, ftruncate(fd, size)); |
||||
} |
||||
CHECK_NE(MAP_FAILED, |
||||
(map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0))); |
||||
map->magic = YCBCRIO_MAGIC; |
||||
map->fd = fd; |
||||
map->size = size; |
||||
memcpy(&map->frame, frame, sizeof(map->frame)); |
||||
FixupPointers(map); |
||||
memcpy(&map->frame.y.data, frame->y.data, GetPlaneBytes(&frame->y)); |
||||
memcpy(&map->frame.cb.data, frame->cb.data, GetPlaneBytes(&frame->cb)); |
||||
memcpy(&map->frame.cr.data, frame->cr.data, GetPlaneBytes(&frame->cr)); |
||||
return map; |
||||
} |
||||
|
||||
static struct Ycbcrio *YcbcrioOpenExisting(const char *path) { |
||||
int fd; |
||||
struct stat st; |
||||
struct Ycbcrio *map; |
||||
CHECK_NE(-1, (fd = open(path, O_RDWR))); |
||||
CHECK_NE(-1, fstat(fd, &st)); |
||||
CHECK_NE(MAP_FAILED, (map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, |
||||
MAP_SHARED, fd, 0))); |
||||
CHECK_EQ(YCBCRIO_MAGIC, map->magic); |
||||
CHECK_GE(st.st_size, CalcMapBytes(&map->frame)); |
||||
FixupPointers(map); |
||||
map->fd = fd; |
||||
map->size = st.st_size; |
||||
return map; |
||||
} |
||||
|
||||
/**
|
||||
* Opens shareable persistable MPEG video frame memory. |
||||
* |
||||
* @param path is a file name |
||||
* @param frame if NULL means open existing file, otherwise copies new |
||||
* @param points to pointer returned by YcbcrioOpen() which is cleared |
||||
* @return memory mapping needing YcbcrioClose() |
||||
*/ |
||||
struct Ycbcrio *YcbcrioOpen(const char *path, const struct plm_frame_t *frame) { |
||||
if (frame) { |
||||
return YcbcrioOpenNew(path, frame); |
||||
} else { |
||||
return YcbcrioOpenExisting(path); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Closes mapped video frame file. |
||||
* |
||||
* @param points to pointer returned by YcbcrioOpen() which is cleared |
||||
*/ |
||||
void YcbcrioClose(struct Ycbcrio **map) { |
||||
CHECK_NE(-1, close_s(&(*map)->fd)); |
||||
CHECK_NE(-1, munmap_s(map, (*map)->size)); |
||||
} |
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
#ifndef COSMOPOLITAN_DSP_MPEG_YCBCRIO_H_ |
||||
#define COSMOPOLITAN_DSP_MPEG_YCBCRIO_H_ |
||||
#include "dsp/mpeg/mpeg.h" |
||||
#include "libc/bits/bswap.h" |
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0) |
||||
COSMOPOLITAN_C_START_ |
||||
|
||||
#define YCBCRIO_MAGIC bswap_32(0xBCCBCCBCu) |
||||
|
||||
/**
|
||||
* Mappable persistable MPEG-2 video frame in Y-Cr-Cb colorspace. |
||||
*/ |
||||
struct Ycbcrio { |
||||
uint32_t magic; |
||||
int32_t fd; |
||||
uint64_t size; |
||||
plm_frame_t frame; |
||||
}; |
||||
|
||||
struct Ycbcrio *YcbcrioOpen(const char *, const struct plm_frame_t *) |
||||
paramsnonnull((1)) vallocesque returnsnonnull; |
||||
|
||||
void YcbcrioClose(struct Ycbcrio **) paramsnonnull(); |
||||
|
||||
COSMOPOLITAN_C_END_ |
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ |
||||
#endif /* COSMOPOLITAN_DSP_MPEG_YCBCRIO_H_ */ |
@ -1,28 +0,0 @@
@@ -1,28 +0,0 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CONV_SIZEMULTIPLY_H_ |
||||
#define COSMOPOLITAN_LIBC_CONV_SIZEMULTIPLY_H_ |
||||
#include "libc/limits.h" |
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0) |
||||
|
||||
/**
|
||||
* Multiplies memory sizes. |
||||
* |
||||
* @param count may be 0 to for realloc() โ free() behavior |
||||
* @param opt_out set to count*itemsize or SIZE_MAX on overflow |
||||
* @return true on success or false on overflow |
||||
*/ |
||||
forceinline bool sizemultiply(size_t *opt_out, size_t count, size_t itemsize) { |
||||
size_t res = 0; |
||||
bool overflowed = false; |
||||
if (count != 0) { |
||||
res = count * itemsize; |
||||
if (((count | itemsize) & ~0xfffful) && (res / count != itemsize)) { |
||||
overflowed = true; |
||||
res = SIZE_MAX; |
||||
} |
||||
} |
||||
if (opt_out) *opt_out = res; |
||||
return !overflowed; |
||||
} |
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ |
||||
#endif /* COSMOPOLITAN_LIBC_CONV_SIZEMULTIPLY_H_ */ |
@ -0,0 +1,370 @@
@@ -0,0 +1,370 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-โ
|
||||
โvi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :viโ |
||||
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโก |
||||
โ Copyright 2020 Justine Alexandra Roberts Tunney โ |
||||
โ โ |
||||
โ This program is free software; you can redistribute it and/or modify โ |
||||
โ it under the terms of the GNU General Public License as published by โ |
||||
โ the Free Software Foundation; version 2 of the License. โ |
||||
โ โ |
||||
โ This program is distributed in the hope that it will be useful, but โ |
||||
โ WITHOUT ANY WARRANTY; without even the implied warranty of โ |
||||
โ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU โ |
||||
โ General Public License for more details. โ |
||||
โ โ |
||||
โ You should have received a copy of the GNU General Public License โ |
||||
โ along with this program; if not, write to the Free Software โ |
||||
โ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA โ |
||||
โ 02110-1301 USA โ |
||||
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ*/ |
||||
#include "libc/assert.h" |
||||
#include "libc/bits/safemacros.h" |
||||
#include "libc/bits/weaken.h" |
||||
#include "libc/calls/calls.h" |
||||
#include "libc/conv/conv.h" |
||||
#include "libc/conv/itoa.h" |
||||
#include "libc/log/asan.h" |
||||
#include "libc/log/backtrace.h" |
||||
#include "libc/log/log.h" |
||||
#include "libc/macros.h" |
||||
#include "libc/mem/hook/hook.h" |
||||
#include "libc/runtime/directmap.h" |
||||
#include "libc/runtime/internal.h" |
||||
#include "libc/runtime/memtrack.h" |
||||
#include "libc/runtime/missioncritical.h" |
||||
#include "libc/runtime/runtime.h" |
||||
#include "libc/runtime/symbols.h" |
||||
#include "libc/stdio/stdio.h" |
||||
#include "libc/str/str.h" |
||||
#include "libc/sysv/consts/fileno.h" |
||||
#include "libc/sysv/consts/map.h" |
||||
#include "libc/sysv/consts/prot.h" |
||||
#include "third_party/dlmalloc/dlmalloc.h" |
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Address Sanitizer Runtime. |
||||
* |
||||
* Someone brilliant at Google figured out a way to improve upon memory |
||||
* protection. Rather than invent another Java or Rust they changed GCC |
||||
* so it can emit fast code, that checks the validity of each memory op |
||||
* with byte granularity, by probing shadow memory. |
||||
* |
||||
* AddressSanitizer dedicates one-eighth of the virtual address space |
||||
* to its shadow memory and uses a direct mapping with a scale and |
||||
* offset to translate an application address to its corresponding |
||||
* shadow address. Given the application memory address Addr, the |
||||
* address of the shadow byte is computed as (Addr>>3)+Offset." |
||||
* |
||||
* We use the following encoding for each shadow byte: 0 means that |
||||
* all 8 bytes of the corresponding application memory region are |
||||
* addressable; k (1 โค k โค 7) means that the first k bytes are |
||||
* addressible; any negative value indicates that the entire 8-byte |
||||
* word is unaddressable. We use different negative values to |
||||
* distinguish between different kinds of unaddressable memory (heap |
||||
* redzones, stack redzones, global redzones, freed memory). |
||||
* |
||||
* Here's what the generated code looks like for 64-bit reads: |
||||
* |
||||
* movq %addr,%tmp |
||||
* shrq $3,%tmp |
||||
* cmpb $0,0x7fff8000(%tmp) |
||||
* jnz abort |
||||
* movq (%addr),%dst |
||||
*/ |
||||
|
||||
#define HOOK(HOOK, IMPL) \ |
||||
if (weaken(HOOK)) { \ |
||||
*weaken(HOOK) = IMPL; \ |
||||
} |
||||
|
||||
struct AsanSourceLocation { |
||||
const char *filename; |
||||
int line; |
||||
int column; |
||||
}; |
||||
|
||||
struct AsanAccessInfo { |
||||
const char *addr; |
||||
const char *first_bad_addr; |
||||
size_t size; |
||||
bool iswrite; |
||||
unsigned long ip; |
||||
}; |
||||
|
||||
struct AsanGlobal { |
||||
const char *addr; |
||||
size_t size; |
||||
size_t size_with_redzone; |
||||
const void *name; |
||||
const void *module_name; |
||||
unsigned long has_cxx_init; |
||||
struct AsanSourceLocation *location; |
||||
char *odr_indicator; |
||||
}; |
||||
|
||||
static bool __asan_is_mapped(void *p) { |
||||
int x, i; |
||||
x = (intptr_t)p >> 16; |
||||
i = FindMemoryInterval(&_mmi, x); |
||||
return i < _mmi.i && x >= _mmi.p[i].x && x <= _mmi.p[i].y; |
||||
} |
||||
|
||||
void __asan_map_shadow(void *addr, size_t size) { |
||||
int i, n, x; |
||||
char *a, *b; |
||||
struct DirectMap sm; |
||||
a = (char *)ROUNDDOWN(SHADOW((intptr_t)addr), FRAMESIZE); |
||||
b = (char *)ROUNDDOWN(SHADOW((intptr_t)addr + size - 1), FRAMESIZE); |
||||
for (; a <= b; a += FRAMESIZE) { |
||||
if (!__asan_is_mapped(a)) { |
||||
sm = DirectMap(a, FRAMESIZE, PROT_READ | PROT_WRITE, |
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); |
||||
if (sm.addr == MAP_FAILED || |
||||
TrackMemoryInterval(&_mmi, (intptr_t)a >> 16, (intptr_t)a >> 16, |
||||
sm.maphandle) == -1) { |
||||
abort(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
size_t __asan_malloc_usable_size(const void *vp) { |
||||
char *s; |
||||
size_t n; |
||||
for (n = 0, s = (char *)SHADOW((intptr_t)vp);; ++s) { |
||||
if (!*s) { |
||||
n += 8; |
||||
} else if (*s > 0) { |
||||
n += *s & 7; |
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
void *__asan_allocate(size_t align, size_t size, int underrun, int overrun) { |
||||
char *p, *s; |
||||
size_t q, r, i; |
||||
if (!(p = dlmemalign(align, ROUNDUP(size, 8) + 16))) return NULL; |
||||
s = (char *)SHADOW((intptr_t)p - 16); |
||||
q = size / 8; |
||||
r = size % 8; |
||||
*s++ = underrun; |
||||
*s++ = underrun; |
||||
memset(s, 0, q); |
||||
s += q; |
||||
if (r) *s++ = r; |
||||
*s++ = overrun; |
||||
*s++ = overrun; |
||||
return p; |
||||
} |
||||
|
||||
void __asan_deallocate(char *p, int kind) { |
||||
char *s; |
||||
size_t n; |
||||
s = (char *)SHADOW((intptr_t)p); |
||||
n = dlmalloc_usable_size(p); |
||||
n /= 8; |
||||
memset(s, kind, n); |
||||
dlfree(p); |
||||
} |
||||
|
||||
void __asan_free(void *vp) { |
||||
__asan_deallocate(vp, kAsanHeapFree); |
||||
} |
||||
|
||||
void *__asan_memalign(size_t align, size_t size) { |
||||
return __asan_allocate(align, size, kAsanHeapUnderrun, kAsanHeapOverrun); |
||||
} |
||||
|
||||
void *__asan_malloc(size_t size) { |
||||
return __asan_memalign(16, size); |
||||
} |
||||
|
||||
void *__asan_calloc(size_t n, size_t m) { |
||||
char *p; |
||||
size_t size; |
||||
if (__builtin_mul_overflow(n, m, &size)) size = -1; |
||||
if ((p = __asan_malloc(size))) memset(p, 0, size); |
||||
return p; |
||||
} |
||||
|
||||
void *__asan_realloc(void *p, size_t n) { |
||||
char *p2; |
||||
if (p) { |
||||
if (n) { |
||||
if ((p2 = __asan_malloc(n))) { |
||||
memcpy(p2, p, min(n, dlmalloc_usable_size(p))); |
||||
__asan_deallocate(p, kAsanRelocated); |
||||
} |
||||
} else { |
||||
__asan_free(p); |
||||
p2 = NULL; |
||||
} |
||||
} else { |
||||
p2 = __asan_malloc(n); |
||||
} |
||||
return p2; |
||||
} |
||||
|
||||
void *__asan_valloc(size_t n) { |
||||
return __asan_memalign(PAGESIZE, n); |
||||
} |
||||
|
||||
void *__asan_pvalloc(size_t n) { |
||||
return __asan_valloc(ROUNDUP(n, PAGESIZE)); |
||||
} |
||||
|
||||
void __asan_poison(intptr_t addr, size_t size, size_t redsize, int kind) { |
||||
char *s; |
||||
intptr_t p; |
||||
size_t a, b, w; |
||||
w = (intptr_t)addr & 7; |
||||
p = (intptr_t)addr - w; |
||||
a = w + size; |
||||
b = w + redsize; |
||||
s = (char *)SHADOW(p + a); |
||||
if (a & 7) *s++ = a & 7; |
||||
memset(s, kind, (b - ROUNDUP(a, 8)) >> 3); |
||||
} |
||||
|
||||
void __asan_register_globals(struct AsanGlobal g[], int n) { |
||||
size_t i; |
||||
for (i = 0; i < n; ++i) { |
||||
__asan_poison((intptr_t)g[i].addr, g[i].size, g[i].size_with_redzone, |
||||
kAsanGlobalOverrun); |
||||
} |
||||
} |
||||
|
||||
void __asan_report_memory_fault(uint8_t *addr, int size, const char *kind) { |
||||
char *p, *s, ibuf[21], buf[256]; |
||||
switch (*(char *)SHADOW((intptr_t)addr)) { |
||||
case kAsanStackFree: |
||||
s = "stack use after release"; |
||||
break; |
||||
case kAsanHeapFree: |
||||
s = "heap use after free"; |
||||
break; |
||||
case kAsanRelocated: |
||||
s = "heap use after relocate"; |
||||