mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
d5cb0d85b5
We force use of tal_wally_start/tal_wally_end around every wally allocation, and with "end" make the caller choose where to reparent everything. This is particularly powerful where we allocate a tx or a psbt: we want that tx or psbt to be the parent of the other allocations, so this way we can reparent the tx or psbt, then reparent everything else onto it. Implementing psbt_finalize (which uses a behavior flag antipattern) was tricky, so I ended up splitting that into 'psbt_finalize' and 'psbt_final_tx', which I think also makes the callers clearer. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
176 lines
3.9 KiB
C
176 lines
3.9 KiB
C
#include "utils.h"
|
|
#include <bitcoin/chainparams.h>
|
|
#include <ccan/list/list.h>
|
|
#include <ccan/str/hex/hex.h>
|
|
#include <ccan/tal/str/str.h>
|
|
#include <locale.h>
|
|
|
|
const tal_t *wally_tal_ctx;
|
|
secp256k1_context *secp256k1_ctx;
|
|
const tal_t *tmpctx;
|
|
|
|
const struct chainparams *chainparams;
|
|
|
|
bool is_elements(const struct chainparams *chainparams)
|
|
{
|
|
return chainparams->is_elements;
|
|
}
|
|
|
|
void tal_wally_start(void)
|
|
{
|
|
if (wally_tal_ctx) {
|
|
/* This makes valgrind show us backtraces! */
|
|
*(u8 *)wally_tal_ctx = '\0';
|
|
abort();
|
|
}
|
|
|
|
wally_tal_ctx = tal_arr(NULL, char, 0);
|
|
}
|
|
|
|
void tal_wally_end(const tal_t *parent)
|
|
{
|
|
tal_t *p;
|
|
while ((p = tal_first(wally_tal_ctx)) != NULL) {
|
|
if (p != parent)
|
|
tal_steal(parent, p);
|
|
}
|
|
wally_tal_ctx = tal_free(wally_tal_ctx);
|
|
}
|
|
|
|
#if DEVELOPER
|
|
/* If you've got a softref, we assume no reallocs. */
|
|
static void dont_move_softref(tal_t *ctx, enum tal_notify_type ntype, void *info)
|
|
{
|
|
abort();
|
|
}
|
|
#endif
|
|
|
|
static void softref_nullify(tal_t *obj, void **ptr)
|
|
{
|
|
*ptr = NULL;
|
|
#if DEVELOPER
|
|
tal_del_notifier(obj, dont_move_softref);
|
|
#endif
|
|
}
|
|
|
|
static void softref_cleanup(const tal_t *outer, void **ptr)
|
|
{
|
|
if (*ptr) {
|
|
tal_del_destructor2(*ptr, softref_nullify, ptr);
|
|
}
|
|
#if DEVELOPER
|
|
tal_del_notifier(outer, dont_move_softref);
|
|
#endif
|
|
}
|
|
|
|
void set_softref_(const tal_t *outer, size_t outersize, void **ptr, tal_t *obj)
|
|
{
|
|
/* pointer is inside outer, right? */
|
|
assert((char *)ptr >= (char *)outer);
|
|
assert((char *)ptr < (char *)outer + outersize);
|
|
|
|
/* This is harmless if there was no prior, otherwise constrains the
|
|
* leak: we don't have enough information in softref_nullify to
|
|
* clear softref_cleanup */
|
|
tal_del_destructor2(outer, softref_cleanup, ptr);
|
|
|
|
if (obj) {
|
|
tal_add_destructor2(outer, softref_cleanup, ptr);
|
|
tal_add_destructor2(obj, softref_nullify, ptr);
|
|
#if DEVELOPER
|
|
tal_add_notifier(obj, TAL_NOTIFY_MOVE, dont_move_softref);
|
|
#endif
|
|
}
|
|
|
|
#if DEVELOPER
|
|
tal_add_notifier(outer, TAL_NOTIFY_MOVE, dont_move_softref);
|
|
#endif
|
|
|
|
*ptr = obj;
|
|
}
|
|
|
|
void clear_softref_(const tal_t *outer, size_t outersize, void **ptr)
|
|
{
|
|
assert((char *)ptr >= (char *)outer);
|
|
assert((char *)ptr < (char *)outer + outersize);
|
|
|
|
if (*ptr) {
|
|
tal_del_destructor2(outer, softref_cleanup, ptr);
|
|
tal_del_destructor2(*ptr, softref_nullify, ptr);
|
|
#if DEVELOPER
|
|
tal_del_notifier(*ptr, dont_move_softref);
|
|
#endif
|
|
}
|
|
|
|
#if DEVELOPER
|
|
tal_del_notifier(outer, dont_move_softref);
|
|
#endif
|
|
|
|
*ptr = NULL;
|
|
}
|
|
|
|
char *tal_hexstr(const tal_t *ctx, const void *data, size_t len)
|
|
{
|
|
char *str = tal_arr(ctx, char, hex_str_size(len));
|
|
hex_encode(data, len, str, hex_str_size(len));
|
|
return str;
|
|
}
|
|
|
|
char *tal_hex(const tal_t *ctx, const tal_t *data)
|
|
{
|
|
return tal_hexstr(ctx, data, tal_bytelen(data));
|
|
}
|
|
|
|
u8 *tal_hexdata(const tal_t *ctx, const void *str, size_t len)
|
|
{
|
|
u8 *data = tal_arr(ctx, u8, hex_data_size(len));
|
|
if (!hex_decode(str, len, data, hex_data_size(len)))
|
|
return NULL;
|
|
return data;
|
|
}
|
|
|
|
/* Use the POSIX C locale. */
|
|
void setup_locale(void)
|
|
{
|
|
setlocale(LC_ALL, "C");
|
|
putenv("LC_ALL=C"); /* For exec{l,lp,v,vp}(...) */
|
|
}
|
|
|
|
/* Initial creation of tmpctx. */
|
|
void setup_tmpctx(void)
|
|
{
|
|
tmpctx = tal_arr_label(NULL, char, 0, "tmpctx");
|
|
}
|
|
|
|
/* Free any children of tmpctx. */
|
|
void clean_tmpctx(void)
|
|
{
|
|
const tal_t *p;
|
|
|
|
/* Don't actually free tmpctx: we hand pointers to it around. */
|
|
while ((p = tal_first(tmpctx)) != NULL)
|
|
tal_free(p);
|
|
}
|
|
|
|
void tal_arr_remove_(void *p, size_t elemsize, size_t n)
|
|
{
|
|
// p is a pointer-to-pointer for tal_resize.
|
|
char *objp = *(char **)p;
|
|
size_t len = tal_bytelen(objp);
|
|
assert(len % elemsize == 0);
|
|
assert((n + 1) * elemsize <= len);
|
|
memmove(objp + elemsize * n, objp + elemsize * (n+1),
|
|
len - (elemsize * (n+1)));
|
|
tal_resize((char **)p, len - elemsize);
|
|
}
|
|
|
|
void *tal_dup_talarr_(const tal_t *ctx, const tal_t *src TAKES, const char *label)
|
|
{
|
|
if (!src) {
|
|
/* Correctly handle TAKES on a NULL `src`. */
|
|
(void) taken(src);
|
|
return NULL;
|
|
}
|
|
return tal_dup_(ctx, src, 1, tal_bytelen(src), 0, label);
|
|
}
|