mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 13:52:28 +00:00
Make improvements
- Fix build flakes - Polyfill SIGWINCH on Windows - Fix an execve issue on Windows - Make strerror show more information - Improve cmd.exe setup/teardown on Windows - Support bracketed paste mode in Blinkenlights - Show keyboard shortcuts in Blinkenlights status bar - Fixed copy_file_range() and copyfile() w/ zip filesystem - Size optimize GetDosArgv() to keep life.com 12kb in size - Improve Blinkenlights ability to load weird ELF executables - Fix program_executable_name and add GetInterpreterExecutableName - Make Python in tiny mode fail better if docstrings are requested - Update Python test exclusions in tiny* modes such as tinylinux - Add bulletproof unbreakable kprintf() troubleshooting function - Remove "oldskool" keyword from ape.S for virus scanners - Fix issue that caused backtraces to not print sometimes - Improve Blinkenlights serial uart character i/o - Make clock_gettime() not clobber errno on xnu - Improve sha256 cpuid check for old computers - Integrate some bestline linenoise fixes - Show runit process names better in htop - Remove SIGPIPE from ShowCrashReports() - Make realpath() not clobber errno - Avoid attaching GDB on non-Linux - Improve img.com example
This commit is contained in:
parent
2a938b3eaa
commit
b45d50b690
194 changed files with 4881 additions and 2966 deletions
372
test/libc/intrin/kprintf_test.c
Normal file
372
test/libc/intrin/kprintf_test.c
Normal file
|
@ -0,0 +1,372 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
#define S(x) ((uintptr_t)(x))
|
||||
|
||||
/**
|
||||
* returns random bytes that don't have exclamation mark
|
||||
* since that would disable memory safety in the fuzzing
|
||||
*/
|
||||
static uint64_t Rando(void) {
|
||||
uint64_t x;
|
||||
do x = vigna();
|
||||
while (((x ^ READ64LE("!!!!!!!!")) - 0x0101010101010101) &
|
||||
~(x ^ READ64LE("!!!!!!!!")) & 0x8080808080808080);
|
||||
return x;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *want;
|
||||
const char *fmt;
|
||||
uintptr_t arg1;
|
||||
uintptr_t arg2;
|
||||
} V[] = {
|
||||
{"!!WONTFMT", (const char *)31337, 123}, //
|
||||
{"!!31337", "%s", 0x31337}, //
|
||||
{"!!1", "%#s", 1}, //
|
||||
{"!!feff800000031337", "%s", 0xfeff800000031337ull}, //
|
||||
{"!!ffff800000031337", "%s", 0xffff800000031337ull}, //
|
||||
{"123", "%d", 123}, //
|
||||
{"2147483647", "%d", INT_MAX}, //
|
||||
{"-2147483648", "%d", INT_MIN}, //
|
||||
{"9223372036854775807", "%ld", LONG_MAX}, //
|
||||
{"-9223372036854775808", "%ld", LONG_MIN}, //
|
||||
{"9'223'372'036'854'775'807", "%'ld", LONG_MAX}, //
|
||||
{"-9'223'372'036'854'775'808", "%'ld", LONG_MIN}, //
|
||||
{"9,223,372,036,854,775,807", "%,ld", LONG_MAX}, //
|
||||
{"-9,223,372,036,854,775,808", "%,ld", LONG_MIN}, //
|
||||
{"9_223_372_036_854_775_807", "%_ld", LONG_MAX}, //
|
||||
{"-9_223_372_036_854_775_808", "%_ld", LONG_MIN}, //
|
||||
{"true", "%hhhd", 0xffff}, //
|
||||
{"true", "%hhhd", 0xff00}, //
|
||||
{"false", "%hhhd"}, //
|
||||
{"fa", "%hhh.2d"}, //
|
||||
{" 0x001337", "%#010.6x", 0x1337}, //
|
||||
{"0x001337 ", "%#-010.6x", 0x1337}, //
|
||||
{"0x1337 ", "%#-010.2x", 0x1337}, //
|
||||
{" 0x1337", "%#010.2x", 0x1337}, //
|
||||
{"0000001337", "%010d", 1337}, //
|
||||
{"+000001337", "%+010d", 1337}, //
|
||||
{" 001337", "%010.6d", 1337}, //
|
||||
{" +001337", "%+010.6d", 1337}, //
|
||||
{" 001337", "%010.6x", 0x1337}, //
|
||||
{" 1337", "%010.2x", 0x1337}, //
|
||||
{"1337 ", "%-010d", 1337}, //
|
||||
{"001337 ", "%-010.6d", 1337}, //
|
||||
{"+1337 ", "%+-010d", 1337}, //
|
||||
{"+001337 ", "%+-010.6d", 1337}, //
|
||||
{"001337 ", "%-010.6x", 0x1337}, //
|
||||
{"1337 ", "%-010.2x", 0x1337}, //
|
||||
{"000001'337", "%'010d", 1337}, //
|
||||
{" 1337", "%*d", 10, 1337}, //
|
||||
{"1337 ", "%*d", -10, 1337}, //
|
||||
{"0", "%#x"}, //
|
||||
{"0", "%#o"}, //
|
||||
{"0", "%#b"}, //
|
||||
{"0", "%#d"}, //
|
||||
{"0", "%p"}, //
|
||||
{"-1", "%p", S(MAP_FAILED)}, //
|
||||
{"00000000", "%#.8x"}, //
|
||||
{"00000000", "%#.8b"}, //
|
||||
{"00000000", "%#.8o"}, //
|
||||
{" 123", "%5d", 123}, //
|
||||
{" -123", "%5d", -123}, //
|
||||
{" 123", "%*d", 5, 123}, //
|
||||
{" -123", "%*d", 5, -123}, //
|
||||
{"123 ", "%-5d", 123}, //
|
||||
{"-123 ", "%-5d", -123}, //
|
||||
{" +123", "%+5d", 123}, //
|
||||
{"00123", "%05d", 123}, //
|
||||
{"-0123", "%05d", -123}, //
|
||||
{" 0", "%5d"}, //
|
||||
{" +0", "%+5d"}, //
|
||||
{"00000", "%05d"}, //
|
||||
{" deadbeef", "%20x", 0xdeadbeef}, //
|
||||
{" 0xdeadbeef", "%20p", 0xdeadbeef}, //
|
||||
{"101", "%b", 0b101}, //
|
||||
{"123", "%x", 0x123}, //
|
||||
{"deadbeef", "%x", 0xdeadbeef}, //
|
||||
{"DEADBEEF", "%X", 0xdeadbeef}, //
|
||||
{"0", "%hd", INT_MIN}, //
|
||||
{"123", "%o", 0123}, //
|
||||
{"+0", "%+d"}, //
|
||||
{"+123", "%+d", 123}, //
|
||||
{"-123", "%+d", -123}, //
|
||||
{" 0", "% d"}, //
|
||||
{" 123", "% d", 123}, //
|
||||
{"-123", "% d", -123}, //
|
||||
{"x", "%c", 'x'}, //
|
||||
{"☺", "%hc", u'☺'}, //
|
||||
{"☺", "%lc", L'☺'}, //
|
||||
{"☺", "%C", L'☺'}, //
|
||||
{"0x31337", "%p", 0x31337}, //
|
||||
{"0xffff800000031337", "%p", 0xffff800000031337ull}, //
|
||||
{"0xfeff800000031337", "%p", 0xfeff800000031337ull}, //
|
||||
{"65535", "%hu", 0xffffffffu}, //
|
||||
{"0", "%hu", 0x80000000u}, //
|
||||
{"123", "%hd", 123}, //
|
||||
{"32767", "%hd", SHRT_MAX}, //
|
||||
{"-32768", "%hd", SHRT_MIN}, //
|
||||
{"-1", "%hhd", 0xffff}, //
|
||||
{"-128", "%hhd", 0xff80}, //
|
||||
{"255", "%hhu", 0xffffffffu}, //
|
||||
{"'x'", "%#c", 'x'}, //
|
||||
{"u'☺'", "%#hc", u'☺'}, //
|
||||
{"L'☺'", "%#lc", L'☺'}, //
|
||||
{"L'☺'", "%#C", L'☺'}, //
|
||||
{"L'\\''", "%#C", L'\''}, //
|
||||
{"hello world\n", "%s", S("hello world\n")}, //
|
||||
{"☺☻♥♦♣♠!\n", "%s", S("☺☻♥♦♣♠!\n")}, //
|
||||
{"␁", "%s", S("\1")}, //
|
||||
{"\1", "%.*s", 1, S("\1")}, //
|
||||
{"\\001", "%'s", S("\1")}, //
|
||||
{"\"\\001\"", "%#s", S("\1")}, //
|
||||
{"", "%.*s", 0}, //
|
||||
{"☺☻♥♦♣♠!", "%hhs", S("\1\2\3\4\5\6!")}, //
|
||||
{"", "% s", S("")}, //
|
||||
{" a", "% s", S("a")}, //
|
||||
{"", "% .*s", 0, S("a")}, //
|
||||
{"", "% s"}, //
|
||||
{"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷", "%hs", S(u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷")}, //
|
||||
{"☺☻♥♦♣♠!", "%ls", S(L"☺☻♥♦♣♠!")}, //
|
||||
{"☺☻♥♦♣♠!\n", "%S", S(L"☺☻♥♦♣♠!\n")}, //
|
||||
{"eeeeeee ", "%10s", S("eeeeeee")}, //
|
||||
{"hello", "%.*s", 5, S("hello world")}, //
|
||||
{"þell", "%.*s", 5, S("þello world")}, //
|
||||
{"þello", "%.*hs", 5, S(u"þello world")}, //
|
||||
{"þeeeeee ", "%10s", S("þeeeeee")}, //
|
||||
{"☺☻♥♦♣♠! ", "%10s", S("☺☻♥♦♣♠!")}, //
|
||||
{"☺☻♥♦♣♠ ", "%10hs", S(u"☺☻♥♦♣♠")}, //
|
||||
{"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷 ", "%10hs", S(u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷")}, //
|
||||
{"☺☻♥♦♣♠! ", "%10ls", S(L"☺☻♥♦♣♠!")}, //
|
||||
{"\"xx\"", "%#s", S("xx")}, //
|
||||
{"u\"☺☺\"", "%#hs", S(u"☺☺")}, //
|
||||
{"L\"☺☺\"", "%#ls", S(L"☺☺")}, //
|
||||
{"L\"☺☺\"", "%#S", S(L"☺☺")}, //
|
||||
{"\"\\\\\\\"\\177\"", "%#s", S("\\\"\177")}, //
|
||||
{"%%", "%%%%"}, //
|
||||
{"%", "%.%"}, //
|
||||
{"=", "%="}, //
|
||||
};
|
||||
|
||||
TEST(ksnprintf, test) {
|
||||
char b[48], g[48];
|
||||
size_t i, j, n, rc;
|
||||
rngset(g, sizeof(g), 0, 0);
|
||||
for (i = 0; i < ARRAYLEN(V); ++i) {
|
||||
bzero(b, 48);
|
||||
n = strlen(V[i].want);
|
||||
rc = ksnprintf(b, 48, V[i].fmt, V[i].arg1, V[i].arg2);
|
||||
EXPECT_EQ(n, rc, "ksnprintf(\"%s\", %#lx, %#lx) → %zu ≠ %zu", V[i].fmt,
|
||||
V[i].arg1, V[i].arg2, rc, n);
|
||||
EXPECT_STREQ(V[i].want, b);
|
||||
memcpy(b, g, 48);
|
||||
for (j = 0; j < 40; ++j) {
|
||||
rc = ksnprintf(b, 0, V[i].fmt, V[i].arg1, V[i].arg2);
|
||||
ASSERT_EQ(n, rc, "ksnprintf(b, %zu, \"%s\", %#lx, %#lx) → %zu ≠ %zu", j,
|
||||
V[i].fmt, V[i].arg1, V[i].arg2, rc, n);
|
||||
ASSERT_EQ(READ64LE(g + j), READ64LE(b + j),
|
||||
"ksnprintf(b, %zu, \"%s\", %#lx, %#lx) → buffer overrun", j,
|
||||
V[i].fmt, V[i].arg1, V[i].arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ksnprintf, fuzzTheUnbreakable) {
|
||||
int e;
|
||||
size_t i;
|
||||
uint64_t x;
|
||||
char *f, b[32];
|
||||
_Alignas(PAGESIZE) static const char weasel[PAGESIZE];
|
||||
asm("mov\t%1,%0" : "=r"(f) : "g"(weasel));
|
||||
EXPECT_SYS(0, 0, mprotect(f, PAGESIZE, PROT_READ | PROT_WRITE));
|
||||
strcpy(f, "hello %s\n");
|
||||
EXPECT_EQ(12, ksnprintf(b, sizeof(b), f, "world"));
|
||||
EXPECT_STREQ("hello world\n", b);
|
||||
for (i = 0; i < 30000; ++i) {
|
||||
x = Rando();
|
||||
memcpy(f, &x, sizeof(x));
|
||||
x = Rando();
|
||||
memcpy(f + 8, &x, sizeof(x));
|
||||
f[Rando() & 15] = '%';
|
||||
ksnprintf(b, sizeof(b), f, vigna(), vigna(), vigna());
|
||||
}
|
||||
EXPECT_SYS(0, 0, mprotect(f, PAGESIZE, PROT_READ));
|
||||
}
|
||||
|
||||
TEST(kprintf, testFailure_wontClobberErrnoAndBypassesSystemCallSupport) {
|
||||
int n;
|
||||
#if 0
|
||||
ASSERT_EQ(0, errno); /* xxx: todo(jart) */
|
||||
#else
|
||||
errno = 0;
|
||||
#endif
|
||||
EXPECT_SYS(0, 3, dup(2));
|
||||
EXPECT_SYS(0, 0, close(2));
|
||||
n = g_syscount;
|
||||
kprintf("hello%n");
|
||||
EXPECT_EQ(n, g_syscount);
|
||||
EXPECT_EQ(0, errno);
|
||||
EXPECT_SYS(0, 2, dup2(3, 2));
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testy) {
|
||||
char b[32];
|
||||
EXPECT_EQ(3, ksnprintf(b, 32, "%#s", 1));
|
||||
EXPECT_STREQ("!!1", b);
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testNonTextFmt_wontFormat) {
|
||||
char b[32];
|
||||
char variable_format_string[16] = "%s";
|
||||
EXPECT_EQ(9, ksnprintf(b, 32, variable_format_string, NULL));
|
||||
EXPECT_STREQ("!!WONTFMT", b);
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testMisalignedPointer_wontFormat) {
|
||||
char b[32];
|
||||
const char16_t *s = u"hello";
|
||||
ksnprintf(b, 32, "%hs", (char *)s + 1);
|
||||
EXPECT_STARTSWITH("!!", b);
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testUnterminatedOverrun_truncatesAtPageBoundary) {
|
||||
char *m;
|
||||
char b[32];
|
||||
m = memset(mapanon(FRAMESIZE * 2), 1, FRAMESIZE);
|
||||
EXPECT_SYS(0, 0, munmap(m + FRAMESIZE, FRAMESIZE));
|
||||
EXPECT_EQ(12, ksnprintf(b, 32, "%'s", m + FRAMESIZE - 3));
|
||||
EXPECT_STREQ("\\001\\001\\001", b);
|
||||
EXPECT_SYS(0, 0, munmap(m, FRAMESIZE));
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testEmptyBuffer_determinesTrueLength) {
|
||||
EXPECT_EQ(5, ksnprintf(0, 0, "hello"));
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testFormatOnly_copiesString) {
|
||||
char b[6];
|
||||
EXPECT_EQ(5, ksnprintf(b, 6, "hello"));
|
||||
EXPECT_STREQ("hello", b);
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testOneChar_justNulTerminates) {
|
||||
char b[2] = {1, 2};
|
||||
EXPECT_EQ(3, ksnprintf(b, 1, "%d", 123));
|
||||
EXPECT_EQ(0, b[0]);
|
||||
EXPECT_EQ(2, b[1]);
|
||||
}
|
||||
|
||||
TEST(kprintf, testStringUcs2) {
|
||||
char b[32];
|
||||
EXPECT_EQ(21, ksnprintf(b, 32, "%hs", u"þ☺☻♥♦♣♠!"));
|
||||
EXPECT_EQ(0xc3, b[0] & 255);
|
||||
EXPECT_EQ(0xbe, b[1] & 255);
|
||||
EXPECT_EQ(0xe2, b[2] & 255);
|
||||
EXPECT_EQ(0x98, b[3] & 255);
|
||||
EXPECT_EQ(0xba, b[4] & 255);
|
||||
EXPECT_STREQ("þ☺☻♥♦♣♠!", b);
|
||||
}
|
||||
|
||||
TEST(kprintf, testTruncate_addsDotsAndReturnsTrueLength) {
|
||||
char b[15];
|
||||
EXPECT_EQ(10, ksnprintf(b, 15, "%p", 0xdeadbeef));
|
||||
EXPECT_STREQ("0xdeadbeef", b);
|
||||
EXPECT_EQ(10, ksnprintf(b, 10, "%p", 0xdeadbeef));
|
||||
EXPECT_STREQ("0xdead...", b);
|
||||
}
|
||||
|
||||
TEST(kprintf, testTruncate_preservesNewlineFromEndOfFormatString) {
|
||||
char b[14];
|
||||
EXPECT_EQ(11, ksnprintf(b, 10, "%p\n", 0xdeadbeef));
|
||||
EXPECT_STREQ("0xdea...\n", b);
|
||||
}
|
||||
|
||||
TEST(ksnprintf, testTruncate_doesntBreakApartCharacters) {
|
||||
char b[5];
|
||||
ASSERT_EQ(6, ksnprintf(b, 5, "☻☻"));
|
||||
ASSERT_STREQ("....", b);
|
||||
}
|
||||
|
||||
TEST(ksnprintf, badUtf16) {
|
||||
size_t i;
|
||||
char b[16];
|
||||
static const struct {
|
||||
const char *want;
|
||||
const char *fmt;
|
||||
char16_t arg[16];
|
||||
} V[] = {
|
||||
{"<EFBFBD> ", "%10hs", {0xd800}},
|
||||
{"<EFBFBD> ", "%10hs", {0xdc00}},
|
||||
{"<EFBFBD><EFBFBD> ", "%10hs", {0xd800, 0xd800}},
|
||||
{"<EFBFBD><EFBFBD> ", "%10hs", {0xdc00, 0xdc00}},
|
||||
};
|
||||
for (i = 0; i < ARRAYLEN(V); ++i) {
|
||||
EXPECT_EQ(strlen(V[i].want), ksnprintf(b, 16, V[i].fmt, V[i].arg));
|
||||
EXPECT_STREQ(V[i].want, b);
|
||||
}
|
||||
}
|
||||
|
||||
BENCH(printf, bench) {
|
||||
char b[128];
|
||||
int snprintf_(char *, size_t, const char *, ...) asm("snprintf");
|
||||
EZBENCH2("ksnprintf fmt", donothing,
|
||||
ksnprintf(b, 128,
|
||||
"hello world\nhello world\nhello world\nhello world\n"));
|
||||
EZBENCH2("snprintf fmt", donothing,
|
||||
snprintf_(b, 128,
|
||||
"hello world\nhello world\nhello world\nhello world\n"));
|
||||
EZBENCH2("ksnprintf str", donothing,
|
||||
ksnprintf(b, 128, "%s\n", "hello world"));
|
||||
EZBENCH2("snprintf str", donothing,
|
||||
snprintf_(b, 128, "%s\n", "hello world"));
|
||||
EZBENCH2("ksnprintf utf8", donothing,
|
||||
ksnprintf(b, 128, "%s\n", "天地玄黄宇宙洪荒天地玄黄宇宙洪荒"));
|
||||
EZBENCH2("snprintf utf8", donothing,
|
||||
snprintf_(b, 128, "%s\n", "天地玄黄宇宙洪荒天地玄黄宇宙洪荒"));
|
||||
EZBENCH2("ksnprintf chinese", donothing,
|
||||
ksnprintf(b, 128, "%hs\n", u"天地玄黄宇宙洪荒"));
|
||||
EZBENCH2("snprintf chinese", donothing,
|
||||
snprintf_(b, 128, "%hs\n", u"天地玄黄宇宙洪荒"));
|
||||
EZBENCH2("ksnprintf astral", donothing,
|
||||
ksnprintf(b, 128, "%hs\n", u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷"));
|
||||
EZBENCH2("snprintf astral", donothing,
|
||||
snprintf_(b, 128, "%hs\n", u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷"));
|
||||
EZBENCH2("ksnprintf long", donothing, ksnprintf(b, 128, "%ld", LONG_MAX));
|
||||
EZBENCH2("snprintf long", donothing, snprintf_(b, 128, "%ld", LONG_MAX));
|
||||
EZBENCH2("ksnprintf thou", donothing, ksnprintf(b, 128, "%'ld", LONG_MAX));
|
||||
EZBENCH2("snprintf thou", donothing, snprintf_(b, 128, "%'ld", LONG_MAX));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue