mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
ccan: update (for htable_getfirst/getnext)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
7efc0efab1
commit
ab09a42350
@ -1,3 +1,3 @@
|
||||
CCAN imported from http://ccodearchive.net.
|
||||
|
||||
CCAN version: init-2136-g64e9e71
|
||||
CCAN version: init-2181-g2953f51
|
||||
|
@ -213,7 +213,7 @@ static struct cdump_type *get_type(struct cdump_definitions *defs,
|
||||
enum cdump_type_kind kind,
|
||||
const char *name)
|
||||
{
|
||||
struct cdump_map *m;
|
||||
cdump_map_t *m;
|
||||
struct cdump_type *t;
|
||||
|
||||
switch (kind) {
|
||||
@ -609,7 +609,7 @@ static bool tok_take_enum(struct parse_state *ps)
|
||||
|
||||
static bool gather_undefines(const char *name,
|
||||
struct cdump_type *t,
|
||||
struct cdump_map *undefs)
|
||||
cdump_map_t *undefs)
|
||||
{
|
||||
if (!type_defined(t))
|
||||
strmap_add(undefs, name, t);
|
||||
@ -618,15 +618,15 @@ static bool gather_undefines(const char *name,
|
||||
|
||||
static bool remove_from_map(const char *name,
|
||||
struct cdump_type *t,
|
||||
struct cdump_map *map)
|
||||
cdump_map_t *map)
|
||||
{
|
||||
strmap_del(map, name, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void remove_undefined(struct cdump_map *map)
|
||||
static void remove_undefined(cdump_map_t *map)
|
||||
{
|
||||
struct cdump_map undefs;
|
||||
cdump_map_t undefs;
|
||||
|
||||
/* We can't delete inside iterator, so gather all the undefs
|
||||
* then remove them. */
|
||||
|
@ -50,14 +50,12 @@ struct cdump_type {
|
||||
};
|
||||
|
||||
/* The map of typenames to definitions */
|
||||
struct cdump_map {
|
||||
STRMAP_MEMBERS(struct cdump_type *);
|
||||
};
|
||||
typedef STRMAP(struct cdump_type *) cdump_map_t;
|
||||
|
||||
struct cdump_definitions {
|
||||
struct cdump_map enums;
|
||||
struct cdump_map structs;
|
||||
struct cdump_map unions;
|
||||
cdump_map_t enums;
|
||||
cdump_map_t structs;
|
||||
cdump_map_t unions;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -16,99 +16,107 @@ A simple system is a hash chain: we select a random seed value, the
|
||||
hash it 1,000,000 times. This gives the first "random" number.
|
||||
Hashed 999,999 times gives the second number, etc. ie:
|
||||
|
||||
R(1,000,000) = seed
|
||||
R(N-1) = SHA256(R(N))
|
||||
R(0) = seed
|
||||
R(N+1) = SHA256(R(N))
|
||||
|
||||
This way the remote node needs only to remember the last R(N) it was
|
||||
given, and it can calculate any R for N-1 or below.
|
||||
given, and it can calculate any R for N+1 or above.
|
||||
|
||||
However, this means we need to generate 1 million hashes up front, and
|
||||
then do almost as many hashes to derive the next number. That's slow.
|
||||
|
||||
A More Complex Solution
|
||||
-----------------------
|
||||
A Tree Solution
|
||||
---------------
|
||||
|
||||
Instead of a one-dimensional chain, we can use two dimensions: 1000
|
||||
chains of 1000 values each. Indeed, we can set generate the "top" of
|
||||
each chain much like we generated a single chain:
|
||||
A better solution is to use a binary tree, with the seed at the root.
|
||||
The left child is the same as the parent, the right child is the
|
||||
SHA256() of the parent with one bit flipped (corresponding to the
|
||||
height).
|
||||
|
||||
Chain 1000 Chain 999 Chain 998 ...........Chain 1
|
||||
seed SHA256(C1000) SHA256(C999) ....... SHA256(C2)
|
||||
This gives a tree like so:
|
||||
|
||||
Now, deriving chain 1000 from seed doesn't quite work, because it'll
|
||||
look like this chain, so we flip the lower bit to generate the chain:
|
||||
seed
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
seed SHA256(seed^1)
|
||||
/ \ / \
|
||||
seed SHA256(seed^2) SHA256(seed^1) SHA256(SHA256(seed^1)^2)
|
||||
Index: 0 1 2 3
|
||||
|
||||
Chain 1000 Chain 999 Chain 998 ...........Chain 1
|
||||
1000 seed^1 SHA256(C1000)^1 SHA256(C999)^1...... SHA256(C2)^1
|
||||
999 SHA256(above) SHA256(above) SHA256(above) ..... SHA256(above)
|
||||
998 SHA256(above) SHA256(above) SHA256(above) ..... SHA256(above)
|
||||
...
|
||||
Clearly, giving R(2) allows you to derive R(3), giving R(1) allows you
|
||||
to derive nothing new (you still have to remember R(2)), and giving
|
||||
R(0) allows you to derive everything.
|
||||
|
||||
Now, we can get the first value to give out (chain 1, position 1) with
|
||||
999 hashes to get to chain 1, and 999 hashes to get to the end of the
|
||||
chain. 2000 hashes is much better than the 999,999 hashes it would
|
||||
have taken previously.
|
||||
In pseudocode, this looks like the following for a 64 bit tree:
|
||||
|
||||
Why Stop at 2 Dimensions?
|
||||
-------------------------
|
||||
generate_from_seed(index):
|
||||
value = seed
|
||||
for bit in 0 to 63:
|
||||
if bit set in index:
|
||||
flip(bit) in value
|
||||
value = SHA256(value)
|
||||
return value
|
||||
|
||||
Indeed, the implementation uses 64 dimensions rather than 2, and a
|
||||
chain length of 2 rather than 1000, giving a worst-case of 63 hashes
|
||||
to derive any of 2^64 values. Each dimension flips a different bit of
|
||||
the hash, to ensure the chains are distinct.
|
||||
|
||||
For simplicity, I'll explain what this looks like using 8 dimensions,
|
||||
ie. 8 bits. The seed value always sits the maximum possible index, in
|
||||
this case index 0xFF (b11111111).
|
||||
The Receiver's Tree
|
||||
-------------------
|
||||
|
||||
To generate the hash for 0xFE (b11111110), we need to move down
|
||||
dimension 0, so we flip bit 0 of the seed value, then hash it. To
|
||||
generate the hash for 0xFD (b11111101) we need to move down dimension
|
||||
1, so we flip bit 1 of the seed value, then hash it.
|
||||
To derive the value for a index N, you need to have the root of a tree
|
||||
which contains it. That is the same as needing an index I which is N
|
||||
rounded down in binary: eg. if N is 0b001100001, you need 0b001100000,
|
||||
0b001000000 or 0b000000000.
|
||||
|
||||
To reach 0xFC (b11111100) we need to move down dimension 1 then
|
||||
dimension 0, in that order.
|
||||
Pseudocode:
|
||||
|
||||
Spotting the pattern, it becomes easy to derive how to reach any value:
|
||||
# Can we derive the value for to_index from from_index?
|
||||
can_derive(from_index, to_index):
|
||||
# to_index must be a subtree under from_index; this is the same as
|
||||
# saying that to_index must be the same as from_index up to the
|
||||
# trailing zeros in from_index.
|
||||
for bit in count_trailing_zeroes(from_index)..63:
|
||||
if bit set in from_index != bit set in to_index:
|
||||
return false
|
||||
return true
|
||||
|
||||
hash = seed
|
||||
for bit in 7 6 5 4 3 2 1 0:
|
||||
if bit not set in index:
|
||||
flip(bit) in hash
|
||||
hash = SHA256(hash)
|
||||
# Derive a value from a lesser index: generalization of generate_from_seed()
|
||||
derive(from_index, to_index, from_value):
|
||||
assert(can_derive(from_index, to_index))
|
||||
value = from_value
|
||||
for bit in 0..63:
|
||||
if bit set in to_index and not bit set in from_index:
|
||||
flip bit in value
|
||||
value = SHA256(value)
|
||||
return value
|
||||
|
||||
Handling Partial Knowledge
|
||||
--------------------------
|
||||
If you are receiving values (in reverse order), you need to remember
|
||||
up to 64 of them to derive all previous values. The simplest method
|
||||
is to keep an array, indexed by the number of trailing zeroes in the
|
||||
received index:
|
||||
|
||||
How does the remote node, which doesn't know the seed value, derive
|
||||
subvalues?
|
||||
# Receive a new value (assumes we receive them in order)
|
||||
receive_value(index, value):
|
||||
pos = count_trailing_zeroes(index)
|
||||
# We should be able to generate every lesser value, otherwise invalid
|
||||
for i in 0..pos-1:
|
||||
if derive(index, value, known[i].index) != known[i].value:
|
||||
return false
|
||||
known[pos].index = index
|
||||
known[pos].value = value
|
||||
return true
|
||||
|
||||
Once it knows the value for index 1, it can derive the value for index
|
||||
0 by flipping bit 0 of the value and hashing it. In effect, it can
|
||||
always derive a value for any index where it only needs to clear bits.
|
||||
To derive a previous value, find an element in that array from which
|
||||
you can derive the value you want, eg:
|
||||
|
||||
So, index 1 gives index 0, but index 2 doesn't yield index 1. When
|
||||
index 3 comes along, it yields 2, 1, and 0.
|
||||
# Find an old value
|
||||
regenerate_value(index):
|
||||
for i in known:
|
||||
if can_derive(i.index, index):
|
||||
return derive(i.index, i.value, index)
|
||||
fail
|
||||
|
||||
How many hash values will we have to remember at once? The answer is
|
||||
equal to the number of dimensions. It turns out that the worst case
|
||||
for 8 dimensions is 254 (0b11111110), for which we will have to
|
||||
remember the following indices:
|
||||
|
||||
127 0b01111111
|
||||
191 0b10111111
|
||||
223 0b11011111
|
||||
239 0b11101111
|
||||
247 0b11110111
|
||||
251 0b11111011
|
||||
253 0b11111101
|
||||
254 0b11111110
|
||||
|
||||
127 lets us derive any hash value for index <= 127. Similarly, 191
|
||||
lets us derive anything > 127 but <= 191. 254 lets us derive only
|
||||
itself.
|
||||
|
||||
When we get index 255 this collapses, and we only need to remember
|
||||
that one index to derive everything.
|
||||
You can see the implementation for more optimized variants of the
|
||||
above code.
|
||||
|
||||
Rusty Russell <rusty@rustcorp.com.au>
|
||||
|
@ -5,15 +5,39 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define INDEX_BITS ((sizeof(shachain_index_t)) * CHAR_BIT)
|
||||
|
||||
static void change_bit(unsigned char *arr, size_t index)
|
||||
{
|
||||
arr[index / CHAR_BIT] ^= (1 << (index % CHAR_BIT));
|
||||
}
|
||||
|
||||
/* We can only ever *unset* bits, so to must only have bits in from. */
|
||||
static int count_trailing_zeroes(shachain_index_t index)
|
||||
{
|
||||
#if HAVE_BUILTIN_CTZLL
|
||||
return index ? __builtin_ctzll(index) : INDEX_BITS;
|
||||
#else
|
||||
int i;
|
||||
|
||||
for (i = 0; i < INDEX_BITS; i++) {
|
||||
if (index & (1ULL << i))
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool can_derive(shachain_index_t from, shachain_index_t to)
|
||||
{
|
||||
return (~from & to) == 0;
|
||||
shachain_index_t mask;
|
||||
|
||||
/* Corner case: can always derive from seed. */
|
||||
if (from == 0)
|
||||
return true;
|
||||
|
||||
/* Leading bits must be the same */
|
||||
mask = ~((1ULL << count_trailing_zeroes(from))-1);
|
||||
return ((from ^ to) & mask) == 0;
|
||||
}
|
||||
|
||||
static void derive(shachain_index_t from, shachain_index_t to,
|
||||
@ -28,7 +52,7 @@ static void derive(shachain_index_t from, shachain_index_t to,
|
||||
/* We start with the first hash. */
|
||||
*hash = *from_hash;
|
||||
|
||||
/* This represents the bits set in from, and not to. */
|
||||
/* This represents the bits set in to, and not from. */
|
||||
branches = from ^ to;
|
||||
for (i = ilog64(branches) - 1; i >= 0; i--) {
|
||||
if (((branches >> i) & 1)) {
|
||||
@ -41,45 +65,42 @@ static void derive(shachain_index_t from, shachain_index_t to,
|
||||
void shachain_from_seed(const struct sha256 *seed, shachain_index_t index,
|
||||
struct sha256 *hash)
|
||||
{
|
||||
derive((shachain_index_t)-1ULL, index, seed, hash);
|
||||
derive(0, index, seed, hash);
|
||||
}
|
||||
|
||||
void shachain_init(struct shachain *chain)
|
||||
{
|
||||
chain->num_valid = 0;
|
||||
chain->max_index = 0;
|
||||
chain->min_index = 0;
|
||||
}
|
||||
|
||||
bool shachain_add_hash(struct shachain *chain,
|
||||
shachain_index_t index, const struct sha256 *hash)
|
||||
{
|
||||
int i;
|
||||
int i, pos;
|
||||
|
||||
/* You have to insert them in order! */
|
||||
assert(index == chain->max_index + 1 ||
|
||||
(index == 0 && chain->num_valid == 0));
|
||||
|
||||
for (i = 0; i < chain->num_valid; i++) {
|
||||
/* If we could derive this value, we don't need it,
|
||||
* not any others (since they're in order). */
|
||||
if (can_derive(index, chain->known[i].index)) {
|
||||
struct sha256 expect;
|
||||
assert(index == chain->min_index - 1 ||
|
||||
(index == (shachain_index_t)(-1ULL) && chain->num_valid == 0));
|
||||
|
||||
/* Make sure the others derive as expected! */
|
||||
derive(index, chain->known[i].index, hash, &expect);
|
||||
if (memcmp(&expect, &chain->known[i].hash,
|
||||
sizeof(expect)) != 0)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
pos = count_trailing_zeroes(index);
|
||||
|
||||
/* All derivable answers must be valid. */
|
||||
/* FIXME: Is it sufficient to check just the next answer? */
|
||||
for (i = 0; i < pos; i++) {
|
||||
struct sha256 expect;
|
||||
|
||||
/* Make sure the others derive as expected! */
|
||||
derive(index, chain->known[i].index, hash, &expect);
|
||||
if (memcmp(&expect, &chain->known[i].hash, sizeof(expect)))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This can happen if you skip indices! */
|
||||
assert(i < sizeof(chain->known) / sizeof(chain->known[0]));
|
||||
chain->known[i].index = index;
|
||||
chain->known[i].hash = *hash;
|
||||
chain->num_valid = i+1;
|
||||
chain->max_index = index;
|
||||
chain->known[pos].index = index;
|
||||
chain->known[pos].hash = *hash;
|
||||
if (pos + 1 > chain->num_valid)
|
||||
chain->num_valid = pos + 1;
|
||||
chain->min_index = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -14,49 +14,49 @@
|
||||
/**
|
||||
* shachain_from_seed - Generate an unpredictable SHA from a seed value.
|
||||
* @seed: (secret) seed value to use
|
||||
* @index: index of value to generate.
|
||||
* @index: index of value to generate (0 == seed)
|
||||
* @hash: value generated
|
||||
*
|
||||
* There will be no way to derive the result from that generated for
|
||||
* any *lesser* index.
|
||||
* any *greater* index.
|
||||
*
|
||||
* Example:
|
||||
* #include <time.h>
|
||||
*
|
||||
* static void next_hash(struct sha256 *hash)
|
||||
* {
|
||||
* static uint64_t index = 0;
|
||||
* static uint64_t index = 0xFFFFFFFFFFFFFFFFULL;
|
||||
* static struct sha256 seed;
|
||||
*
|
||||
* // First time, initialize seed.
|
||||
* if (index == 0) {
|
||||
* if (index == 0xFFFFFFFFFFFFFFFFULL) {
|
||||
* // DO NOT DO THIS! Very predictable!
|
||||
* time_t now = time(NULL);
|
||||
* memcpy(&seed, &now, sizeof(now));
|
||||
* }
|
||||
*
|
||||
* shachain_from_seed(&seed, index++, hash);
|
||||
* shachain_from_seed(&seed, index--, hash);
|
||||
* }
|
||||
*/
|
||||
void shachain_from_seed(const struct sha256 *seed, shachain_index_t index,
|
||||
struct sha256 *hash);
|
||||
|
||||
/**
|
||||
* shachain - structure for recording/deriving incrementing chain members
|
||||
* @max_index: maximum index value successfully shachain_add_hash()ed.
|
||||
* @num_valid: number of known[] array valid. If non-zero, @max_index valid.
|
||||
* @known: known values to allow us to derive those <= @max_index.
|
||||
* shachain - structure for recording/deriving decrementing chain members
|
||||
* @min_index: minimum index value successfully shachain_add_hash()ed.
|
||||
* @num_valid: number of known[] array valid. If non-zero, @min_index valid.
|
||||
* @known: known values to allow us to derive those >= @min_index.
|
||||
*
|
||||
* This is sufficient storage to derive any shachain hash value previously
|
||||
* added.
|
||||
*/
|
||||
struct shachain {
|
||||
shachain_index_t max_index;
|
||||
shachain_index_t min_index;
|
||||
unsigned int num_valid;
|
||||
struct {
|
||||
shachain_index_t index;
|
||||
struct sha256 hash;
|
||||
} known[sizeof(shachain_index_t) * 8];
|
||||
} known[sizeof(shachain_index_t) * 8 + 1];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -73,8 +73,9 @@ void shachain_init(struct shachain *chain);
|
||||
* @index: the index of the hash
|
||||
* @hash: the hash value.
|
||||
*
|
||||
* You can only add index 0 (for a freshly initialized chain), or one more
|
||||
* than the previously successfully added value.
|
||||
* You can only add index 0xFFFFFFFFFFFFFFFF (for a freshly
|
||||
* initialized chain), or one less than the previously successfully
|
||||
* added value.
|
||||
*
|
||||
* This can fail (return false without altering @chain) if the hash
|
||||
* for this index isn't consistent with previous hashes (ie. wasn't
|
||||
@ -85,10 +86,10 @@ void shachain_init(struct shachain *chain);
|
||||
* Example:
|
||||
* static void next_hash(const struct sha256 *hash)
|
||||
* {
|
||||
* static uint64_t index = 0;
|
||||
* static uint64_t index = 0xFFFFFFFFFFFFFFFFULL;
|
||||
* static struct shachain chain;
|
||||
*
|
||||
* if (!shachain_add_hash(&chain, index++, hash))
|
||||
* if (!shachain_add_hash(&chain, index--, hash))
|
||||
* errx(1, "Corrupted hash value?");
|
||||
* }
|
||||
*/
|
||||
@ -111,14 +112,14 @@ bool shachain_add_hash(struct shachain *chain,
|
||||
*
|
||||
* static void next_hash(const struct sha256 *hash)
|
||||
* {
|
||||
* static uint64_t index = 0;
|
||||
* static uint64_t index = 0xFFFFFFFFFFFFFFFFULL;
|
||||
* static struct shachain chain;
|
||||
*
|
||||
* if (!shachain_add_hash(&chain, index++, hash))
|
||||
* if (!shachain_add_hash(&chain, index--, hash))
|
||||
* errx(1, "Corrupted hash value?");
|
||||
* else {
|
||||
* struct sha256 check;
|
||||
* assert(shachain_get_hash(&chain, index-1, &check));
|
||||
* assert(shachain_get_hash(&chain, index+1, &check));
|
||||
* assert(structeq(&check, hash));
|
||||
* }
|
||||
* }
|
||||
|
@ -13,39 +13,41 @@ int main(void)
|
||||
{
|
||||
struct sha256 seed;
|
||||
struct shachain chain;
|
||||
struct sha256 expect[NUM_TESTS];
|
||||
size_t i, j;
|
||||
struct sha256 expect[NUM_TESTS+1];
|
||||
int i, j;
|
||||
|
||||
/* This is how many tests you plan to run */
|
||||
plan_tests(NUM_TESTS * 3 + NUM_TESTS * (NUM_TESTS + 1));
|
||||
plan_tests(66559);
|
||||
|
||||
memset(&seed, 0, sizeof(seed));
|
||||
/* Generate a whole heap. */
|
||||
for (i = 0; i < NUM_TESTS; i++) {
|
||||
/* Generate a whole heap; each should be different */
|
||||
for (i = 0; i <= NUM_TESTS; i++) {
|
||||
shachain_from_seed(&seed, i, &expect[i]);
|
||||
if (i == 0)
|
||||
ok1(memcmp(&expect[i], &seed, sizeof(expect[i])));
|
||||
ok1(memcmp(&expect[i], &seed, sizeof(expect[i])) == 0);
|
||||
else
|
||||
ok1(memcmp(&expect[i], &expect[i-1], sizeof(expect[i])));
|
||||
}
|
||||
|
||||
shachain_init(&chain);
|
||||
|
||||
for (i = 0; i < NUM_TESTS; i++) {
|
||||
for (i = NUM_TESTS; i > 0; i--) {
|
||||
struct sha256 hash;
|
||||
|
||||
ok1(shachain_add_hash(&chain, i, &expect[i]));
|
||||
for (j = 0; j <= i; j++) {
|
||||
for (j = i; j <= NUM_TESTS; j++) {
|
||||
ok1(shachain_get_hash(&chain, j, &hash));
|
||||
ok1(memcmp(&hash, &expect[j], sizeof(hash)) == 0);
|
||||
}
|
||||
ok1(!shachain_get_hash(&chain, i+1, &hash));
|
||||
if (chain.num_valid == 8) {
|
||||
printf("%zu: num_valid %u\n", i, chain.num_valid);
|
||||
for (j = 0; j < 8; j++)
|
||||
printf("chain.known[%zu] = 0x%02x\n",
|
||||
j, chain.known[j].index);
|
||||
}
|
||||
ok1(!shachain_get_hash(&chain, i-1, &hash));
|
||||
}
|
||||
|
||||
/* Now add seed. */
|
||||
ok1(shachain_add_hash(&chain, 0, &expect[0]));
|
||||
for (j = 0; j <= NUM_TESTS; j++) {
|
||||
struct sha256 hash;
|
||||
ok1(shachain_get_hash(&chain, j, &hash));
|
||||
ok1(memcmp(&hash, &expect[j], sizeof(hash)) == 0);
|
||||
}
|
||||
|
||||
return exit_status();
|
||||
|
@ -9,26 +9,27 @@ int main(void)
|
||||
{
|
||||
struct sha256 seed;
|
||||
struct shachain chain;
|
||||
size_t i;
|
||||
uint64_t i;
|
||||
|
||||
plan_tests(NUM_TESTS);
|
||||
|
||||
memset(&seed, 0xFF, sizeof(seed));
|
||||
shachain_init(&chain);
|
||||
|
||||
for (i = 0; i < NUM_TESTS; i++) {
|
||||
for (i = 0xFFFFFFFFFFFFFFFFULL;
|
||||
i > 0xFFFFFFFFFFFFFFFFULL - NUM_TESTS;
|
||||
i--) {
|
||||
struct sha256 expect;
|
||||
unsigned int num_known = chain.num_valid;
|
||||
|
||||
shachain_from_seed(&seed, i, &expect);
|
||||
/* Screw it up. */
|
||||
expect.u.u8[0]++;
|
||||
|
||||
/* Either it should fail, or it couldn't derive any others. */
|
||||
/* Either it should fail, or it couldn't derive any others (ie. pos 0). */
|
||||
if (shachain_add_hash(&chain, i, &expect)) {
|
||||
ok1(chain.num_valid == num_known + 1);
|
||||
ok1(chain.known[0].index == i);
|
||||
/* Fix it up in-place */
|
||||
chain.known[num_known].hash.u.u8[0]--;
|
||||
chain.known[0].hash.u.u8[0]--;
|
||||
} else {
|
||||
expect.u.u8[0]--;
|
||||
ok1(shachain_add_hash(&chain, i, &expect));
|
||||
|
41
ccan/ccan/crypto/shachain/test/run-can_derive.c
Normal file
41
ccan/ccan/crypto/shachain/test/run-can_derive.c
Normal file
@ -0,0 +1,41 @@
|
||||
#define shachain_index_t uint8_t
|
||||
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
/* Include the C files directly. */
|
||||
#include <ccan/crypto/shachain/shachain.c>
|
||||
#include <ccan/tap/tap.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static bool bit_set(shachain_index_t index, int bit)
|
||||
{
|
||||
return index & (1ULL << bit);
|
||||
}
|
||||
|
||||
/* As per design.txt */
|
||||
static bool naive_can_derive(shachain_index_t from, shachain_index_t to)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = count_trailing_zeroes(from); i < 8; i++) {
|
||||
if (bit_set(from, i) != bit_set(to, i))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* This is how many tests you plan to run */
|
||||
plan_tests(65536);
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
for (j = 0; j < 256; j++) {
|
||||
ok1(can_derive(i, j) == naive_can_derive(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
return exit_status();
|
||||
}
|
@ -10,32 +10,37 @@ int main(void)
|
||||
struct sha256 seed;
|
||||
struct shachain chain;
|
||||
struct sha256 expect[NUM_TESTS];
|
||||
size_t i, j;
|
||||
uint64_t i, j;
|
||||
|
||||
/* This is how many tests you plan to run */
|
||||
plan_tests(NUM_TESTS * 3 + NUM_TESTS * (NUM_TESTS + 1));
|
||||
plan_tests(NUM_TESTS * 3 + NUM_TESTS * (NUM_TESTS + 1) - 1);
|
||||
|
||||
memset(&seed, 0, sizeof(seed));
|
||||
/* Generate a whole heap. */
|
||||
for (i = 0; i < NUM_TESTS; i++) {
|
||||
shachain_from_seed(&seed, i, &expect[i]);
|
||||
if (i == 0)
|
||||
ok1(memcmp(&expect[i], &seed, sizeof(expect[i])));
|
||||
else
|
||||
ok1(memcmp(&expect[i], &expect[i-1], sizeof(expect[i])));
|
||||
for (i = 0xFFFFFFFFFFFFFFFFULL;
|
||||
i > 0xFFFFFFFFFFFFFFFFULL - NUM_TESTS;
|
||||
i--) {
|
||||
int expidx = 0xFFFFFFFFFFFFFFFFULL - i;
|
||||
shachain_from_seed(&seed, i, &expect[expidx]);
|
||||
if (i != 0xFFFFFFFFFFFFFFFFULL)
|
||||
ok1(memcmp(&expect[expidx], &expect[expidx-1],
|
||||
sizeof(expect[expidx])));
|
||||
}
|
||||
|
||||
shachain_init(&chain);
|
||||
|
||||
for (i = 0; i < NUM_TESTS; i++) {
|
||||
for (i = 0xFFFFFFFFFFFFFFFFULL;
|
||||
i > 0xFFFFFFFFFFFFFFFFULL - NUM_TESTS;
|
||||
i--) {
|
||||
struct sha256 hash;
|
||||
|
||||
ok1(shachain_add_hash(&chain, i, &expect[i]));
|
||||
for (j = 0; j <= i; j++) {
|
||||
int expidx = 0xFFFFFFFFFFFFFFFFULL - i;
|
||||
ok1(shachain_add_hash(&chain, i, &expect[expidx]));
|
||||
for (j = i; j != 0; j++) {
|
||||
ok1(shachain_get_hash(&chain, j, &hash));
|
||||
ok1(memcmp(&hash, &expect[j], sizeof(hash)) == 0);
|
||||
expidx = 0xFFFFFFFFFFFFFFFFULL - j;
|
||||
ok1(memcmp(&hash, &expect[expidx], sizeof(hash)) == 0);
|
||||
}
|
||||
ok1(!shachain_get_hash(&chain, i+1, &hash));
|
||||
ok1(!shachain_get_hash(&chain, i-1, &hash));
|
||||
}
|
||||
|
||||
return exit_status();
|
||||
|
@ -2,6 +2,7 @@
|
||||
#ifndef CCAN_HTABLE_TYPE_H
|
||||
#define CCAN_HTABLE_TYPE_H
|
||||
#include <ccan/htable/htable.h>
|
||||
#include <ccan/compiler/compiler.h>
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
@ -30,9 +31,15 @@
|
||||
* bool <name>_del(struct <name> *ht, const <type> *e);
|
||||
* bool <name>_delkey(struct <name> *ht, const <keytype> *k);
|
||||
*
|
||||
* Find function return the matching element, or NULL:
|
||||
* Find and return the (first) matching element, or NULL:
|
||||
* type *<name>_get(const struct @name *ht, const <keytype> *k);
|
||||
*
|
||||
* Find and return all matching elements, or NULL:
|
||||
* type *<name>_getfirst(const struct @name *ht, const <keytype> *k,
|
||||
* struct <name>_iter *i);
|
||||
* type *<name>_getnext(const struct @name *ht, const <keytype> *k,
|
||||
* struct <name>_iter *i);
|
||||
*
|
||||
* Iteration over hashtable is also supported:
|
||||
* type *<name>_first(const struct <name> *ht, struct <name>_iter *i);
|
||||
* type *<name>_next(const struct <name> *ht, struct <name>_iter *i);
|
||||
@ -50,15 +57,16 @@
|
||||
{ \
|
||||
return hashfn(keyof((const type *)elem)); \
|
||||
} \
|
||||
static inline void name##_init(struct name *ht) \
|
||||
static inline UNNEEDED void name##_init(struct name *ht) \
|
||||
{ \
|
||||
htable_init(&ht->raw, name##_hash, NULL); \
|
||||
} \
|
||||
static inline void name##_init_sized(struct name *ht, size_t s) \
|
||||
static inline UNNEEDED void name##_init_sized(struct name *ht, \
|
||||
size_t s) \
|
||||
{ \
|
||||
htable_init_sized(&ht->raw, name##_hash, NULL, s); \
|
||||
} \
|
||||
static inline void name##_clear(struct name *ht) \
|
||||
static inline UNNEEDED void name##_clear(struct name *ht) \
|
||||
{ \
|
||||
htable_clear(&ht->raw); \
|
||||
} \
|
||||
@ -66,11 +74,12 @@
|
||||
{ \
|
||||
return htable_add(&ht->raw, hashfn(keyof(elem)), elem); \
|
||||
} \
|
||||
static inline bool name##_del(struct name *ht, const type *elem) \
|
||||
static inline UNNEEDED bool name##_del(struct name *ht, \
|
||||
const type *elem) \
|
||||
{ \
|
||||
return htable_del(&ht->raw, hashfn(keyof(elem)), elem); \
|
||||
} \
|
||||
static inline type *name##_get(const struct name *ht, \
|
||||
static inline UNNEEDED type *name##_get(const struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof) k) \
|
||||
{ \
|
||||
/* Typecheck for eqfn */ \
|
||||
@ -81,7 +90,36 @@
|
||||
(bool (*)(const void *, void *))(eqfn), \
|
||||
k); \
|
||||
} \
|
||||
static inline bool name##_delkey(struct name *ht, \
|
||||
static inline UNNEEDED type *name##_getmatch_(const struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof) k, \
|
||||
size_t h, \
|
||||
type *v, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
while (v) { \
|
||||
if (eqfn(v, k)) \
|
||||
break; \
|
||||
v = htable_nextval(&ht->raw, &iter->i, h); \
|
||||
} \
|
||||
return v; \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_getfirst(const struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof) k, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
size_t h = hashfn(k); \
|
||||
type *v = htable_firstval(&ht->raw, &iter->i, h); \
|
||||
return name##_getmatch_(ht, k, h, v, iter); \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_getnext(const struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof) k, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
size_t h = hashfn(k); \
|
||||
type *v = htable_nextval(&ht->raw, &iter->i, h); \
|
||||
return name##_getmatch_(ht, k, h, v, iter); \
|
||||
} \
|
||||
static inline UNNEEDED bool name##_delkey(struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof) k) \
|
||||
{ \
|
||||
type *elem = name##_get(ht, k); \
|
||||
@ -89,12 +127,12 @@
|
||||
return name##_del(ht, elem); \
|
||||
return false; \
|
||||
} \
|
||||
static inline type *name##_first(const struct name *ht, \
|
||||
static inline UNNEEDED type *name##_first(const struct name *ht, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
return htable_first(&ht->raw, &iter->i); \
|
||||
} \
|
||||
static inline type *name##_next(const struct name *ht, \
|
||||
static inline UNNEEDED type *name##_next(const struct name *ht, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
return htable_next(&ht->raw, &iter->i); \
|
||||
|
@ -111,12 +111,12 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned int i;
|
||||
struct htable_obj ht;
|
||||
struct obj val[NUM_VALS];
|
||||
struct obj val[NUM_VALS], *result;
|
||||
unsigned int dne;
|
||||
void *p;
|
||||
struct htable_obj_iter iter;
|
||||
|
||||
plan_tests(20);
|
||||
plan_tests(26);
|
||||
for (i = 0; i < NUM_VALS; i++)
|
||||
val[i].key = i;
|
||||
dne = i;
|
||||
@ -169,7 +169,33 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* Delete them all by key. */
|
||||
del_vals_bykey(&ht, val, NUM_VALS);
|
||||
htable_obj_clear(&ht);
|
||||
|
||||
/* Write two of the same value. */
|
||||
val[1] = val[0];
|
||||
htable_obj_add(&ht, &val[0]);
|
||||
htable_obj_add(&ht, &val[1]);
|
||||
i = 0;
|
||||
|
||||
result = htable_obj_getfirst(&ht, &i, &iter);
|
||||
ok1(result == &val[0] || result == &val[1]);
|
||||
if (result == &val[0]) {
|
||||
ok1(htable_obj_getnext(&ht, &i, &iter) == &val[1]);
|
||||
ok1(htable_obj_getnext(&ht, &i, &iter) == NULL);
|
||||
|
||||
/* Deleting first should make us iterate over the other. */
|
||||
ok1(htable_obj_del(&ht, &val[0]));
|
||||
ok1(htable_obj_getfirst(&ht, &i, &iter) == &val[1]);
|
||||
ok1(htable_obj_getnext(&ht, &i, &iter) == NULL);
|
||||
} else {
|
||||
ok1(htable_obj_getnext(&ht, &i, &iter) == &val[0]);
|
||||
ok1(htable_obj_getnext(&ht, &i, &iter) == NULL);
|
||||
|
||||
/* Deleting first should make us iterate over the other. */
|
||||
ok1(htable_obj_del(&ht, &val[1]));
|
||||
ok1(htable_obj_getfirst(&ht, &i, &iter) == &val[0]);
|
||||
ok1(htable_obj_getnext(&ht, &i, &iter) == NULL);
|
||||
}
|
||||
|
||||
htable_obj_clear(&ht);
|
||||
return exit_status();
|
||||
}
|
||||
|
@ -107,3 +107,22 @@ bool memeqzero(const void *data, size_t length)
|
||||
/* Now we know that's zero, memcmp with self. */
|
||||
return memcmp(data, p, length) == 0;
|
||||
}
|
||||
|
||||
void memtaint(void *data, size_t len)
|
||||
{
|
||||
/* Using 16 bytes is a bit quicker than 4 */
|
||||
const unsigned tainter[]
|
||||
= { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
|
||||
char *p = data;
|
||||
|
||||
while (len >= sizeof(tainter)) {
|
||||
memcpy(p, tainter, sizeof(tainter));
|
||||
p += sizeof(tainter);
|
||||
len -= sizeof(tainter);
|
||||
}
|
||||
memcpy(p, tainter, len);
|
||||
|
||||
#if HAVE_VALGRIND_MEMCHECK_H
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(data, len);
|
||||
#endif
|
||||
}
|
||||
|
@ -275,4 +275,20 @@ static inline void *memcheck_(const void *data, size_t len)
|
||||
#else
|
||||
#define memcheck(data, len) memcheck_((data), (len))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* memtaint - mark a memory region unused
|
||||
* @data: start of region
|
||||
* @len: length in bytes
|
||||
*
|
||||
* This writes an "0xdeadbeef" eyecatcher repeatedly to the memory.
|
||||
* When running under valgrind, it also tells valgrind that the memory is
|
||||
* uninitialized, triggering valgrind errors if it is used for branches
|
||||
* or written out (or passed to memcheck!) in future.
|
||||
*
|
||||
* Example:
|
||||
* // We'll reuse this buffer later, but be sure we don't access it.
|
||||
* memtaint(somebytes, bytes_len);
|
||||
*/
|
||||
void memtaint(void *data, size_t len);
|
||||
#endif /* CCAN_MEM_H */
|
||||
|
@ -29,7 +29,7 @@
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* size_t i;
|
||||
* struct { STRMAP_MEMBERS(size_t); } map;
|
||||
* STRMAP(size_t) map;
|
||||
*
|
||||
* strmap_init(&map);
|
||||
* for (i = 1; i < argc; i++)
|
||||
|
@ -21,7 +21,7 @@ struct strmap {
|
||||
};
|
||||
|
||||
/**
|
||||
* STRMAP_MEMBERS - declare members for a type-specific strmap.
|
||||
* STRMAP - declare a type-specific strmap
|
||||
* @type: type for this map's values, or void * for any pointer.
|
||||
*
|
||||
* You use this to create your own typed strmap for a particular type.
|
||||
@ -29,14 +29,11 @@ struct strmap {
|
||||
* value!
|
||||
*
|
||||
* Example:
|
||||
* struct strmap_intp {
|
||||
* STRMAP_MEMBERS(int *);
|
||||
* };
|
||||
* STRMAP(int *) int_strmap;
|
||||
* strmap_init(&int_strmap);
|
||||
*/
|
||||
#define STRMAP_MEMBERS(type) \
|
||||
struct strmap raw; \
|
||||
TCON(type canary)
|
||||
|
||||
#define STRMAP(type) \
|
||||
TCON_WRAP(struct strmap, type canary)
|
||||
|
||||
/**
|
||||
* strmap_init - initialize a string map (empty)
|
||||
@ -46,11 +43,11 @@ struct strmap {
|
||||
* need this.
|
||||
*
|
||||
* Example:
|
||||
* struct strmap_intp map;
|
||||
* STRMAP(int *) map;
|
||||
*
|
||||
* strmap_init(&map);
|
||||
*/
|
||||
#define strmap_init(map) strmap_init_(&(map)->raw)
|
||||
#define strmap_init(map) strmap_init_(tcon_unwrap(map))
|
||||
|
||||
static inline void strmap_init_(struct strmap *map)
|
||||
{
|
||||
@ -65,7 +62,7 @@ static inline void strmap_init_(struct strmap *map)
|
||||
* if (!strmap_empty(&map))
|
||||
* abort();
|
||||
*/
|
||||
#define strmap_empty(map) strmap_empty_(&(map)->raw)
|
||||
#define strmap_empty(map) strmap_empty_(tcon_unwrap(map))
|
||||
|
||||
static inline bool strmap_empty_(const struct strmap *map)
|
||||
{
|
||||
@ -85,7 +82,7 @@ static inline bool strmap_empty_(const struct strmap *map)
|
||||
* printf("hello => %i\n", *val);
|
||||
*/
|
||||
#define strmap_get(map, member) \
|
||||
tcon_cast((map), canary, strmap_get_(&(map)->raw, (member)))
|
||||
tcon_cast((map), canary, strmap_get_(tcon_unwrap(map), (member)))
|
||||
void *strmap_get_(const struct strmap *map, const char *member);
|
||||
|
||||
/**
|
||||
@ -106,8 +103,8 @@ void *strmap_get_(const struct strmap *map, const char *member);
|
||||
* if (!strmap_add(&map, "goodbye", val))
|
||||
* printf("goodbye was already in the map\n");
|
||||
*/
|
||||
#define strmap_add(map, member, value) \
|
||||
strmap_add_(&tcon_check((map), canary, (value))->raw, \
|
||||
#define strmap_add(map, member, value) \
|
||||
strmap_add_(tcon_unwrap(tcon_check((map), canary, (value))), \
|
||||
(member), (void *)(value))
|
||||
|
||||
bool strmap_add_(struct strmap *map, const char *member, const void *value);
|
||||
@ -130,7 +127,7 @@ bool strmap_add_(struct strmap *map, const char *member, const void *value);
|
||||
* printf("goodbye was not in the map?\n");
|
||||
*/
|
||||
#define strmap_del(map, member, valuep) \
|
||||
strmap_del_(&tcon_check_ptr((map), canary, valuep)->raw, \
|
||||
strmap_del_(tcon_unwrap(tcon_check_ptr((map), canary, valuep)), \
|
||||
(member), (void **)valuep)
|
||||
char *strmap_del_(struct strmap *map, const char *member, void **valuep);
|
||||
|
||||
@ -143,7 +140,7 @@ char *strmap_del_(struct strmap *map, const char *member, void **valuep);
|
||||
* Example:
|
||||
* strmap_clear(&map);
|
||||
*/
|
||||
#define strmap_clear(map) strmap_clear_(&(map)->raw)
|
||||
#define strmap_clear(map) strmap_clear_(tcon_unwrap(map))
|
||||
|
||||
void strmap_clear_(struct strmap *map);
|
||||
|
||||
@ -160,9 +157,7 @@ void strmap_clear_(struct strmap *map);
|
||||
* You should not alter the map within the @handle function!
|
||||
*
|
||||
* Example:
|
||||
* struct strmap_intp {
|
||||
* STRMAP_MEMBERS(int *);
|
||||
* };
|
||||
* typedef STRMAP(int *) strmap_intp;
|
||||
* static bool dump_some(const char *member, int *value, int *num)
|
||||
* {
|
||||
* // Only dump out num nodes.
|
||||
@ -172,7 +167,7 @@ void strmap_clear_(struct strmap *map);
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* static void dump_map(const struct strmap_intp *map)
|
||||
* static void dump_map(const strmap_intp *map)
|
||||
* {
|
||||
* int max = 100;
|
||||
* strmap_iterate(map, dump_some, &max);
|
||||
@ -181,7 +176,7 @@ void strmap_clear_(struct strmap *map);
|
||||
* }
|
||||
*/
|
||||
#define strmap_iterate(map, handle, arg) \
|
||||
strmap_iterate_(&(map)->raw, \
|
||||
strmap_iterate_(tcon_unwrap(map), \
|
||||
typesafe_cb_cast(bool (*)(const char *, \
|
||||
void *, void *), \
|
||||
bool (*)(const char *, \
|
||||
@ -202,7 +197,7 @@ void strmap_iterate_(const struct strmap *map,
|
||||
* strmap_empty() on the returned pointer.
|
||||
*
|
||||
* Example:
|
||||
* static void dump_prefix(const struct strmap_intp *map,
|
||||
* static void dump_prefix(const strmap_intp *map,
|
||||
* const char *prefix)
|
||||
* {
|
||||
* int max = 100;
|
||||
@ -214,10 +209,10 @@ void strmap_iterate_(const struct strmap *map,
|
||||
*/
|
||||
#if HAVE_TYPEOF
|
||||
#define strmap_prefix(map, prefix) \
|
||||
((const __typeof__(map))strmap_prefix_(&(map)->raw, (prefix)))
|
||||
((const __typeof__(map))strmap_prefix_(tcon_unwrap(map), (prefix)))
|
||||
#else
|
||||
#define strmap_prefix(map, prefix) \
|
||||
((const void *)strmap_prefix_(&(map)->raw, (prefix)))
|
||||
((const void *)strmap_prefix_(tcon_unwrap(map), (prefix)))
|
||||
#endif
|
||||
|
||||
const struct strmap *strmap_prefix_(const struct strmap *map,
|
||||
|
@ -14,9 +14,7 @@ static bool find_string(const char *str, char *member, const char *cmp)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct strmap_charp {
|
||||
STRMAP_MEMBERS(char *);
|
||||
} map;
|
||||
STRMAP(char *) map;
|
||||
|
||||
plan_tests(3);
|
||||
|
||||
|
@ -33,9 +33,7 @@ static bool dump(const char *member, char *value, bool *ok)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct strmap_charp {
|
||||
STRMAP_MEMBERS(char *);
|
||||
} map;
|
||||
STRMAP(char *) map;
|
||||
unsigned int i;
|
||||
char *str[NUM];
|
||||
bool dump_ok;
|
||||
|
@ -24,11 +24,9 @@ static bool find_empty(const char *index, char *value, char *empty)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct map {
|
||||
STRMAP_MEMBERS(char *);
|
||||
};
|
||||
struct map map;
|
||||
const struct map *sub;
|
||||
typedef STRMAP(char *) map_t;
|
||||
map_t map;
|
||||
const map_t *sub;
|
||||
unsigned int i;
|
||||
char *str[NUM], *empty;
|
||||
|
||||
@ -56,9 +54,9 @@ int main(void)
|
||||
|
||||
/* Everything */
|
||||
sub = strmap_prefix(&map, "0");
|
||||
ok1(sub->raw.u.n == map.raw.u.n);
|
||||
ok1(tcon_unwrap(sub)->u.n == tcon_unwrap(&map)->u.n);
|
||||
sub = strmap_prefix(&map, "");
|
||||
ok1(sub->raw.u.n == map.raw.u.n);
|
||||
ok1(tcon_unwrap(sub)->u.n == tcon_unwrap(&map)->u.n);
|
||||
|
||||
/* Single. */
|
||||
sub = strmap_prefix(&map, "00000000");
|
||||
|
@ -4,9 +4,7 @@
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct strmap_charp {
|
||||
STRMAP_MEMBERS(char *);
|
||||
} map;
|
||||
STRMAP(char *) map;
|
||||
const char str[] = "hello";
|
||||
const char val[] = "there";
|
||||
const char none[] = "";
|
||||
|
@ -66,4 +66,6 @@
|
||||
#define HAVE_WARN_UNUSED_RESULT 1
|
||||
#define HAVE_OPENMP 1
|
||||
#define HAVE_VALGRIND_MEMCHECK_H 1
|
||||
#define HAVE_UCONTEXT 1
|
||||
#define HAVE_POINTER_SAFE_MAKECONTEXT 1
|
||||
#endif /* CCAN_CONFIG_H */
|
||||
|
@ -319,6 +319,52 @@ static struct test tests[] = {
|
||||
"-Werror -fopenmp" },
|
||||
{ "HAVE_VALGRIND_MEMCHECK_H", OUTSIDE_MAIN, NULL, NULL,
|
||||
"#include <valgrind/memcheck.h>\n" },
|
||||
{ "HAVE_UCONTEXT", DEFINES_EVERYTHING|EXECUTE,
|
||||
NULL, NULL,
|
||||
"#include <ucontext.h>\n"
|
||||
"static int x = 0;\n"
|
||||
"static char stack[2048];\n"
|
||||
"static ucontext_t a, b;\n"
|
||||
"static void fn(void) {\n"
|
||||
" x |= 2;\n"
|
||||
" setcontext(&b);\n"
|
||||
" x |= 4;\n"
|
||||
"}\n"
|
||||
"int main(int argc, char *argv[]) {\n"
|
||||
" x |= 1;\n"
|
||||
" getcontext(&a);\n"
|
||||
" a.uc_stack.ss_sp = stack;\n"
|
||||
" a.uc_stack.ss_size = sizeof(stack);\n"
|
||||
" makecontext(&a, fn, 0);\n"
|
||||
" swapcontext(&b, &a);\n"
|
||||
" return (x == 3) ? 0 : 1;\n"
|
||||
"}\n"
|
||||
},
|
||||
{ "HAVE_POINTER_SAFE_MAKECONTEXT", DEFINES_EVERYTHING|EXECUTE,
|
||||
"HAVE_UCONTEXT", NULL,
|
||||
"#include <stddef.h>\n"
|
||||
"#include <ucontext.h>\n"
|
||||
"static int worked = 0;\n"
|
||||
"static char stack[1024];\n"
|
||||
"static ucontext_t a, b;\n"
|
||||
"static void fn(void *p, void *q) {\n"
|
||||
" void *cp = &worked;\n"
|
||||
" void *cq = (void *)(~((ptrdiff_t)cp));\n"
|
||||
" if ((p == cp) && (q == cq))\n"
|
||||
" worked = 1;\n"
|
||||
" setcontext(&b);\n"
|
||||
"}\n"
|
||||
"int main(int argc, char *argv[]) {\n"
|
||||
" void *ap = &worked;\n"
|
||||
" void *aq = (void *)(~((ptrdiff_t)ap));\n"
|
||||
" getcontext(&a);\n"
|
||||
" a.uc_stack.ss_sp = stack;\n"
|
||||
" a.uc_stack.ss_size = sizeof(stack);\n"
|
||||
" makecontext(&a, (void (*)(void))fn, 2, ap, aq);\n"
|
||||
" swapcontext(&b, &a);\n"
|
||||
" return worked ? 0 : 1;\n"
|
||||
"}\n"
|
||||
},
|
||||
};
|
||||
|
||||
static char *grab_fd(int fd)
|
||||
@ -497,7 +543,8 @@ static bool run_test(const char *cmd, struct test *test)
|
||||
fclose(outf);
|
||||
|
||||
if (verbose > 1)
|
||||
if (system("cat " INPUT_FILE) == -1);
|
||||
if (system("cat " INPUT_FILE) == -1)
|
||||
;
|
||||
|
||||
newcmd = strdup(cmd);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user