Make redbean StoreAsset() work better
- Better UBSAN error messages - POSIX Advisory Locks polyfills - Move redbean manual to /.help.txt - System call memory safety in ASAN mode - Character classification now does UNICODE
This commit is contained in:
168
libc/log/ubsan.c
168
libc/log/ubsan.c
@@ -16,6 +16,7 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/reverse.internal.h"
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
@@ -43,6 +44,89 @@ upcast of\0\
|
||||
cast to virtual base of\0\
|
||||
\0";
|
||||
|
||||
static int __ubsan_bits(struct UbsanTypeDescriptor *t) {
|
||||
return 1 << (t->info >> 1);
|
||||
}
|
||||
|
||||
static bool __ubsan_signed(struct UbsanTypeDescriptor *t) {
|
||||
return t->info & 1;
|
||||
}
|
||||
|
||||
static bool __ubsan_negative(struct UbsanTypeDescriptor *t, uintptr_t x) {
|
||||
return __ubsan_signed(t) && (intptr_t)x < 0;
|
||||
}
|
||||
|
||||
static size_t __ubsan_strlen(const char *s) {
|
||||
size_t n = 0;
|
||||
while (*s++) ++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static char *__ubsan_stpcpy(char *d, const char *s) {
|
||||
size_t i;
|
||||
for (i = 0;; ++i) {
|
||||
if (!(d[i] = s[i])) {
|
||||
return d + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *__ubsan_poscpy(char *p, uintptr_t i) {
|
||||
int j = 0;
|
||||
do {
|
||||
p[j++] = i % 10 + '0';
|
||||
i /= 10;
|
||||
} while (i > 0);
|
||||
reverse(p, j);
|
||||
return p + j;
|
||||
}
|
||||
|
||||
static char *__ubsan_intcpy(char *p, intptr_t i) {
|
||||
if (i >= 0) return __ubsan_poscpy(p, i);
|
||||
*p++ = '-';
|
||||
return __ubsan_poscpy(p, -i);
|
||||
}
|
||||
|
||||
static char *__ubsan_hexcpy(char *p, uintptr_t x, int k) {
|
||||
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *__ubsan_itpcpy(char *p, struct UbsanTypeDescriptor *t,
|
||||
uintptr_t x) {
|
||||
if (__ubsan_signed(t)) {
|
||||
return __ubsan_intcpy(p, x);
|
||||
} else {
|
||||
return __ubsan_poscpy(p, x);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *__ubsan_dubnul(const char *s, unsigned i) {
|
||||
size_t n;
|
||||
while (i--) {
|
||||
if ((n = __ubsan_strlen(s))) {
|
||||
s += n + 1;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static uintptr_t __ubsan_extend(struct UbsanTypeDescriptor *t, uintptr_t x) {
|
||||
int w;
|
||||
w = __ubsan_bits(t);
|
||||
if (w < sizeof(x) * CHAR_BIT) {
|
||||
x <<= sizeof(x) * CHAR_BIT - w;
|
||||
if (__ubsan_signed(t)) {
|
||||
x = (intptr_t)x >> w;
|
||||
} else {
|
||||
x >>= w;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void __ubsan_abort(const struct UbsanSourceLocation *loc,
|
||||
const char *description) {
|
||||
static bool once;
|
||||
@@ -53,43 +137,73 @@ void __ubsan_abort(const struct UbsanSourceLocation *loc,
|
||||
}
|
||||
if (IsDebuggerPresent(false)) DebugBreak();
|
||||
__start_fatal(loc->file, loc->line);
|
||||
fprintf(stderr, "%s\r\n", description);
|
||||
write(2, description, strlen(description));
|
||||
write(2, "\r\n", 2);
|
||||
__die();
|
||||
unreachable;
|
||||
}
|
||||
|
||||
void __ubsan_handle_shift_out_of_bounds(struct UbsanShiftOutOfBoundsInfo *info,
|
||||
uintptr_t lhs, uintptr_t rhs) {
|
||||
char *p;
|
||||
const char *s;
|
||||
lhs = __ubsan_extend(info->lhs_type, lhs);
|
||||
rhs = __ubsan_extend(info->rhs_type, rhs);
|
||||
if (__ubsan_negative(info->rhs_type, rhs)) {
|
||||
s = "shift exponent is negative";
|
||||
} else if (rhs >= __ubsan_bits(info->lhs_type)) {
|
||||
s = "shift exponent too large for type";
|
||||
} else if (__ubsan_negative(info->lhs_type, lhs)) {
|
||||
s = "left shift of negative value";
|
||||
} else if (__ubsan_signed(info->lhs_type)) {
|
||||
s = "signed left shift changed sign bit or overflowed";
|
||||
} else {
|
||||
s = "wut shift out of bounds";
|
||||
}
|
||||
p = __ubsan_buf;
|
||||
p = __ubsan_stpcpy(p, s), *p++ = ' ';
|
||||
p = __ubsan_itpcpy(p, info->lhs_type, lhs), *p++ = ' ';
|
||||
p = __ubsan_stpcpy(p, info->lhs_type->name), *p++ = ' ';
|
||||
p = __ubsan_itpcpy(p, info->rhs_type, rhs), *p++ = ' ';
|
||||
p = __ubsan_stpcpy(p, info->rhs_type->name);
|
||||
__ubsan_abort(&info->location, __ubsan_buf);
|
||||
}
|
||||
|
||||
void __ubsan_handle_out_of_bounds(struct UbsanOutOfBoundsInfo *info,
|
||||
uintptr_t index) {
|
||||
snprintf(__ubsan_buf, sizeof(__ubsan_buf),
|
||||
"%s index %,lu into %s out of bounds", info->index_type->name, index,
|
||||
info->array_type->name);
|
||||
char *p;
|
||||
p = __ubsan_buf;
|
||||
p = __ubsan_stpcpy(p, info->index_type->name);
|
||||
p = __ubsan_stpcpy(p, " index ");
|
||||
p = __ubsan_itpcpy(p, info->index_type, index);
|
||||
p = __ubsan_stpcpy(p, " into ");
|
||||
p = __ubsan_stpcpy(p, info->array_type->name);
|
||||
p = __ubsan_stpcpy(p, " out of bounds");
|
||||
__ubsan_abort(&info->location, __ubsan_buf);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *type_mismatch,
|
||||
void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *info,
|
||||
uintptr_t pointer) {
|
||||
struct UbsanSourceLocation *loc = &type_mismatch->location;
|
||||
const char *description;
|
||||
const char *kind = IndexDoubleNulString(kUbsanTypeCheckKinds,
|
||||
type_mismatch->type_check_kind);
|
||||
if (pointer == 0) {
|
||||
description = "null pointer access";
|
||||
} else if (type_mismatch->alignment != 0 &&
|
||||
(pointer & (type_mismatch->alignment - 1))) {
|
||||
description = __ubsan_buf;
|
||||
snprintf(__ubsan_buf, sizeof(__ubsan_buf), "%s %s %s @%p %s %d",
|
||||
"unaligned", kind, type_mismatch->type->name, pointer, "align",
|
||||
type_mismatch->alignment);
|
||||
char *p;
|
||||
const char *kind;
|
||||
if (!pointer) __ubsan_abort(&info->location, "null pointer access");
|
||||
p = __ubsan_buf;
|
||||
kind = __ubsan_dubnul(kUbsanTypeCheckKinds, info->type_check_kind);
|
||||
if (info->alignment && (pointer & (info->alignment - 1))) {
|
||||
p = __ubsan_stpcpy(p, "unaligned ");
|
||||
p = __ubsan_stpcpy(p, kind), *p++ = ' ';
|
||||
p = __ubsan_stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@';
|
||||
p = __ubsan_itpcpy(p, info->type, pointer);
|
||||
p = __ubsan_stpcpy(p, " align ");
|
||||
p = __ubsan_intcpy(p, info->alignment);
|
||||
} else {
|
||||
description = __ubsan_buf;
|
||||
snprintf(__ubsan_buf, sizeof(__ubsan_buf), "%s\r\n\t%s %s %p %s %s",
|
||||
"insufficient size", kind, "address", pointer,
|
||||
"with insufficient space for object of type",
|
||||
type_mismatch->type->name);
|
||||
p = __ubsan_stpcpy(p, "insufficient size\r\n\t");
|
||||
p = __ubsan_stpcpy(p, kind);
|
||||
p = __ubsan_stpcpy(p, " address 0x");
|
||||
p = __ubsan_hexcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
|
||||
p = __ubsan_stpcpy(p, " with insufficient space for object of type ");
|
||||
p = __ubsan_stpcpy(p, info->type->name);
|
||||
}
|
||||
__ubsan_abort(loc, description);
|
||||
unreachable;
|
||||
__ubsan_abort(&info->location, __ubsan_buf);
|
||||
}
|
||||
|
||||
void ___ubsan_handle_type_mismatch_v1(
|
||||
@@ -100,7 +214,6 @@ void ___ubsan_handle_type_mismatch_v1(
|
||||
mm.alignment = 1u << type_mismatch->log_alignment;
|
||||
mm.type_check_kind = type_mismatch->type_check_kind;
|
||||
__ubsan_handle_type_mismatch(&mm, pointer);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
void __ubsan_handle_float_cast_overflow(void *data_raw, void *from_raw) {
|
||||
@@ -116,5 +229,4 @@ void __ubsan_handle_float_cast_overflow(void *data_raw, void *from_raw) {
|
||||
};
|
||||
__ubsan_abort(((void)data, &kUnknownLocation), "float cast overflow");
|
||||
#endif
|
||||
unreachable;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user