Merge remote-tracking branch 'upstream/master' into bugfix_typos

This commit is contained in:
Tim Gates 2021-08-09 06:49:29 +10:00
commit 6c013d7b86
No known key found for this signature in database
GPG key ID: AE3BE0D53823CF05
48 changed files with 696 additions and 750 deletions

Binary file not shown.

View file

@ -39,15 +39,17 @@
* @param l is byte length of `s`
* @return bytes appended (always `l`) or -1 if `ENOMEM`
* @see appendz(b).i to get buffer length
* @note 20% faster than appends()
*/
ssize_t appendd(char **b, const void *s, size_t l) {
char *p;
size_t n;
struct appendz z;
assert(b);
z = appendz((p = *b));
if (ROUNDUP(z.i + l + 1, 8) + W > z.n) {
n = ROUNDUP(z.i + l + 1, 8) + W;
if (n > z.n) {
if (!z.n) z.n = W * 2;
while (ROUNDUP(z.i + l + 1, 8) + W > z.n) z.n += z.n >> 1;
while (n > z.n) z.n += z.n >> 1;
z.n = ROUNDUP(z.n, W);
if ((p = realloc(p, z.n))) {
z.n = malloc_usable_size(p);
@ -59,9 +61,7 @@ ssize_t appendd(char **b, const void *s, size_t l) {
}
*(char *)mempcpy(p + z.i, s, l) = 0;
z.i += l;
if (!IsTiny() && W == 8) {
z.i |= (size_t)APPEND_COOKIE << 48;
}
if (!IsTiny() && W == 8) z.i |= (size_t)APPEND_COOKIE << 48;
*(size_t *)(p + z.n - W) = z.i;
return l;
}

View file

@ -27,6 +27,7 @@
*
* @return bytes appended or -1 if `ENOMEM`
* @see appendz(b).i to get buffer length
* @note O(1) amortized buffer growth
*/
ssize_t(appendf)(char **b, const char *fmt, ...) {
int n;

View file

@ -20,6 +20,7 @@
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/stdio/append.internal.h"
#include "libc/str/str.h"
@ -37,35 +38,39 @@
* free(b);
*
* If `i` is greater than the current length then the extra bytes are
* filled with NUL characters.
* filled with NUL characters. If `i` is less than the current length
* then memory is released to the system.
*
* The resulting buffer is guaranteed to be NUL-terminated, i.e.
* `!b[appendz(b).i]` will be the case.
* `!b[appendz(b).i]` will be the case even if both params are 0.
*
* @return `i` or -1 if `ENOMEM`
* @see appendz(b).i to get buffer length
*/
ssize_t appendr(char **b, size_t i) {
char *p;
size_t n;
struct appendz z;
assert(b);
z = appendz((p = *b));
z.n = ROUNDUP(i + 1, 8) + W;
if ((p = realloc(p, z.n))) {
z.n = malloc_usable_size(p);
assert(!(z.n & (W - 1)));
*b = p;
} else {
return -1;
if (i != z.i || !p) {
n = ROUNDUP(i + 1, 8) + W;
if (n > z.n || bsrl(n) < bsrl(z.n)) {
if ((p = realloc(p, n))) {
n = malloc_usable_size(p);
assert(!(n & (W - 1)));
*b = p;
} else {
return -1;
}
}
if (i > z.i) {
memset(p + z.i, 0, i - z.i + 1);
} else {
p[i] = 0;
}
*(size_t *)(p + n - W) =
i | (!IsTiny() && W == 8 ? (size_t)APPEND_COOKIE << 48 : 0);
}
if (i > z.i) {
memset(p, z.i, i - z.i);
}
z.i = i;
p[z.i] = 0;
if (!IsTiny() && W == 8) {
z.i |= (size_t)APPEND_COOKIE << 48;
}
*(size_t *)(p + z.n - W) = z.i;
return i;
}

View file

@ -31,6 +31,7 @@
*
* @return bytes appended (always `strlen(s)`) or -1 if `ENOMEM`
* @see appendz(b).i to get buffer length
* @note 2x faster than appendf()
*/
ssize_t appends(char **b, const char *s) {
return appendd(b, s, strlen(s));

View file

@ -16,18 +16,23 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/stdio/append.internal.h"
#define W sizeof(size_t)
/**
* Appends character or word-encoded string to buffer.
*
* Up to eight characters can be appended. For example:
*
* appendw(&s, 'h'|'i'<<8);
* appendw(&s, READ64LE("hi\0\0\0\0\0"));
*
* Is equivalent to:
* Are equivalent to:
*
* appends(&s, "hi");
*
@ -37,15 +42,40 @@
*
* Will append a single NUL character.
*
* This function is slightly faster than appendd() and appends(). Its
* main advantage is it improves code size in functions that call it.
*
* The resulting buffer is guaranteed to be NUL-terminated, i.e.
* `!b[appendz(b).i]` will be the case.
*
* @return bytes appended or -1 if `ENOMEM`
* @see appendz(b).i to get buffer length
*/
ssize_t appendw(char **b, uint64_t w) {
char t[8];
unsigned n = 1;
WRITE64LE(t, w);
if (w) n += bsrl(w) >> 3;
return appendd(b, t, n);
size_t n;
unsigned l;
char *p, *q;
struct appendz z;
z = appendz((p = *b));
l = w ? (bsrl(w) >> 3) + 1 : 1;
n = ROUNDUP(z.i + 8 + 1, 8) + W;
if (n > z.n) {
if (!z.n) z.n = W * 2;
while (n > z.n) z.n += z.n >> 1;
z.n = ROUNDUP(z.n, W);
if ((p = realloc(p, z.n))) {
z.n = malloc_usable_size(p);
assert(!(z.n & (W - 1)));
*b = p;
} else {
return -1;
}
}
q = p + z.i;
WRITE64LE(q, w);
q[8] = 0;
z.i += l;
if (!IsTiny() && W == 8) z.i |= (size_t)APPEND_COOKIE << 48;
*(size_t *)(p + z.n - W) = z.i;
return l;
}

View file

@ -26,6 +26,7 @@
/**
* Returns size of append buffer.
*
* @param p must be 0 or have been allocated by an append*() function
* @return i is number of bytes stored in buffer
* @return n is number of bytes in allocation
*/
@ -36,6 +37,12 @@ struct appendz appendz(char *p) {
assert(z.n >= W * 2 && !(z.n & (W - 1)));
z.i = *(size_t *)(p + z.n - W);
if (!IsTiny() && W == 8) {
/*
* This check should fail if an append*() function was passed a
* pointer that was allocated manually by malloc(). Append ptrs
* can be free()'d safely, but they need to be allocated by the
* append library, because we write a special value to the end.
*/
assert((z.i >> 48) == APPEND_COOKIE);
z.i &= 0x0000ffffffffffff;
}

52
libc/stdio/dumphexc.c Normal file
View file

@ -0,0 +1,52 @@
/*-*- 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/macros.internal.h"
#include "libc/stdio/append.internal.h"
#include "libc/stdio/hex.internal.h"
#include "libc/str/str.h"
/**
* Turns data into "\x00..." string literal.
*/
char *DumpHexc(const char *p, size_t n, size_t *z) {
long o;
int i, m;
char A[128], *q, *s = 0;
if (n == -1) n = p ? strlen(p) : 0;
appendw(&s, '"' | '\\' << 8 | '\n' << 16);
for (o = 0; (m = MIN(16, n)); p += m, n -= m) {
q = A;
for (i = 0; i < m; ++i) {
*q++ = '\\';
*q++ = 'x';
*q++ = "0123456789abcdef"[(p[i] & 0xF0) >> 4];
*q++ = "0123456789abcdef"[(p[i] & 0x0F) >> 0];
}
if (o) appendw(&s, '\\' | '\n' << 8);
appendd(&s, A, q - A);
o += m;
}
if (appendw(&s, '"') != -1) {
if (z) *z = appendz(s).i;
return s;
} else {
free(s);
return 0;
}
}

11
libc/stdio/hex.internal.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COSMOPOLITAN_LIBC_STDIO_HEX_INTERNAL_H_
#define COSMOPOLITAN_LIBC_STDIO_HEX_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
char *DumpHex(const char *, size_t, size_t *);
char *DumpHexc(const char *, size_t, size_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_STDIO_HEX_INTERNAL_H_ */

View file

@ -57,7 +57,7 @@ o/$(MODE)/libc/stdio/fputc.o: \
o//libc/stdio/appendw.o: \
OVERRIDE_CFLAGS += \
-O2
-Os
LIBC_STDIO_LIBS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x)))
LIBC_STDIO_SRCS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x)_SRCS))

View file

@ -30,14 +30,16 @@
ssize_t(vappendf)(char **b, const char *f, va_list v) {
char *p;
int r, s;
size_t n;
va_list w;
struct appendz z;
z = appendz((p = *b));
va_copy(w, v);
if ((r = (vsnprintf)(p + z.i, z.n ? z.n - W - z.i : 0, f, v)) >= 0) {
if (ROUNDUP(z.i + r + 1, 8) + W > z.n) {
n = ROUNDUP(z.i + r + 1, 8) + W;
if (n > z.n) {
if (!z.n) z.n = W * 2;
while (ROUNDUP(z.i + r + 1, 8) + W > z.n) z.n += z.n >> 1;
while (n > z.n) z.n += z.n >> 1;
z.n = ROUNDUP(z.n, W);
if ((p = realloc(p, z.n))) {
z.n = malloc_usable_size(p);

View file

@ -1,27 +1,28 @@
#ifndef COSMOPOLITAN_LIBC_BENCH_H_
#define COSMOPOLITAN_LIBC_BENCH_H_
#include "libc/bits/safemacros.internal.h"
#include "libc/nexgen32e/bench.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview Microbenchmarking tools.
* @fileoverview Microbenchmarking Toolz.
*/
#ifndef BENCHLOOP
#define BENCHLOOP(START, STOP, N, INIT, EXPR) \
({ \
unsigned long Iter, Count; \
double Average, Sample, Time1, Time2; \
for (Average = 1, Iter = 1, Count = (N); Iter < Count; ++Iter) { \
INIT; \
Time1 = START(); \
EXPR; \
Time2 = STOP(); \
Sample = Time2 - Time1; \
Average += 1. / Iter * (Sample - Average); \
} \
Average; \
#define BENCHLOOP(START, STOP, N, INIT, EXPR) \
({ \
unsigned long Iter, Count; \
uint64_t Time1, Time2; \
double Average; \
for (Average = 1, Iter = 1, Count = (N); Iter < Count; ++Iter) { \
INIT; \
Time1 = START(); \
EXPR; \
Time2 = STOP(); \
Average += 1. / Iter * (unsignedsubtract(Time2, Time1) - Average); \
} \
Average; \
})
#endif /* BENCHLOOP */

View file

@ -0,0 +1,34 @@
/*-*- 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/stdio/hex.internal.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/hyperion.h"
#include "libc/testlib/testlib.h"
TEST(DumpHexc, test) {
EXPECT_STREQ("\"\\\n\
\\x68\\x65\\x6c\\x6c\\x6f\\xe2\\x86\\x92\\x0a\\x01\\x02\\x74\\x68\\x65\\x65\\x72\\\n\
\\x68\\x75\\x72\\x63\\x65\\x6f\\x61\\x68\\x72\\x63\\x75\\x6f\\x65\\x61\\x75\\x68\\\n\
\\x63\\x72\"",
DumpHexc("hello→\n\1\2theerhurceoahrcuoeauhcr", -1, 0));
}
BENCH(DumpHexc, bench) {
EZBENCH2("dumphexc", donothing, free(DumpHexc(kHyperion, kHyperionSize, 0)));
}

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/stdio/append.internal.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
@ -87,8 +88,7 @@ TEST(appendw, test) {
EXPECT_EQ(0, b[0]);
EXPECT_EQ('h', b[1]);
EXPECT_EQ(0, b[2]);
ASSERT_NE(-1, appendw(&b, 'e' | 'l' << 8 | 'l' << 16 | 'o' << 24 |
(uint64_t)'!' << 32));
ASSERT_NE(-1, appendw(&b, READ64LE("ello!\0\0")));
EXPECT_EQ(7, appendz(b).i);
EXPECT_EQ(0, b[0]);
EXPECT_EQ('h', b[1]);
@ -101,7 +101,7 @@ TEST(appendw, test) {
free(b);
}
TEST(appendr, test) {
TEST(appendr, testShrink_nulTerminates) {
char *b = 0;
ASSERT_NE(-1, appends(&b, "hello"));
EXPECT_EQ(5, appendz(b).i);
@ -121,15 +121,54 @@ TEST(appendr, test) {
free(b);
}
TEST(appendr, testExtend_zeroFills) {
char *b = 0;
ASSERT_NE(-1, appends(&b, "hello"));
EXPECT_EQ(5, appendz(b).i);
ASSERT_NE(-1, appendr(&b, 20));
EXPECT_EQ(20, appendz(b).i);
ASSERT_BINEQ(u"hello                ", b);
ASSERT_NE(-1, appendr(&b, 20));
EXPECT_EQ(20, appendz(b).i);
ASSERT_BINEQ(u"hello                ", b);
free(b);
}
TEST(appendr, testAbsent_allocatesNul) {
char *b = 0;
ASSERT_NE(-1, appendr(&b, 0));
EXPECT_EQ(0, appendz(b).i);
ASSERT_BINEQ(u" ", b);
free(b);
}
TEST(appendd, testMemFail_doesntInitializePointer) {
char *b = 0;
ASSERT_EQ(-1, appendd(&b, 0, -1ull >> 8));
EXPECT_EQ(0, b);
}
TEST(appendd, testMemFail_doesntFreeExistingAllocation) {
char *b = 0;
ASSERT_NE(-1, appends(&b, "hello"));
EXPECT_STREQ("hello", b);
ASSERT_EQ(-1, appendd(&b, 0, -1ull >> 8));
EXPECT_STREQ("hello", b);
free(b);
}
BENCH(vappendf, bench) {
const char t[] = {0};
char *b = 0;
EZBENCH2("appendf", donothing, appendf(&b, "1"));
EZBENCH2("appendf", donothing, appendf(&b, "hello"));
free(b), b = 0;
EZBENCH2("appends", donothing, appends(&b, "1"));
EZBENCH2("appends", donothing, appends(&b, "hello"));
free(b), b = 0;
EZBENCH2("appendw", donothing, appendw(&b, 'B'));
EZBENCH2("appendw", donothing,
appendw(&b, 'h' | 'e' << 8 | 'l' << 16 | 'l' << 24 |
(uint64_t)'o' << 32));
free(b), b = 0;
EZBENCH2("appendd", donothing, appendd(&b, t, 1));
EZBENCH2("appendd", donothing, appendd(&b, "hello", 5));
EZBENCH2("appendr", donothing, appendr(&b, 0));
free(b), b = 0;
}

View file

@ -18,7 +18,6 @@
#include "third_party/lua/lstate.h"
#include "third_party/lua/lstring.h"
#include "third_party/lua/ltable.h"
#include "third_party/lua/larray.h"
#include "third_party/lua/ltm.h"
#include "third_party/lua/lua.h"
#include "third_party/lua/lundump.h"
@ -313,12 +312,6 @@ LUA_API int lua_isuserdata (lua_State *L, int idx) {
}
LUA_API int lua_isarray (lua_State *L, int idx) {
const TValue *o = index2value(L, idx);
return (isvalid(L, o) && ttype(o) == LUA_TTABLE && hvalue(o)->truearray);
}
LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
const TValue *o1 = index2value(L, index1);
const TValue *o2 = index2value(L, index2);
@ -766,41 +759,6 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
}
LUA_API void lua_createarray (lua_State *L, int narray) {
Array *a;
lua_lock(L);
a = luaA_new(L);
setavalue2s(L, L->top, a);
api_incr_top(L);
if (narray > 0)
luaA_resize(L, a, narray);
luaC_checkGC(L);
lua_unlock(L);
}
LUA_API void lua_resize (lua_State *L, int idx, unsigned int size) {
TValue *o;
Table *t;
unsigned int i, oldsize;
lua_lock(L);
o = index2value(L, idx);
api_check(L, ttistable(o), "table expected");
t = hvalue(o);
oldsize = t->sizeused;
if (size > luaH_realasize(t)) {
luaH_resizearray(L, t, size);
}
lua_unlock(L);
/* set removed elements to nil when shrinking array size */
for(i = size + 1; i <= oldsize; i++) {
lua_pushnil(L);
lua_seti(L, idx, i);
}
t->sizeused = size;
}
LUA_API int lua_getmetatable (lua_State *L, int objindex) {
const TValue *obj;
Table *mt;
@ -909,10 +867,7 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
api_checknelems(L, 1);
t = index2value(L, idx);
if (ttisarray(t)) {
luaA_setint(L, avalue(t), n, s2v(L->top - 1));
}
else if (luaV_fastgeti(L, t, n, slot)) {
if (luaV_fastgeti(L, t, n, slot)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
}
else {

View file

@ -1,107 +0,0 @@
/*
** Lua arrays
** See Copyright Notice in lua.h
*/
asm(".ident\t\"\\n\\n\
lua-array (MIT License)\\n\
Copyright 2018-2021 Petri Häkkinen\"");
asm(".include \"libc/disclaimer.inc\"");
#define larray_c
#define LUA_CORE
#include "third_party/lua/lprefix.h"
#include <libc/math.h>
#include <libc/limits.h>
#include "third_party/lua/lua.h"
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
#include "third_party/lua/lgc.h"
#include "third_party/lua/lmem.h"
#include "third_party/lua/lobject.h"
#include "third_party/lua/lstate.h"
#include "third_party/lua/lstring.h"
#include "third_party/lua/ltable.h"
#include "third_party/lua/larray.h"
#include "third_party/lua/lvm.h"
Array *luaA_new (lua_State *L) {
GCObject *o = luaC_newobj(L, LUA_TARRAY, sizeof(Array));
Array *a = gco2a(o);
a->array = NULL;
a->alimit = 0;
return a;
}
void luaA_resize (lua_State *L, Array *a, unsigned int newsize) {
unsigned int i;
unsigned int oldsize = a->alimit;
TValue *newarray;
/* allocate new array */
newarray = luaM_reallocvector(L, a->array, oldsize, newsize, TValue);
if (newarray == NULL && newsize > 0) { /* allocation failed? */
luaM_error(L); /* raise error (with array unchanged) */
}
/* allocation ok; initialize new part of the array */
a->array = newarray; /* set new array part */
a->alimit = newsize;
for (i = oldsize; i < newsize; i++) /* clear new slice of the array */
setempty(&a->array[i]);
}
void luaA_free (lua_State *L, Array *a) {
luaM_freearray(L, a->array, a->alimit);
luaM_free(L, a);
}
const TValue *luaA_getint (lua_State *L, Array *a, lua_Integer key) {
/* (1 <= key && key <= t->alimit) */
if (l_castS2U(key) - 1u < a->alimit)
return &a->array[key - 1];
else
return luaO_nilobject;
}
const TValue *luaA_get (lua_State *L, Array *a, const TValue *key) {
if (ttypetag(key) == LUA_VNUMINT) {
lua_Integer ikey = ivalue(key);
if (l_castS2U(ikey) - 1u < a->alimit)
return &a->array[ikey - 1];
else
return luaO_nilobject;
} else {
return luaO_nilobject;
}
}
void luaA_setint (lua_State *L, Array *a, lua_Integer key, TValue *value) {
if (l_castS2U(key) - 1u < a->alimit) {
/* set value! */
TValue* val = &a->array[key - 1];
val->value_ = value->value_;
val->tt_ = value->tt_;
checkliveness(L,val);
} else {
/* TODO: this error message could be improved! */
luaG_runerror(L, "array index out of bounds");
}
}
void luaA_set (lua_State *L, Array *a, const TValue* key, TValue *value) {
if (ttypetag(key) == LUA_VNUMINT) {
lua_Integer ikey = ivalue(key);
luaA_setint(L, a, ikey, value);
} else {
/* TODO: the error message could be improved */
luaG_runerror(L, "attempt to index array with a non-integer value");
}
}

View file

@ -1,22 +0,0 @@
/*
** Lua arrays
** See Copyright Notice in lua.h
*/
#ifndef larray_h
#define larray_h
#include "third_party/lua/lobject.h"
#define luaO_nilobject (&G(L)->nilvalue)
LUAI_FUNC Array *luaA_new (lua_State *L);
LUAI_FUNC void luaA_resize (lua_State *L, Array *a, unsigned int nsize);
LUAI_FUNC void luaA_free (lua_State *L, Array *a);
LUAI_FUNC const TValue *luaA_getint (lua_State *L, Array *a, lua_Integer key);
LUAI_FUNC void luaA_setint (lua_State *L, Array *a, lua_Integer key, TValue *value);
LUAI_FUNC const TValue *luaA_get (lua_State *L, Array *a, const TValue *key);
LUAI_FUNC void luaA_set (lua_State *L, Array *a, const TValue *key, TValue *value);
#endif

View file

@ -254,12 +254,9 @@ static int luaB_next (lua_State *L) {
}
}
static int luaB_ipairs (lua_State *L);
static int luaB_pairs (lua_State *L) {
luaL_checkany(L, 1);
if (lua_isarray(L, 1))
return luaB_ipairs(L);
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
lua_pushcfunction(L, luaB_next); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
@ -282,16 +279,6 @@ static int ipairsaux (lua_State *L) {
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}
/*
** Traversal function for 'ipairs' specialized for arrays.
*/
static int ipairsauxarray (lua_State *L) {
lua_Integer i = luaL_checkinteger(L, 2) + 1;
lua_pushinteger(L, i);
lua_geti(L, 1, i);
return (lua_rawlen(L, 1) == i-1) ? 1 : 2;
}
/*
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
@ -299,7 +286,7 @@ static int ipairsauxarray (lua_State *L) {
*/
static int luaB_ipairs (lua_State *L) {
luaL_checkany(L, 1);
lua_pushcfunction(L, lua_isarray(L, 1) ? ipairsauxarray : ipairsaux); /* iteration function */
lua_pushcfunction(L, ipairsaux); /* iteration function */
lua_pushvalue(L, 1); /* state */
lua_pushinteger(L, 0); /* initial value */
return 3;

View file

@ -688,7 +688,7 @@ static const char *varinfo (lua_State *L, const TValue *o) {
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a%s %s value%s", op, ttisarray(o) ? "n" : "", t, varinfo(L, o));
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
}

View file

@ -17,7 +17,6 @@
#include "third_party/lua/lstate.h"
#include "third_party/lua/lstring.h"
#include "third_party/lua/ltable.h"
#include "third_party/lua/larray.h"
#include "third_party/lua/ltm.h"
#include "third_party/lua/lua.h"
@ -778,9 +777,6 @@ static void freeobj (lua_State *L, GCObject *o) {
case LUA_VTABLE:
luaH_free(L, gco2t(o));
break;
case LUA_TARRAY:
luaA_free(L, gco2a(o));
break;
case LUA_VTHREAD:
luaE_freethread(L, gco2th(o));
break;

View file

@ -722,8 +722,6 @@ typedef struct Table {
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* log2 of size of 'node' array */
unsigned int alimit; /* "limit" of 'array' array */
lu_byte truearray; /* 1 if the table is a true array (no hash part) */
unsigned int sizeused; /* size reported by objlen for true arrays (unused for regular tables) */
TValue *array; /* array part */
Node *node;
Node *lastfree; /* any free position is before this position */
@ -793,31 +791,6 @@ LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t srclen);
/*
** {==================================================================
** Arrays
** ===================================================================
*/
#define ttisarray(o) checktag((o), ctb(LUA_TARRAY))
#define avalue(o) check_exp(ttisarray(o), gco2a(val_(o).gc))
#define setavalue(L,obj,x) \
{ TValue *io = (obj); Array *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TARRAY)); \
checkliveness(L,io); }
#define setavalue2s(L,o,h) setavalue(L,s2v(o),h)
typedef struct Array {
CommonHeader;
unsigned int alimit; /* size of 'array' array */
TValue *array; /* array part */
GCObject *gclist;
} Array;
/* }================================================================== */
#endif

View file

@ -905,14 +905,9 @@ static void field (LexState *ls, ConsControl *cc) {
}
static void constructor (LexState *ls, expdesc *t, int array) {
static void constructor (LexState *ls, expdesc *t) {
/* constructor -> '{' [ field { sep field } [sep] ] '}'
sep -> ',' | ';' */
/* special case for arrays (when 'array' is true):
constructor -> '[' [ listfield { sep listfield } [sep] ] ']'
sep -> ',' | ';' */
FuncState *fs = ls->fs;
int line = ls->linenumber;
int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
@ -923,32 +918,18 @@ static void constructor (LexState *ls, expdesc *t, int array) {
init_exp(t, VNONRELOC, fs->freereg); /* table will be at stack top */
luaK_reserveregs(fs, 1);
init_exp(&cc.v, VVOID, 0); /* no value (yet) */
luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */
checknext(ls, (array ? '[' : '{'));
checknext(ls, '{');
do {
lua_assert(cc.v.k == VVOID || cc.tostore > 0);
if (ls->t.token == (array ? ']' : '}')) break;
if (ls->t.token == '}') break;
closelistfield(fs, &cc);
if (array)
listfield(ls, &cc);
else
field(ls, &cc);
field(ls, &cc);
} while (testnext(ls, ',') || testnext(ls, ';'));
check_match(ls, array ? ']' : '}', array ? '[' : '{', line);
check_match(ls, '}', '{', line);
lastlistfield(fs, &cc);
luaK_settablesize(fs, pc, t->u.info, cc.na, cc.nh);
/* encode arrayness by setting B to max value (255) */
if (array) {
/* make sure B is not already 255 */
/* I don't this can happen in practice (max size is luaO_fb2int(255) = 3221225472), but let's be sure... */
unsigned int b = GETARG_B(fs->f->code[pc]);
if (b == 255)
luaX_syntaxerror(fs->ls, "table too large");
SETARG_B(fs->f->code[pc], 255);
}
}
/* }====================================================================== */
@ -1042,7 +1023,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
break;
}
case '{': { /* funcargs -> constructor */
constructor(ls, &args, 0);
constructor(ls, &args);
break;
}
case TK_STRING: { /* funcargs -> STRING */
@ -1177,11 +1158,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
break;
}
case '{': { /* constructor */
constructor(ls, v, 0);
return;
}
case '[': { /* array constructor */
constructor(ls, v, 1);
constructor(ls, v);
return;
}
case TK_FUNCTION: {

View file

@ -351,7 +351,6 @@ union GCUnion {
struct Udata u;
union Closure cl;
struct Table h;
struct Array a;
struct Proto p;
struct lua_State th; /* thread */
struct UpVal upv;
@ -374,7 +373,6 @@ union GCUnion {
#define gco2cl(o) \
check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
#define gco2t(o) check_exp((o)->tt == LUA_VTABLE, &((cast_u(o))->h))
#define gco2a(o) check_exp((o)->tt == LUA_TARRAY, &((cast_u(o))->a))
#define gco2p(o) check_exp((o)->tt == LUA_VPROTO, &((cast_u(o))->p))
#define gco2th(o) check_exp((o)->tt == LUA_VTHREAD, &((cast_u(o))->th))
#define gco2upv(o) check_exp((o)->tt == LUA_VUPVAL, &((cast_u(o))->upv))

View file

@ -565,7 +565,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
t->array = newarray; /* set new array part */
t->alimit = newasize;
for (i = oldasize; i < newasize; i++) /* clear new slice of the array */
setempty(&t->array[i]);
setempty(&t->array[i]);
/* re-insert elements from old hash part into new parts */
reinsert(L, &newt, t); /* 'newt' now has the old hash */
freehash(L, &newt); /* free old hash part */
@ -613,10 +613,8 @@ Table *luaH_new (lua_State *L) {
Table *t = gco2t(o);
t->metatable = NULL;
t->flags = cast_byte(maskflags); /* table has no metamethod fields */
t->truearray = 0;
t->array = NULL;
t->alimit = 0;
t->sizeused = 0;
setnodevector(L, t, 0);
return t;
}
@ -654,25 +652,7 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
TValue aux;
if (l_unlikely(ttisnil(key)))
luaG_runerror(L, "table index is nil");
else if (t->truearray) {
/* set new value to true array */
int capacity;
int asize = luaH_realasize(t);
int idx = ivalue(key); /* TODO: does not handle numbers larger than fits into a 32-bit signed integer! */
if (!ttisinteger(key) || idx < 1)
luaG_runerror(L, "invalid array index");
/* enlarge capacity */
if (asize < idx) {
capacity = asize + (asize >> 1);
if (capacity < idx)
capacity = idx;
luaH_resizearray(L, t, capacity);
}
t->sizeused = idx; // since this is guaranteed to be a new key, it exceeds t->sizeused
luaC_barrierback(L, obj2gco(t), key);
setobj2t(L, cast(TValue *, t->array + idx - 1), value);
return;
} else if (ttisfloat(key)) {
else if (ttisfloat(key)) {
lua_Number f = fltvalue(key);
lua_Integer k;
if (luaV_flttointeger(f, &k, F2Ieq)) { /* does key fit in an integer? */
@ -927,8 +907,6 @@ static unsigned int binsearch (const TValue *array, unsigned int i,
*/
lua_Unsigned luaH_getn (Table *t) {
unsigned int limit = t->alimit;
if (t->truearray)
return t->sizeused;
if (limit > 0 && isempty(&t->array[limit - 1])) { /* (1)? */
/* there must be a boundary before 'limit' */
if (limit >= 2 && !isempty(&t->array[limit - 2])) {

View file

@ -401,18 +401,6 @@ static int sort (lua_State *L) {
return 0;
}
static int resize (lua_State *L) {
/* reserve capacity of the array part -- useful when filling large tables/arrays */
int size;
luaL_checktype(L, 1, LUA_TTABLE);
size = luaL_checkinteger(L, 2);
luaL_argcheck(L, size >= 0, 2, "invalid size");
lua_resize(L, 1, (unsigned int)size);
return 0;
}
/* }====================================================== */
@ -424,7 +412,6 @@ static const luaL_Reg tab_funcs[] = {
{"remove", tremove},
{"move", tmove},
{"sort", sort},
{"resize", resize},
{NULL, NULL}
};

View file

@ -26,7 +26,7 @@ static const char udatatypename[] = "userdata";
LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTYPES] = {
"no value",
"nil", "boolean", udatatypename, "number",
"string", "table", "function", udatatypename, "thread", "array",
"string", "table", "function", udatatypename, "thread",
"upvalue", "proto" /* these last cases are used for tests only */
};
@ -264,3 +264,4 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
}

View file

@ -60,8 +60,8 @@ typedef struct lua_State lua_State;
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
#define LUA_TARRAY 9
#define LUA_NUMTYPES 10
#define LUA_NUMTYPES 9
@ -173,7 +173,6 @@ LUA_API int (lua_isstring) (lua_State *L, int idx);
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
LUA_API int (lua_isinteger) (lua_State *L, int idx);
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
LUA_API int (lua_isarray) (lua_State *L, int idx);
LUA_API int (lua_type) (lua_State *L, int idx);
LUA_API const char *(lua_typename) (lua_State *L, int tp);
@ -246,8 +245,6 @@ LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
LUA_API void (lua_createarray) (lua_State *L, int narr);
LUA_API void (lua_resize) (lua_State *L, int idx, unsigned int size);
LUA_API void *(lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue);
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
LUA_API int (lua_getiuservalue) (lua_State *L, int idx, int n);

39
third_party/lua/lvm.c vendored
View file

@ -17,7 +17,6 @@
#include "third_party/lua/lstate.h"
#include "third_party/lua/lstring.h"
#include "third_party/lua/ltable.h"
#include "third_party/lua/larray.h"
#include "third_party/lua/ltm.h"
#include "third_party/lua/lua.h"
#include "third_party/lua/lvm.h"
@ -284,11 +283,6 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
for (loop = 0; loop < MAXTAGLOOP; loop++) {
if (slot == NULL) { /* 't' is not a table? */
lua_assert(!ttistable(t));
if (ttisarray(t)) {
/* get array value */
setobj2s(L, val, luaA_get(L, avalue(t), key));
return;
}
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (l_unlikely(notm(tm)))
luaG_typeerror(L, t, "index"); /* no metamethod */
@ -337,17 +331,12 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
if (tm == NULL) { /* no metamethod? */
luaH_finishset(L, h, key, slot, val); /* set new value */
invalidateTMcache(h);
/* enlarge array length when necessary */
/* this should be quite fast as fields of h and key have already been loaded to CPU cache at this point */
h->sizeused += (val_(key).i > h->sizeused) & ttisinteger(key) & 1;
luaC_barrierback(L, obj2gco(h), val);
return;
}
/* else will try the metamethod */
}
else { /* not a table; check metamethod */
if(ttisarray(t))
luaG_typeerror(L, t, "set non-integer index of");
tm = luaT_gettmbyobj(L, t, TM_NEWINDEX);
if (l_unlikely(notm(tm)))
luaG_typeerror(L, t, "index");
@ -693,11 +682,6 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
setivalue(s2v(ra), luaH_getn(h)); /* else primitive len */
return;
}
case LUA_TARRAY: {
Array *a = avalue(rb);
setivalue(s2v(ra), a->alimit);
return;
}
case LUA_VSHRSTR: {
setivalue(s2v(ra), tsvalue(rb)->shrlen);
return;
@ -1257,10 +1241,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
const TValue *slot;
TValue *rb = vRB(i);
int c = GETARG_C(i);
if(ttisarray(rb)) {
setobj2s(L, ra, luaA_getint(L, avalue(rb), c));
}
else if (luaV_fastgeti(L, rb, c, slot)) {
if (luaV_fastgeti(L, rb, c, slot)) {
setobj2s(L, ra, slot);
}
else {
@ -1313,10 +1294,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
const TValue *slot;
int c = GETARG_B(i);
TValue *rc = RKC(i);
if(ttisarray(s2v(ra))) {
luaA_setint(L, avalue(s2v(ra)), c, rc);
}
else if (luaV_fastgeti(L, s2v(ra), c, slot)) {
if (luaV_fastgeti(L, s2v(ra), c, slot)) {
luaV_finishfastset(L, s2v(ra), slot, rc);
}
else {
@ -1341,8 +1319,6 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmcase(OP_NEWTABLE) {
int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */
/* decode arrayness */
int array = (b == 255);
Table *t;
if (b > 0)
b = 1 << (b - 1); /* size is 2^(b - 1) */
@ -1352,16 +1328,9 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
pc++; /* skip extra argument */
L->top = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */
t->truearray = array;
t->sizeused = c;
sethvalue2s(L, ra, t);
if (b != 0 || c != 0) {
if (array) {
luaH_resizearray(L, t, c); /* idem */
} else {
luaH_resize(L, t, c, b); /* idem */
}
}
if (b != 0 || c != 0)
luaH_resize(L, t, c, b); /* idem */
checkGC(L, ra + 1);
vmbreak;
}

15
third_party/lua/lvm.h vendored
View file

@ -88,13 +88,6 @@ typedef enum {
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!isempty(slot))) /* result not empty? */
/* This one supports arrays as well as tables. */
#define luaV_fastget2(L,t,k,slot,f) \
(ttisarray(t) ? (slot = f(avalue(t), k), !isempty(slot)) : \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!isempty(slot)))) /* result not empty? */
/*
** Special case of 'luaV_fastget' for integers, inlining the fast case
@ -107,14 +100,6 @@ typedef enum {
? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \
!isempty(slot))) /* result not empty? */
/* This one supports arrays as well as tables. */
#define luaV_fastgeti2(L,t,k,slot) \
(ttisarray(t) ? (slot = (l_castS2U(k) - 1u < avalue(t)->sizearray) ? &avalue(t)->array[k - 1] : luaO_nilobject, !isempty(slot)) : \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = (l_castS2U(k) - 1u < hvalue(t)->sizearray) \
? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \
!isempty(slot)))) /* result not empty? */
/*
** Finish a fast set operation (when fast get succeeds). In that case,

View file

@ -1,211 +0,0 @@
local errors = false
function assert(cond)
if not cond then
local line = debug.getinfo(2).currentline
print("test failed at line " .. line)
errors = true
end
end
-- test array constructor
do
local a = [1, 2, 3]
assert(a[1] == 1)
assert(a[2] == 2)
assert(a[3] == 3)
assert(#a == 3)
end
-- test nested array constructor
do
local a = [1, 2, 3, [4, 5]]
assert(a[1] == 1)
assert(a[2] == 2)
assert(a[3] == 3)
assert(a[4][1] == 4)
assert(a[4][2] == 5)
assert(#a == 4)
end
-- test array write
do
local a = [1, 2, 3]
a[1] = -1
assert(a[1] == -1)
assert(#a == 3)
end
-- test array extend
do
local a = [1, 2, 3]
a[7] = 5
assert(#a == 7)
assert(a[7] == 5)
end
-- test array extend 2
do
local a = []
for i=5,15 do
a[i] = i
assert(a[i] == i)
assert(#a == i)
end
end
-- test setting element to nil (should not affect array size)
do
local a = [1, 2, 3]
a[3] = nil
assert(a[3] == nil)
assert(#a == 3)
end
-- test array with holes
do
local a = [1, nil, 3]
assert(a[1] == 1)
assert(a[2] == nil)
assert(a[3] == 3)
assert(#a == 3)
a[1] = nil
assert(#a == 3)
end
-- test filling hole in array
do
local a = [1, nil, 3]
a[2] = 2
assert(a[2] == 2)
assert(#a == 3)
end
-- test filling hole in array 2
do
local a = [1, nil, 3]
local i = 2
a[i] = 2
assert(a[2] == 2)
assert(#a == 3)
end
-- test read out of bounds
do
local a = [1, 2, 3]
assert(#a == 3)
assert(a[0] == nil)
assert(a[4] == nil)
assert(#a == 3)
end
-- test array resize (array growing)
do
local a = [1, 2, 3]
table.resize(a, 1000)
assert(a[4] == nil)
assert(#a == 1000)
a[1] = 4
a[10] = 10
a[11] = 11
assert(#a == 1000)
end
-- test array resize (array shrinking)
do
local a = [1, 2, 3, 4, 5]
table.resize(a, 3)
assert(a[1] == 1)
assert(a[2] == 2)
assert(a[3] == 3)
assert(a[4] == nil)
assert(a[5] == nil)
assert(#a == 3)
end
-- test non-const integer
do
local a = []
local y = 3
a[y] = 66
assert(a[3] == 66)
assert(#a == 3)
end
-- test table.insert()
do
local a = [1, 2, 3]
table.insert(a, 1, "new")
assert(a[1] == "new")
assert(a[2] == 1)
assert(a[3] == 2)
assert(a[4] == 3)
assert(#a == 4)
end
-- test table.remove()
do
local a = [1, 2, 3]
table.remove(a, 1)
assert(a[1] == 2)
assert(a[2] == 3)
-- TODO: fix the implementation, as after upgrading to Lua 5.4.3
-- it keeps the array size the same after table.remove()
-- assert(#a == 2)
end
-- test ipairs
-- expected behavior: equivalent to for i=1,#a do print(i, a[i]) end
do
local a = [1, nil, 3, nil]
local cnt = 0
for k,v in ipairs(a) do
assert(v == a[k])
cnt = cnt + 1
end
assert(cnt == #a)
end
-- test pairs
-- expected behavior: same as ipairs?
do
local a = [1, nil, 3]
local cnt = 0
for k,v in pairs(a) do
assert(v == a[k])
cnt = cnt + 1
end
assert(cnt == 3)
end
-- test normal insert/remove operations
local function test (a)
assert(not pcall(table.insert, a, 2, 20));
table.insert(a, 10);
table.insert(a, 2, 20);
table.insert(a, 1, -1);
table.insert(a, 40);
table.insert(a, #a+1, 50)
table.insert(a, 2, -2)
assert(a[2] ~= undef)
assert(a["2"] == undef)
assert(not pcall(table.insert, a, 0, 20));
assert(not pcall(table.insert, a, #a + 2, 20));
assert(table.remove(a,1) == -1)
assert(table.remove(a,1) == -2)
assert(table.remove(a,1) == 10)
assert(table.remove(a,1) == 20)
assert(table.remove(a,1) == 40)
assert(table.remove(a,1) == 50)
assert(table.remove(a,1) == nil)
assert(table.remove(a) == nil)
assert(table.remove(a, #a) == nil)
end
a = {n=0, [-7] = "ban"}
test(a)
assert(a.n == 0 and a[-7] == "ban")
if not errors then
print("All tests passed!")
end

View file

@ -64,6 +64,7 @@
/* key exchange */
#define MBEDTLS_RSA_C
#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#ifndef TINY
#define MBEDTLS_ECP_C
#define MBEDTLS_ECDH_C
@ -72,13 +73,12 @@
#define MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
/*#define MBEDTLS_DHM_C*/
/*#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED*/
/*#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED*/
/*#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED*/
/*#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED*/
/*#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED*/
/*#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED*/
/*#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED*/
#endif

View file

@ -17,6 +17,7 @@
*/
#include "libc/calls/calls.h"
#include "third_party/mbedtls/asn1.h"
#include "third_party/mbedtls/bignum.h"
#include "third_party/mbedtls/common.h"
#include "third_party/mbedtls/dhm.h"
#include "third_party/mbedtls/error.h"
@ -322,7 +323,7 @@ static int dhm_random_below( mbedtls_mpi *R, const mbedtls_mpi *M,
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( R, mbedtls_mpi_size( M ), f_rng, p_rng ) );
while( mbedtls_mpi_cmp_mpi( R, M ) >= 0 )
mbedtls_mpi_shift_r( &R, 1 );
mbedtls_mpi_shift_r( R, 1 );
if( count++ > 10 )
return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );

View file

@ -1419,7 +1419,7 @@ int mbedtls_ssl_conf_dh_param_ctx( mbedtls_ssl_config *, mbedtls_dhm_context * )
int mbedtls_ssl_conf_dtls_srtp_protection_profiles( mbedtls_ssl_config *, const mbedtls_ssl_srtp_profile * );
int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *, unsigned char );
int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *, mbedtls_x509_crt *, mbedtls_pk_context * );
int mbedtls_ssl_conf_psk( mbedtls_ssl_config *, const unsigned char *, size_t, const unsigned char *, size_t );
int mbedtls_ssl_conf_psk( mbedtls_ssl_config *, const void *, size_t, const void *, size_t );
int mbedtls_ssl_context_load( mbedtls_ssl_context *, const unsigned char *, size_t );
int mbedtls_ssl_context_save( mbedtls_ssl_context *, unsigned char *, size_t, size_t * );
int mbedtls_ssl_get_ciphersuite_id( const char * );

View file

@ -72,16 +72,19 @@ static const uint16_t ciphersuite_preference[] =
#endif
#ifdef MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED
MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384,
MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256,
MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
#endif
@ -165,17 +168,25 @@ static const uint16_t ciphersuite_preference[] =
static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] =
{
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)
{ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "ECDHE-ECDSA-AES128-GCM-SHA256",
MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA,
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384)
{ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "ECDHE-ECDSA-AES256-GCM-SHA384",
MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
0 },
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)
{ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "ECDHE-ECDSA-AES256-GCM-SHA384",
MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA,
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384)
{ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "ECDHE-RSA-AES256-GCM-SHA384",
MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
0 },
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)
{ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "ECDHE-ECDSA-AES128-GCM-SHA256",
MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
0 },
@ -189,9 +200,9 @@ static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] =
0 },
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)
{ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "ECDHE-RSA-AES256-GCM-SHA384",
MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA,
#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384)
{ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, "ECDHE-PSK-AES256-GCM-SHA384",
MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
0 },
@ -267,6 +278,22 @@ static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] =
MBEDTLS_SHA256_C &&
MBEDTLS_SSL_PROTO_TLS1_2 */
#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)
{ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, "ECDHE-PSK-AES128-GCM-SHA256",
MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
0 },
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_CCM_C) && defined(MBEDTLS_SHA512_C)
{ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256, "ECDHE-PSK-AES128-CCM-SHA256",
MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
0 },
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
#if defined(MBEDTLS_AES_C)
#if defined(MBEDTLS_SHA1_C)

View file

@ -255,6 +255,12 @@ COSMOPOLITAN_C_START_
#define MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD /**< TLS 1.2 */
#define MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE /**< TLS 1.2 */
/* RFC 8442 */
#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 0xD001 /**< TLS 1.2 */
#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 0xD002 /**< TLS 1.2 */
#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256 0xD003 /**< TLS 1.2 */
#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256 0xD005 /**< TLS 1.2 */
/* Reminder: update mbedtls_ssl_premaster_secret when adding a new key exchange.
* Reminder: update MBEDTLS_KEY_EXCHANGE__xxx below
*/

View file

@ -4415,8 +4415,8 @@ static int ssl_conf_set_psk_identity( mbedtls_ssl_config *conf,
* \return An \c MBEDTLS_ERR_SSL_XXX error code on failure.
*/
int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf,
const unsigned char *psk, size_t psk_len,
const unsigned char *psk_identity,
const void *psk, size_t psk_len,
const void *psk_identity,
size_t psk_identity_len )
{
int ret = MBEDTLS_ERR_THIS_CORRUPTION;

View file

@ -55,6 +55,7 @@ TOOL_BUILD_DIRECTDEPS = \
THIRD_PARTY_GETOPT \
THIRD_PARTY_STB \
THIRD_PARTY_XED \
THIRD_PARTY_MBEDTLS \
THIRD_PARTY_ZLIB \
TOOL_BUILD_LIB

View file

@ -117,6 +117,9 @@ struct Command command;
const char *const kSafeEnv[] = {
"ADDR2LINE", // needed by GetAddr2linePath
"HOME", // needed by ~/.runit.psk
"HOMEDRIVE", // needed by ~/.runit.psk
"HOMEPATH", // needed by ~/.runit.psk
"MAKEFLAGS", // needed by IsRunningUnderMake
"MODE", // needed by test scripts
"PATH", // needed by clang

View file

@ -46,6 +46,7 @@ TOOL_BUILD_LIB_A_DIRECTDEPS = \
LIBC_UNICODE \
LIBC_X \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_MBEDTLS \
THIRD_PARTY_XED
TOOL_BUILD_LIB_A_DEPS := \

185
tool/build/lib/eztls.c Normal file
View file

@ -0,0 +1,185 @@
/*-*- 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/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/rand/rand.h"
#include "libc/sock/sock.h"
#include "libc/sysv/consts/sig.h"
#include "libc/x/x.h"
#include "third_party/mbedtls/ctr_drbg.h"
#include "third_party/mbedtls/ecp.h"
#include "third_party/mbedtls/error.h"
#include "third_party/mbedtls/ssl.h"
#include "tool/build/lib/eztls.h"
#include "tool/build/lib/psk.h"
struct EzTlsBio ezbio;
mbedtls_ssl_config ezconf;
mbedtls_ssl_context ezssl;
mbedtls_ctr_drbg_context ezrng;
static char *EzTlsError(int r) {
static char b[128];
mbedtls_strerror(r, b, sizeof(b));
return b;
}
static wontreturn void EzTlsDie(const char *s, int r) {
if (IsTiny()) {
fprintf(stderr, "error: %s (-0x%04x %s)\n", s, -r, EzTlsError(r));
} else {
fprintf(stderr, "error: %s (grep -0x%04x)\n", s, -r);
}
exit(1);
}
static int EzGetEntropy(void *c, unsigned char *p, size_t n) {
CHECK_EQ(n, getrandom(p, n, 0));
return 0;
}
static void EzInitializeRng(mbedtls_ctr_drbg_context *r) {
volatile unsigned char b[64];
mbedtls_ctr_drbg_init(r);
CHECK(getrandom(b, 64, 0) == 64);
CHECK(!mbedtls_ctr_drbg_seed(r, EzGetEntropy, 0, b, 64));
mbedtls_platform_zeroize(b, 64);
}
static ssize_t EzWritevAll(int fd, struct iovec *iov, int iovlen) {
int i;
ssize_t rc;
size_t wrote, total;
i = 0;
total = 0;
do {
if (i) {
while (i < iovlen && !iov[i].iov_len) ++i;
if (i == iovlen) break;
}
if ((rc = writev(fd, iov + i, iovlen - i)) != -1) {
wrote = rc;
total += wrote;
do {
if (wrote >= iov[i].iov_len) {
wrote -= iov[i++].iov_len;
} else {
iov[i].iov_base = (char *)iov[i].iov_base + wrote;
iov[i].iov_len -= wrote;
wrote = 0;
}
} while (wrote);
} else if (errno != EINTR) {
return total ? total : -1;
}
} while (i < iovlen);
return total;
}
int EzTlsFlush(struct EzTlsBio *bio, const unsigned char *buf, size_t len) {
struct iovec v[2];
if (len || bio->c > 0) {
v[0].iov_base = bio->u;
v[0].iov_len = MAX(0, bio->c);
v[1].iov_base = buf;
v[1].iov_len = len;
if (EzWritevAll(bio->fd, v, 2) != -1) {
if (bio->c > 0) bio->c = 0;
} else if (errno == EINTR) {
return MBEDTLS_ERR_NET_CONN_RESET;
} else if (errno == EAGAIN) {
return MBEDTLS_ERR_SSL_TIMEOUT;
} else if (errno == EPIPE || errno == ECONNRESET || errno == ENETRESET) {
return MBEDTLS_ERR_NET_CONN_RESET;
} else {
WARNF("EzTlsSend error %s", strerror(errno));
return MBEDTLS_ERR_NET_SEND_FAILED;
}
}
return 0;
}
static int EzTlsSend(void *ctx, const unsigned char *buf, size_t len) {
int rc;
struct iovec v[2];
struct EzTlsBio *bio = ctx;
if (bio->c >= 0 && bio->c + len <= sizeof(bio->u)) {
memcpy(bio->u + bio->c, buf, len);
bio->c += len;
return len;
}
if ((rc = EzTlsFlush(bio, buf, len)) < 0) return rc;
return len;
}
static int EzTlsRecvImpl(void *ctx, unsigned char *p, size_t n, uint32_t o) {
int r;
ssize_t s;
struct iovec v[2];
struct EzTlsBio *bio = ctx;
if ((r = EzTlsFlush(bio, 0, 0)) < 0) return r;
if (bio->a < bio->b) {
r = MIN(n, bio->b - bio->a);
memcpy(p, bio->t + bio->a, r);
if ((bio->a += r) == bio->b) bio->a = bio->b = 0;
return r;
}
v[0].iov_base = p;
v[0].iov_len = n;
v[1].iov_base = bio->t;
v[1].iov_len = sizeof(bio->t);
while ((r = readv(bio->fd, v, 2)) == -1) {
if (errno == EINTR) {
return MBEDTLS_ERR_SSL_WANT_READ;
} else if (errno == EAGAIN) {
return MBEDTLS_ERR_SSL_TIMEOUT;
} else if (errno == EPIPE || errno == ECONNRESET || errno == ENETRESET) {
return MBEDTLS_ERR_NET_CONN_RESET;
} else {
WARNF("tls read() error %s", strerror(errno));
return MBEDTLS_ERR_NET_RECV_FAILED;
}
}
if (r > n) bio->b = r - n;
return MIN(n, r);
}
static int EzTlsRecv(void *ctx, unsigned char *buf, size_t len, uint32_t tmo) {
return EzTlsRecvImpl(ctx, buf, len, tmo);
}
/*
* openssl s_client -connect 127.0.0.1:31337 \
* -psk $(hex <~/.runit.psk) \
* -psk_identity runit
*/
void SetupPresharedKeySsl(int endpoint) {
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
EzInitializeRng(&ezrng);
mbedtls_ssl_config_defaults(&ezconf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_SUITEC);
mbedtls_ssl_conf_rng(&ezconf, mbedtls_ctr_drbg_random, &ezrng);
DCHECK_EQ(0, mbedtls_ssl_conf_psk(&ezconf, GetRunitPsk(), 32, "runit", 5));
DCHECK_EQ(0, mbedtls_ssl_setup(&ezssl, &ezconf));
mbedtls_ssl_set_bio(&ezssl, &ezbio, EzTlsSend, 0, EzTlsRecv);
}

25
tool/build/lib/eztls.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_EZTLS_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_EZTLS_H_
#include "third_party/mbedtls/ctr_drbg.h"
#include "third_party/mbedtls/ssl.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct EzTlsBio {
int fd, c;
unsigned a, b;
unsigned char t[4000];
unsigned char u[1430];
};
extern struct EzTlsBio ezbio;
extern mbedtls_ssl_config ezconf;
extern mbedtls_ssl_context ezssl;
extern mbedtls_ctr_drbg_context ezrng;
void SetupPresharedKeySsl(int);
int EzTlsFlush(struct EzTlsBio *, const unsigned char *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_EZTLS_H_ */

61
tool/build/lib/psk.c Normal file
View file

@ -0,0 +1,61 @@
/*-*- 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/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
#include "tool/build/lib/psk.h"
/**
* Returns preshared key for runit testing infrastructure.
*/
void *GetRunitPsk(void) {
int fd;
struct stat st;
const char *a, *b;
char *r, p[PATH_MAX + 1];
if ((a = getenv("HOME"))) {
b = "";
} else if (IsWindows()) {
a = getenv("HOMEDRIVE");
b = getenv("HOMEPATH");
if (!a || !b) {
a = "C:";
b = "";
}
} else {
fprintf(stderr, "need $HOME\n");
exit(1);
}
snprintf(p, sizeof(p), "%s%s/.runit.psk", a, b);
if (stat(p, &st) == -1 || st.st_size != 32) {
fprintf(stderr, "need o//examples/getrandom.com -bn32 >~/.runit.psk\n");
exit(1);
}
CHECK_NOTNULL((r = malloc(32)));
CHECK_NE(-1, (fd = open(p, O_RDONLY)));
CHECK_EQ(32, read(fd, r, 32));
CHECK_NE(-1, close(fd));
return r;
}

10
tool/build/lib/psk.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PSK_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_PSK_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void *GetRunitPsk(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PSK_H_ */

View file

@ -16,63 +16,55 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/alg.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/flock.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/dns/dns.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/macros.internal.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/ipclassify.internal.h"
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/lock.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/shut.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sock.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "third_party/mbedtls/ssl.h"
#include "tool/build/lib/eztls.h"
#include "tool/build/runit.h"
/**
* @fileoverview Remote test runner.
*
* This is able to upload and run test binaries on remote operating
* systems with about 30 milliseconds of latency. It requires zero ops
* work too, since it deploys the ephemeral runit daemon via SSH upon
* ECONNREFUSED. That takes 10x longer (300 milliseconds). Further note
* there's no make -j race conditions here, thanks to SO_REUSEPORT.
* We want to scp .com binaries to remote machines and run them. The
* problem is that SSH is the slowest thing imaginable, taking about
* 300ms to connect to a host that's merely half a millisecond away.
*
* This program takes 17ms using elliptic curve diffie hellman exchange
* where we favor a 32-byte binary preshared key (~/.runit.psk) instead
* of certificates. It's how long it takes to connect, copy the binary,
* and run it. The remote daemon is deployed via SSH if it's not there.
*
* o/default/tool/build/runit.com \
* o/default/tool/build/runitd.com \
* o/default/test/libc/alg/qsort_test.com \
* freebsd.test.:31337:22
*
* APE binaries are hermetic and embed dependent files within their zip
* structure, which is why all we need is this simple test runner tool.
* The only thing that needs to be configured is /etc/hosts or Bind, to
* assign numbers to the officially reserved canned names. For example:
*
@ -97,12 +89,7 @@
* iptables -I INPUT 1 -s 10.0.0.0/8 -p tcp --dport 31337 -j ACCEPT
* iptables -I INPUT 1 -s 192.168.0.0/16 -p tcp --dport 31337 -j ACCEPT
*
* If your system administrator blocks all ICMP, you'll likely encounter
* difficulties. Consider offering feedback to his/her manager and grand
* manager.
*
* Finally note this tool isn't designed for untrustworthy environments.
* It also isn't designed to process untrustworthy inputs.
* This tool may be used in zero trust environments.
*/
static const struct addrinfo kResolvHints = {.ai_family = AF_INET,
@ -301,7 +288,9 @@ TryAgain:
void SendRequest(void) {
int fd;
int64_t off;
char *p;
size_t i;
ssize_t rc;
struct stat st;
const char *name;
unsigned char *hdr;
@ -309,6 +298,7 @@ void SendRequest(void) {
DEBUGF("running %s on %s", g_prog, g_hostname);
CHECK_NE(-1, (fd = open(g_prog, O_RDONLY)));
CHECK_NE(-1, fstat(fd, &st));
CHECK_NE(MAP_FAILED, (p = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
CHECK_LE((namesize = strlen((name = basename(g_prog)))), PATH_MAX);
CHECK_LE((progsize = st.st_size), INT_MAX);
CHECK_NOTNULL((hdr = gc(calloc(1, (hdrsize = 4 + 1 + 4 + 4 + namesize)))));
@ -326,25 +316,27 @@ void SendRequest(void) {
hdr[9 + 2] = (unsigned char)((unsigned)progsize >> 010);
hdr[9 + 3] = (unsigned char)((unsigned)progsize >> 000);
memcpy(&hdr[4 + 1 + 4 + 4], name, namesize);
CHECK_EQ(hdrsize, write(g_sock, hdr, hdrsize));
for (off = 0; off < progsize;) {
CHECK_GT(sendfile(g_sock, fd, &off, progsize - off), 0);
CHECK_EQ(hdrsize, mbedtls_ssl_write(&ezssl, hdr, hdrsize));
for (i = 0; i < progsize; i += rc) {
CHECK_GT((rc = mbedtls_ssl_write(&ezssl, p + i, progsize - i)), 0);
}
CHECK_NE(-1, shutdown(g_sock, SHUT_WR));
CHECK_NE(-1, EzTlsFlush(&ezbio, 0, 0));
CHECK_NE(-1, munmap(p, st.st_size));
CHECK_NE(-1, close(fd));
}
int ReadResponse(void) {
int res;
uint32_t size;
ssize_t rc;
size_t n, m;
uint32_t size;
unsigned char *p;
enum RunitCommand cmd;
static long backoff;
static unsigned char msg[512];
res = -1;
for (;;) {
if ((rc = recv(g_sock, msg, sizeof(msg), 0)) == -1) {
if ((rc = mbedtls_ssl_read(&ezssl, msg, sizeof(msg))) == -1) {
CHECK_EQ(ECONNRESET, errno);
usleep((backoff = (backoff + 1000) * 2));
break;
@ -369,7 +361,7 @@ int ReadResponse(void) {
size = READ32BE(p), p += 4, n -= 4;
while (size) {
if (n) {
CHECK_NE(-1, (rc = write(STDERR_FILENO, p, min(n, size))));
CHECK_NE(-1, (rc = write(STDERR_FILENO, p, MIN(n, size))));
CHECK_NE(0, (m = (size_t)rc));
p += m, n -= m, size -= m;
} else {
@ -400,7 +392,11 @@ int RunOnHost(char *spec) {
1);
if (!strchr(g_hostname, '.')) strcat(g_hostname, ".test.");
do {
mbedtls_ssl_session_reset(&ezssl);
Connect();
ezbio.fd = g_sock;
CHECK_EQ(0, mbedtls_ssl_handshake(&ezssl));
CHECK_NE(-1, EzTlsFlush(&ezbio, 0, 0));
SendRequest();
} while ((rc = ReadResponse()) == -1);
return rc;
@ -464,6 +460,7 @@ int RunRemoteTestsInParallel(char *hosts[], int count) {
int main(int argc, char *argv[]) {
showcrashreports();
SetupPresharedKeySsl(MBEDTLS_SSL_IS_CLIENT);
/* __log_level = kLogDebug; */
if (argc > 1 &&
(strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {

View file

@ -17,49 +17,37 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/nt/runtime.h"
#include "libc/paths.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#include "libc/stdio/temp.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/inaddr.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/shut.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
#include "libc/sysv/consts/w.h"
#include "libc/testlib/testlib.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "third_party/getopt/getopt.h"
#include "third_party/mbedtls/ssl.h"
#include "tool/build/lib/eztls.h"
#include "tool/build/runit.h"
/**
@ -208,7 +196,7 @@ void StartTcpServer(void) {
}
}
void SendExitMessage(int sock, int rc) {
void SendExitMessage(int rc) {
unsigned char msg[4 + 1 + 1];
msg[0 + 0] = (unsigned char)((unsigned)RUNITD_MAGIC >> 030);
msg[0 + 1] = (unsigned char)((unsigned)RUNITD_MAGIC >> 020);
@ -216,11 +204,12 @@ void SendExitMessage(int sock, int rc) {
msg[0 + 3] = (unsigned char)((unsigned)RUNITD_MAGIC >> 000);
msg[4] = kRunitExit;
msg[5] = (unsigned char)rc;
CHECK_EQ(sizeof(msg), send(sock, msg, sizeof(msg), 0));
CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg)));
CHECK_NE(-1, EzTlsFlush(&ezbio, 0, 0));
}
void SendOutputFragmentMessage(int sock, enum RunitCommand kind,
unsigned char *buf, size_t size) {
void SendOutputFragmentMessage(enum RunitCommand kind, unsigned char *buf,
size_t size) {
ssize_t rc;
size_t sent;
unsigned char msg[4 + 1 + 4];
@ -233,13 +222,14 @@ void SendOutputFragmentMessage(int sock, enum RunitCommand kind,
msg[5 + 1] = (unsigned char)((unsigned)size >> 020);
msg[5 + 2] = (unsigned char)((unsigned)size >> 010);
msg[5 + 3] = (unsigned char)((unsigned)size >> 000);
CHECK_EQ(sizeof(msg), send(sock, msg, sizeof(msg), 0));
CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg)));
while (size) {
CHECK_NE(-1, (rc = send(sock, buf, size, 0)));
CHECK_NE(-1, (rc = mbedtls_ssl_write(&ezssl, buf, size)));
CHECK_LE((sent = (size_t)rc), size);
size -= sent;
buf += sent;
}
CHECK_NE(-1, EzTlsFlush(&ezbio, 0, 0));
}
void OnAlarm(int sig) {
@ -274,9 +264,12 @@ void HandleClient(void) {
close(g_clifd);
return;
}
ezbio.fd = g_clifd;
CHECK_EQ(0, mbedtls_ssl_handshake(&ezssl));
CHECK_NE(-1, EzTlsFlush(&ezbio, 0, 0));
addrstr = gc(DescribeAddress(&addr));
DEBUGF("%s %s %s", gc(DescribeAddress(&g_servaddr)), "accepted", addrstr);
got = recv(g_clifd, (p = &g_buf[0]), sizeof(g_buf), 0);
got = mbedtls_ssl_read(&ezssl, (p = &g_buf[0]), sizeof(g_buf));
CHECK_GE(got, kMinMsgSize);
CHECK_LE(got, sizeof(g_buf));
CHECK_EQ(RUNITD_MAGIC, READ32BE(p));
@ -304,7 +297,7 @@ void HandleClient(void) {
remaining -= got;
}
while (remaining) {
CHECK_NE(-1, (got = recv(g_clifd, g_buf, sizeof(g_buf), 0)));
CHECK_NE(-1, (got = mbedtls_ssl_read(&ezssl, g_buf, sizeof(g_buf))));
CHECK_LE(got, remaining);
if (!got) {
LOGF("%s %s %,u/%,u %s", addrstr, "sent", remaining, filesize,
@ -351,7 +344,7 @@ void HandleClient(void) {
break;
}
fwrite(g_buf, got, 1, stderr);
SendOutputFragmentMessage(g_clifd, kRunitStderr, g_buf, got);
SendOutputFragmentMessage(kRunitStderr, g_buf, got);
} else {
CHECK_EQ(EINTR, errno);
}
@ -381,7 +374,8 @@ void HandleClient(void) {
/* let client know how it went */
LOGIFNEG1(unlink(g_exepath));
SendExitMessage(g_clifd, exitcode);
SendExitMessage(exitcode);
mbedtls_ssl_close_notify(&ezssl);
LOGIFNEG1(close(g_clifd));
_exit(0);
}
@ -442,6 +436,7 @@ void Daemonize(void) {
int main(int argc, char *argv[]) {
showcrashreports();
SetupPresharedKeySsl(MBEDTLS_SSL_IS_SERVER);
/* __log_level = kLogDebug; */
GetOpts(argc, argv);
CHECK_NE(-1, (g_devnullfd = open("/dev/null", O_RDWR)));

View file

@ -639,6 +639,9 @@ FUNCTIONS
Returns host associated with request. This will be the Host
header, if it's supplied. Otherwise it's the bind address.
GetHostOs() → str
Returns string that describes the host OS.
GetMonospaceWidth(str|char) → int
Returns monospace display width of string. This is useful for
fixed-width formatting. For example, CJK characters typically take
@ -1101,6 +1104,8 @@ CONSTANTS
kLogFatal
Integer for fatal logging level, which is less than kLogError.
Logging anything at this level will result in a backtrace and
process exit.
SEE ALSO

View file

@ -4911,7 +4911,7 @@ static int LuaLog(lua_State *L) {
level = luaL_checkinteger(L, 1);
if (LOGGABLE(level)) {
msg = luaL_checkstring(L, 2);
lua_getstack(L, 1, &ar);
lua_getstack(L, 0, &ar);
lua_getinfo(L, "nSl", &ar);
if (!strcmp(ar.name, "main")) {
module = strndup(effectivepath.p, effectivepath.n);
@ -5035,6 +5035,32 @@ static int LuaGetComment(lua_State *L) {
return 1;
}
static int LuaGetHostOs(lua_State *L) {
const char *s = NULL;
if (IsLinux()) {
s = "LINUX";
} else if (IsMetal()) {
s = "METAL";
} else if (IsWindows()) {
s = "WINDOWS";
} else if (IsXnu()) {
s = "XNU";
} else if (IsOpenbsd()) {
s = "OPENBSD";
} else if (IsFreebsd()) {
s = "FREEBSD";
} else if (IsNetbsd()) {
s = "NETBSD";
}
if (s) {
lua_pushstring(L, s);
} else {
lua_pushnil(L);
}
return 1;
}
static void LuaSetIntField(lua_State *L, const char *k, lua_Integer v) {
lua_pushinteger(L, v);
lua_setfield(L, -2, k);
@ -5194,6 +5220,7 @@ static bool LuaRun(const char *path, bool mandatory) {
} else {
WARNF("%s %s", path, lua_tostring(L, -1));
}
lua_pop(L, 1);
}
free(code);
}
@ -5236,6 +5263,7 @@ static const luaL_Reg kLuaFuncs[] = {
{"GetHeader", LuaGetHeader}, //
{"GetHeaders", LuaGetHeaders}, //
{"GetHost", LuaGetHost}, //
{"GetHostOs", LuaGetHostOs}, //
{"GetHttpReason", LuaGetHttpReason}, //
{"GetHttpVersion", LuaGetHttpVersion}, //
{"GetLastModifiedTime", LuaGetLastModifiedTime}, //

View file

@ -18,75 +18,30 @@
*/
#include "libc/fmt/fmt.h"
#include "libc/macros.internal.h"
#include "libc/stdio/append.internal.h"
#include "libc/stdio/hex.internal.h"
#include "libc/stdio/stdio.h"
struct Append {
size_t i, n;
char *p;
};
int AppendFmt(struct Append *b, const char *fmt, ...) {
int n;
char *p;
va_list va, vb;
va_start(va, fmt);
va_copy(vb, va);
n = vsnprintf(b->p + b->i, b->n - b->i, fmt, va);
if (n >= b->n - b->i) {
do {
if (b->n) {
b->n += b->n >> 1; /* this is the important line */
} else {
b->n = 16;
}
} while (b->i + n + 1 > b->n);
b->p = realloc(b->p, b->n);
vsnprintf(b->p + b->i, b->n - b->i, fmt, vb);
}
va_end(vb);
va_end(va);
b->i += n;
return n;
}
char *DumpHexc(const char *data, size_t size, size_t *z) {
long o;
int b, i, n;
char A[128], *p;
struct Append buf;
if (size == -1) size = data ? strlen(data) : 0;
buf.i = 0;
buf.n = 256;
buf.p = calloc(1, 256);
AppendFmt(&buf, "\"\\\n");
for (b = o = 0; (n = MIN(16, size)); data += n, size -= n) {
p = A;
for (i = 0; i < n; ++i) {
*p++ = '\\';
*p++ = 'x';
*p++ = "0123456789abcdef"[(data[i] & 0xF0) >> 4];
*p++ = "0123456789abcdef"[(data[i] & 0x0F) >> 0];
}
if (o) AppendFmt(&buf, "\\\n");
AppendFmt(&buf, "%.*s", p - A, A);
o += n;
}
AppendFmt(&buf, "\"");
if (z) *z = buf.i;
return buf.p;
}
/**
* @fileoverview Hex String Literal Converter, e.g.
*
* $ echo hello | o/tool/viz/dumphexc.com
* "\
* \x68\x65\x6c\x6c\x6f\x0a"
*/
int main(int argc, char *argv[]) {
char *p;
size_t n, g;
char *b = 0;
char buf[512];
struct Append b = {0};
while ((g = fread(buf, 1, sizeof(buf), stdin))) {
AppendFmt(&b, "%.*s", g, buf);
appendd(&b, buf, g);
}
if (!ferror(stdin)) {
p = DumpHexc(b.p, b.i, &n);
p = DumpHexc(b, appendz(b).i, &n);
fwrite(p, 1, n, stdout);
free(p);
}
printf("\n");
return ferror(stdin) || ferror(stdout) ? 1 : 0;