diff --git a/test/libc/calls/getcwd_test.c b/test/libc/calls/getcwd_test.c index 022ca22b6..af7eb7851 100644 --- a/test/libc/calls/getcwd_test.c +++ b/test/libc/calls/getcwd_test.c @@ -30,14 +30,14 @@ char testlib_enable_tmp_setup_teardown; TEST(getcwd, test) { char buf[PATH_MAX]; - EXPECT_NE(-1, mkdir("subdir", 0755)); - EXPECT_NE(-1, chdir("subdir")); + EXPECT_SYS(0, 0, mkdir("subdir", 0755)); + EXPECT_SYS(0, 0, chdir("subdir")); EXPECT_STREQ("subdir", basename(getcwd(buf, ARRAYLEN(buf)))); } TEST(getcwd, testNullBuf_allocatesResult) { - EXPECT_NE(-1, mkdir("subdir", 0755)); - EXPECT_NE(-1, chdir("subdir")); + EXPECT_SYS(0, 0, mkdir("subdir", 0755)); + EXPECT_SYS(0, 0, chdir("subdir")); EXPECT_STREQ("subdir", basename(gc(getcwd(0, 0)))); } diff --git a/test/libc/calls/sigaction_test.c b/test/libc/calls/sigaction_test.c index fe4983c30..2cece08e6 100644 --- a/test/libc/calls/sigaction_test.c +++ b/test/libc/calls/sigaction_test.c @@ -23,6 +23,7 @@ #include "libc/calls/ucontext.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/nexgen32e/nexgen32e.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" @@ -34,6 +35,7 @@ struct sigaction oldsa; volatile bool gotsigint; void OnSigInt(int sig) { + _checkstackalign(); gotsigint = true; } @@ -46,11 +48,11 @@ void SetUp(void) { TEST(sigaction, raise) { struct sigaction saint = {.sa_handler = OnSigInt}; - EXPECT_NE(-1, sigaction(SIGINT, &saint, &oldsa)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &saint, &oldsa)); ASSERT_FALSE(gotsigint); EXPECT_NE(-1, raise(SIGINT)); ASSERT_TRUE(gotsigint); - EXPECT_NE(-1, sigaction(SIGINT, &oldsa, NULL)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &oldsa, NULL)); } //////////////////////////////////////////////////////////////////////////////// @@ -68,37 +70,36 @@ TEST(sigaction, testPingPongParentChildWithSigint) { // kind of runner. todo(fixme!) return; } - EXPECT_NE(-1, sigemptyset(&blockint)); - EXPECT_NE(-1, sigaddset(&blockint, SIGINT)); - EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &blockint, &oldmask)); - EXPECT_NE(-1, sigaction(SIGINT, &catchint, &oldint)); + EXPECT_SYS(0, 0, sigemptyset(&blockint)); + EXPECT_SYS(0, 0, sigaddset(&blockint, SIGINT)); + EXPECT_SYS(0, 0, sigprocmask(SIG_BLOCK, &blockint, &oldmask)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &catchint, &oldint)); ASSERT_NE(-1, (pid = fork())); if (!pid) { // ping - EXPECT_NE(-1, kill(getppid(), SIGINT)); + EXPECT_SYS(0, 0, kill(getppid(), SIGINT)); EXPECT_FALSE(gotsigint); // pong - EXPECT_NE(-1, sigaction(SIGINT, &catchint, 0)); - EXPECT_EQ(-1, sigsuspend(0)); - EXPECT_EQ(EINTR, errno); + EXPECT_SYS(0, 0, sigaction(SIGINT, &catchint, 0)); + EXPECT_SYS(EINTR, -1, sigsuspend(0)); EXPECT_TRUE(gotsigint); _exit(0); } // pong EXPECT_FALSE(gotsigint); - EXPECT_NE(-1, sigaction(SIGINT, &catchint, 0)); - EXPECT_EQ(-1, sigsuspend(0)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &catchint, 0)); + EXPECT_SYS(EINTR, -1, sigsuspend(0)); EXPECT_TRUE(gotsigint); // ping - EXPECT_NE(-1, sigaction(SIGINT, &ignoreint, 0)); - EXPECT_NE(-1, kill(pid, SIGINT)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &ignoreint, 0)); + EXPECT_SYS(0, 0, kill(pid, SIGINT)); // cleanup EXPECT_NE(-1, wait4(pid, &status, 0, 0)); EXPECT_EQ(1, WIFEXITED(status)); EXPECT_EQ(0, WEXITSTATUS(status)); EXPECT_EQ(0, WTERMSIG(status)); - EXPECT_NE(-1, sigaction(SIGINT, &oldint, 0)); - EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &oldmask, 0)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &oldint, 0)); + EXPECT_SYS(0, 0, sigprocmask(SIG_BLOCK, &oldmask, 0)); } //////////////////////////////////////////////////////////////////////////////// @@ -108,6 +109,7 @@ TEST(sigaction, testPingPongParentChildWithSigint) { volatile int trapeax; void OnTrap(int sig, struct siginfo *si, struct ucontext *ctx) { + _checkstackalign(); trapeax = ctx->uc_mcontext.rax; } @@ -116,7 +118,7 @@ TEST(sigaction, debugBreak_handlerCanReadCpuState) { EXPECT_NE(-1, sigaction(SIGTRAP, &saint, &oldsa)); asm("int3" : /* no outputs */ : "a"(0x31337)); EXPECT_EQ(0x31337, trapeax); - EXPECT_NE(-1, sigaction(SIGTRAP, &oldsa, NULL)); + EXPECT_SYS(0, 0, sigaction(SIGTRAP, &oldsa, NULL)); } //////////////////////////////////////////////////////////////////////////////// @@ -124,6 +126,7 @@ TEST(sigaction, debugBreak_handlerCanReadCpuState) { // test signal handler can modify cpu registers (now it's recoverable!) void SkipOverFaultingInstruction(struct ucontext *ctx) { + _checkstackalign(); struct XedDecodedInst xedd; xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); @@ -131,6 +134,7 @@ void SkipOverFaultingInstruction(struct ucontext *ctx) { } void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) { + _checkstackalign(); SkipOverFaultingInstruction(ctx); ctx->uc_mcontext.rax = 42; ctx->uc_mcontext.rdx = 0; @@ -138,10 +142,10 @@ void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) { noubsan void ubsanTrumpsSystemsEngineering(void) { struct sigaction saint = {.sa_sigaction = OnFpe, .sa_flags = SA_SIGINFO}; - EXPECT_NE(-1, sigaction(SIGFPE, &saint, &oldsa)); + EXPECT_SYS(0, 0, sigaction(SIGFPE, &saint, &oldsa)); volatile long x = 0; EXPECT_EQ(42, 666 / x); /* systems engineering trumps math */ - EXPECT_NE(-1, sigaction(SIGFPE, &oldsa, NULL)); + EXPECT_SYS(0, 0, sigaction(SIGFPE, &oldsa, NULL)); } TEST(sigaction, sigFpe_handlerCanEditProcessStateAndRecoverExecution) { diff --git a/tool/net/help.txt b/tool/net/help.txt index 2bad38c48..4cef7ae1a 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -1308,7 +1308,7 @@ FUNCTIONS the density of information. Cryptographic random should be in the ballpark of 7.9 whereas plaintext will be more like 4.5. - Compress(uncompdata:str[, level:int]) → compdata:str + Compress(uncompdata:str[, level:int[, raw:bool]]) → compdata:str Compresses data using DEFLATE algorithm. The compression format here is defined to be quick and handy for things like @@ -1319,18 +1319,27 @@ FUNCTIONS >: Uncompress(Compress('hello')) "hello" - `level` is the compression level, which defaults to 7. The max - is 10. Lower numbers go faster. Higher numbers go slower, but - have better compression ratios. - - [implementation details] The binary wire format is defined as follows: 1. uleb64 uncompressed byte size (1 to 10 bytes) 2. uint32_t crc32 (4 bytes; zlib polynomial) 3. data (created by zlib compress function) - Uncompress(compdata:str) → uncompdata:str + `level` is the compression level, which defaults to 7. The max + is 10. Lower numbers go faster. Higher numbers go slower, but + have better compression ratios. + + `raw` may be set to true if you only want `data` (3) to be + returned. In this case, it's assumed the caller will take + responsibility for storing the length (and optionall crc) + separately. See the redbean Crc32() API. + + >: a = 'hello' + >: b = Compress(a, 9, true) + >: Uncompress(b, #a) + "hello" + + Uncompress(compdata:str[, uncomplen:int]) → uncompdata:str Uncompresses data using DEFLATE algorithm. This applies the inverse transform of the Compress() function. See its docs for @@ -1341,6 +1350,15 @@ FUNCTIONS of validity iron-clad. It's implemented using Intel CLMUL so it has ludicrous speed performance as well. + If you used the `raw` parameter when calling Compress() i.e. + `compdata` doesn't have the redbean header described above, + then the `uncomplen` parameter may be supplied. IN that case + your data is handed over directly to zlib `uncompress()`. In + this case an exception will be raised if the value couldn't be + decoded, or if the resulting length differed from the supplied + length. It's recommended that Crc32() check still be performed + manually after using this method. + Benchmark(func[, count[, maxattempts]]) └─→ nanos:real, ticks:int, overhead-ticks:int, tries:int diff --git a/tool/net/lfuncs.c b/tool/net/lfuncs.c index 0304038e8..74a4f989c 100644 --- a/tool/net/lfuncs.c +++ b/tool/net/lfuncs.c @@ -683,6 +683,7 @@ int LuaBenchmark(lua_State *L) { } int LuaCompress(lua_State *L) { + bool raw; size_t n, m; char *q, *e; uint32_t crc; @@ -691,14 +692,23 @@ int LuaCompress(lua_State *L) { p = luaL_checklstring(L, 1, &n); level = luaL_optinteger(L, 2, Z_DEFAULT_COMPRESSION); m = compressBound(n); - CHECK_NOTNULL((q = LuaAlloc(L, 10 + 4 + m))); - crc = crc32_z(0, p, n); - e = uleb64(q, n); - e = WRITE32LE(e, crc); - hdrlen = e - q; - CHECK_EQ(Z_OK, compress2((unsigned char *)(q + hdrlen), &m, - (unsigned char *)p, n, level)); - lua_pushlstring(L, q, hdrlen + m); + if (lua_toboolean(L, 3)) { + // raw mode + CHECK_NOTNULL((q = LuaAlloc(L, m))); + CHECK_EQ(Z_OK, + compress2((unsigned char *)q, &m, (unsigned char *)p, n, level)); + lua_pushlstring(L, q, m); + } else { + // easy mode + CHECK_NOTNULL((q = LuaAlloc(L, 10 + 4 + m))); + crc = crc32_z(0, p, n); + e = uleb64(q, n); + e = WRITE32LE(e, crc); + hdrlen = e - q; + CHECK_EQ(Z_OK, compress2((unsigned char *)(q + hdrlen), &m, + (unsigned char *)p, n, level)); + lua_pushlstring(L, q, hdrlen + m); + } free(q); return 1; } @@ -710,18 +720,28 @@ int LuaUncompress(lua_State *L) { const char *p; size_t n, m, len; p = luaL_checklstring(L, 1, &n); - if ((rc = unuleb64(p, n, &m)) == -1 || n < rc + 4) { - luaL_error(L, "compressed value too short to be valid"); - unreachable; - } - len = m; - crc = READ32LE(p + rc); - CHECK_NOTNULL((q = LuaAlloc(L, m))); - if (uncompress((void *)q, &m, (unsigned char *)p + rc + 4, n) != Z_OK || - m != len || crc32_z(0, q, m) != crc) { - free(q); - luaL_error(L, "compressed value is corrupted"); - unreachable; + if (lua_isnoneornil(L, 2)) { + if ((rc = unuleb64(p, n, &m)) == -1 || n < rc + 4) { + luaL_error(L, "compressed value too short to be valid"); + unreachable; + } + len = m; + crc = READ32LE(p + rc); + CHECK_NOTNULL((q = LuaAlloc(L, m))); + if (uncompress((void *)q, &m, (unsigned char *)p + rc + 4, n) != Z_OK || + m != len || crc32_z(0, q, m) != crc) { + free(q); + luaL_error(L, "compressed value is corrupted"); + unreachable; + } + } else { + len = m = luaL_checkinteger(L, 2); + CHECK_NOTNULL((q = LuaAlloc(L, m))); + if (uncompress((void *)q, &m, (void *)p, n) != Z_OK || m != len) { + free(q); + luaL_error(L, "compressed value is corrupted"); + unreachable; + } } lua_pushlstring(L, q, m); free(q);