Skip to content

Commit 02483b2

Browse files
committed
common/gossmap: use u64 for all offsets.
Since we don't compact the gossmap on the fly (FIXME!) we can easily surpass 4GB in the gossmap, and 32 bit offsets are not sufficient. I'm a bit surprised we don't crash immediately, but we've definitely seen issues. Changelog-Fixed: gossipd: crash errors with large gossip_store (>4MB) growth on longer-running nodes. Signed-off-by: Rusty Russell <[email protected]>
1 parent 8aa76a5 commit 02483b2

File tree

4 files changed

+65
-64
lines changed

4 files changed

+65
-64
lines changed

common/gossmap.c

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <errno.h>
1414
#include <fcntl.h>
1515
#include <gossipd/gossip_store_wiregen.h>
16+
#include <inttypes.h>
1617
#include <sys/mman.h>
1718
#include <unistd.h>
1819
#include <wire/peer_wire.h>
@@ -60,7 +61,7 @@ struct gossmap {
6061
/* The memory map of the file: u8 for arithmetic portability */
6162
u8 *mmap;
6263
/* map_end is where we read to so far, map_size is total size */
63-
size_t map_end, map_size;
64+
u64 map_end, map_size;
6465

6566
/* Map of node id -> node */
6667
struct nodeidx_htable *nodes;
@@ -93,18 +94,18 @@ struct gossmap {
9394
void *cb_arg);
9495
bool (*unknown_record)(struct gossmap *map,
9596
int type,
96-
size_t off,
97+
u64 off,
9798
size_t msglen,
9899
void *cb_arg);
99100
void *cb_arg;
100101
};
101102

102103
/* Accessors for the gossmap */
103-
static void map_copy(const struct gossmap *map, size_t offset,
104+
static void map_copy(const struct gossmap *map, u64 offset,
104105
void *dst, size_t len)
105106
{
106107
if (offset >= map->map_size) {
107-
size_t localoff = offset - map->map_size;
108+
u64 localoff = offset - map->map_size;
108109
assert(localoff + len <= tal_bytelen(map->local));
109110
memcpy(dst, map->local + localoff, len);
110111
} else {
@@ -119,35 +120,35 @@ static void map_copy(const struct gossmap *map, size_t offset,
119120
}
120121
}
121122

122-
static u8 map_u8(const struct gossmap *map, size_t offset)
123+
static u8 map_u8(const struct gossmap *map, u64 offset)
123124
{
124125
u8 u8;
125126
map_copy(map, offset, &u8, sizeof(u8));
126127
return u8;
127128
}
128129

129-
static u16 map_be16(const struct gossmap *map, size_t offset)
130+
static u16 map_be16(const struct gossmap *map, u64 offset)
130131
{
131132
be16 be16;
132133
map_copy(map, offset, &be16, sizeof(be16));
133134
return be16_to_cpu(be16);
134135
}
135136

136-
static u32 map_be32(const struct gossmap *map, size_t offset)
137+
static u32 map_be32(const struct gossmap *map, u64 offset)
137138
{
138139
be32 be32;
139140
map_copy(map, offset, &be32, sizeof(be32));
140141
return be32_to_cpu(be32);
141142
}
142143

143-
static u64 map_be64(const struct gossmap *map, size_t offset)
144+
static u64 map_be64(const struct gossmap *map, u64 offset)
144145
{
145146
be64 be64;
146147
map_copy(map, offset, &be64, sizeof(be64));
147148
return be64_to_cpu(be64);
148149
}
149150

150-
static void map_nodeid(const struct gossmap *map, size_t offset,
151+
static void map_nodeid(const struct gossmap *map, u64 offset,
151152
struct node_id *id)
152153
{
153154
map_copy(map, offset, id, sizeof(*id));
@@ -156,7 +157,7 @@ static void map_nodeid(const struct gossmap *map, size_t offset,
156157
/* Returns optional or compulsory feature if set, otherwise -1 */
157158
static int map_feature_test(const struct gossmap *map,
158159
int compulsory_bit,
159-
size_t offset, size_t len)
160+
u64 offset, size_t len)
160161
{
161162
size_t bytenum = compulsory_bit / 8;
162163
u8 bits;
@@ -373,8 +374,8 @@ static struct gossmap_chan *next_free_chan(struct gossmap *map)
373374
}
374375

375376
static struct gossmap_chan *new_channel(struct gossmap *map,
376-
u32 cannounce_off,
377-
u32 plus_scid_off,
377+
u64 cannounce_off,
378+
u64 plus_scid_off,
378379
u32 n1idx, u32 n2idx)
379380
{
380381
struct gossmap_chan *chan = next_free_chan(map);
@@ -444,13 +445,13 @@ void gossmap_remove_node(struct gossmap *map, struct gossmap_node *node)
444445
* * [`point`:`node_id_2`]
445446
*/
446447
static struct gossmap_chan *add_channel(struct gossmap *map,
447-
size_t cannounce_off,
448+
u64 cannounce_off,
448449
size_t msglen)
449450
{
450451
/* Note that first two bytes are message type */
451-
const size_t feature_len_off = 2 + (64 + 64 + 64 + 64);
452+
const u64 feature_len_off = 2 + (64 + 64 + 64 + 64);
452453
size_t feature_len;
453-
size_t plus_scid_off;
454+
u64 plus_scid_off;
454455
struct short_channel_id scid;
455456
struct node_id node_id[2];
456457
struct gossmap_node *n[2];
@@ -468,7 +469,7 @@ static struct gossmap_chan *add_channel(struct gossmap *map,
468469
chan = gossmap_find_chan(map, &scid);
469470
if (chan) {
470471
/* FIXME: Report this better! */
471-
warnx("gossmap: redundant channel_announce for %s, offsets %u and %zu!",
472+
warnx("gossmap: redundant channel_announce for %s, offsets %"PRIu64" and %"PRIu64"!",
472473
fmt_short_channel_id(tmpctx, scid),
473474
chan->cann_off, cannounce_off);
474475
return NULL;
@@ -522,17 +523,17 @@ static struct gossmap_chan *add_channel(struct gossmap *map,
522523
* * [`u32`:`fee_proportional_millionths`]
523524
* * [`u64`:`htlc_maximum_msat`]
524525
*/
525-
static void update_channel(struct gossmap *map, size_t cupdate_off)
526+
static void update_channel(struct gossmap *map, u64 cupdate_off)
526527
{
527528
/* Note that first two bytes are message type */
528-
const size_t scid_off = cupdate_off + 2 + (64 + 32);
529-
const size_t message_flags_off = scid_off + 8 + 4;
530-
const size_t channel_flags_off = message_flags_off + 1;
531-
const size_t cltv_expiry_delta_off = channel_flags_off + 1;
532-
const size_t htlc_minimum_off = cltv_expiry_delta_off + 2;
533-
const size_t fee_base_off = htlc_minimum_off + 8;
534-
const size_t fee_prop_off = fee_base_off + 4;
535-
const size_t htlc_maximum_off = fee_prop_off + 4;
529+
const u64 scid_off = cupdate_off + 2 + (64 + 32);
530+
const u64 message_flags_off = scid_off + 8 + 4;
531+
const u64 channel_flags_off = message_flags_off + 1;
532+
const u64 cltv_expiry_delta_off = channel_flags_off + 1;
533+
const u64 htlc_minimum_off = cltv_expiry_delta_off + 2;
534+
const u64 fee_base_off = htlc_minimum_off + 8;
535+
const u64 fee_prop_off = fee_base_off + 4;
536+
const u64 htlc_maximum_off = fee_prop_off + 4;
536537
struct short_channel_id_dir scidd;
537538
struct gossmap_chan *chan;
538539
struct half_chan hc;
@@ -578,7 +579,7 @@ static void update_channel(struct gossmap *map, size_t cupdate_off)
578579
chan->cupdate_off[chanflags & 1] = cupdate_off;
579580
}
580581

581-
static void remove_channel_by_deletemsg(struct gossmap *map, size_t del_off)
582+
static void remove_channel_by_deletemsg(struct gossmap *map, u64 del_off)
582583
{
583584
struct short_channel_id scid;
584585
struct gossmap_chan *chan;
@@ -616,9 +617,9 @@ struct short_channel_id gossmap_chan_scid(const struct gossmap *map,
616617
* * [`u16`:`addrlen`]
617618
* * [`addrlen*byte`:`addresses`]
618619
*/
619-
static void node_announcement(struct gossmap *map, size_t nann_off)
620+
static void node_announcement(struct gossmap *map, u64 nann_off)
620621
{
621-
const size_t feature_len_off = 2 + 64;
622+
const u64 feature_len_off = 2 + 64;
622623
size_t feature_len;
623624
struct gossmap_node *n;
624625
struct node_id id;
@@ -629,7 +630,7 @@ static void node_announcement(struct gossmap *map, size_t nann_off)
629630
n->nann_off = nann_off;
630631
}
631632

632-
static bool reopen_store(struct gossmap *map, size_t ended_off)
633+
static bool reopen_store(struct gossmap *map, u64 ended_off)
633634
{
634635
int fd;
635636

@@ -659,7 +660,7 @@ static bool map_catchup(struct gossmap *map, bool *changed)
659660
for (; map->map_end + sizeof(struct gossip_hdr) < map->map_size;
660661
map->map_end += reclen) {
661662
struct gossip_hdr ghdr;
662-
size_t off;
663+
u64 off;
663664
u16 type, flags;
664665

665666
map_copy(map, map->map_end, &ghdr, sizeof(ghdr));
@@ -764,8 +765,8 @@ static void destroy_map(struct gossmap *map)
764765
struct localmod {
765766
struct short_channel_id scid;
766767
/* If this is an entirely-local channel, here's its offset.
767-
* Otherwise, 0xFFFFFFFF. */
768-
u32 local_off;
768+
* Otherwise, 0xFFFFFFFFFFFFFFFF. */
769+
u64 local_off;
769770

770771
/* Are updates in either direction set? */
771772
bool updates_set[2];
@@ -822,7 +823,7 @@ bool gossmap_local_addchan(struct gossmap_localmods *localmods,
822823
{
823824
be16 be16;
824825
be64 be64;
825-
size_t off;
826+
u64 off;
826827
struct localmod mod;
827828

828829
/* Don't create duplicate channels. */
@@ -1090,7 +1091,7 @@ struct gossmap *gossmap_load_fd_(const tal_t *ctx, int fd,
10901091
void *cb_arg),
10911092
bool (*unknown_record)(struct gossmap *map,
10921093
int type,
1093-
size_t off,
1094+
u64 off,
10941095
size_t msglen,
10951096
void *cb_arg),
10961097
void *cb_arg)
@@ -1130,7 +1131,7 @@ bool gossmap_chan_is_dying(const struct gossmap *map,
11301131
const struct gossmap_chan *c)
11311132
{
11321133
struct gossip_hdr ghdr;
1133-
size_t off;
1134+
u64 off;
11341135

11351136
/* FIXME: put this flag in plus_scid_off instead? */
11361137
off = c->cann_off - sizeof(ghdr);
@@ -1144,7 +1145,7 @@ bool gossmap_chan_get_capacity(const struct gossmap *map,
11441145
struct amount_sat *amount)
11451146
{
11461147
struct gossip_hdr ghdr;
1147-
size_t off;
1148+
u64 off;
11481149
u16 type;
11491150

11501151
/* Fail for local channels */
@@ -1319,7 +1320,7 @@ int gossmap_chan_get_feature(const struct gossmap *map,
13191320
int fbit)
13201321
{
13211322
/* Note that first two bytes are message type */
1322-
const size_t feature_len_off = 2 + (64 + 64 + 64 + 64);
1323+
const u64 feature_len_off = 2 + (64 + 64 + 64 + 64);
13231324
size_t feature_len;
13241325

13251326
feature_len = map_be16(map, c->cann_off + feature_len_off);
@@ -1334,7 +1335,7 @@ u8 *gossmap_chan_get_features(const tal_t *ctx,
13341335
{
13351336
u8 *ret;
13361337
/* Note that first two bytes are message type */
1337-
const size_t feature_len_off = 2 + (64 + 64 + 64 + 64);
1338+
const u64 feature_len_off = 2 + (64 + 64 + 64 + 64);
13381339
size_t feature_len;
13391340

13401341
feature_len = map_be16(map, c->cann_off + feature_len_off);
@@ -1391,15 +1392,15 @@ void gossmap_chan_get_update_details(const struct gossmap *map,
13911392
struct amount_msat *htlc_maximum_msat)
13921393
{
13931394
/* Note that first two bytes are message type */
1394-
const size_t scid_off = chan->cupdate_off[dir] + 2 + (64 + 32);
1395-
const size_t timestamp_off = scid_off + 8;
1396-
const size_t message_flags_off = timestamp_off + 4;
1397-
const size_t channel_flags_off = message_flags_off + 1;
1398-
const size_t cltv_expiry_delta_off = channel_flags_off + 1;
1399-
const size_t htlc_minimum_off = cltv_expiry_delta_off + 2;
1400-
const size_t fee_base_off = htlc_minimum_off + 8;
1401-
const size_t fee_prop_off = fee_base_off + 4;
1402-
const size_t htlc_maximum_off = fee_prop_off + 4;
1395+
const u64 scid_off = chan->cupdate_off[dir] + 2 + (64 + 32);
1396+
const u64 timestamp_off = scid_off + 8;
1397+
const u64 message_flags_off = timestamp_off + 4;
1398+
const u64 channel_flags_off = message_flags_off + 1;
1399+
const u64 cltv_expiry_delta_off = channel_flags_off + 1;
1400+
const u64 htlc_minimum_off = cltv_expiry_delta_off + 2;
1401+
const u64 fee_base_off = htlc_minimum_off + 8;
1402+
const u64 fee_prop_off = fee_base_off + 4;
1403+
const u64 htlc_maximum_off = fee_prop_off + 4;
14031404

14041405
assert(gossmap_chan_set(chan, dir));
14051406
/* Not allowed on local updates! */
@@ -1440,7 +1441,7 @@ int gossmap_node_get_feature(const struct gossmap *map,
14401441
const struct gossmap_node *n,
14411442
int fbit)
14421443
{
1443-
const size_t feature_len_off = 2 + 64;
1444+
const u64 feature_len_off = 2 + 64;
14441445
size_t feature_len;
14451446

14461447
if (n->nann_off == 0)
@@ -1458,7 +1459,7 @@ u8 *gossmap_node_get_features(const tal_t *ctx,
14581459
{
14591460
u8 *ret;
14601461
/* Note that first two bytes are message type */
1461-
const size_t feature_len_off = 2 + 64;
1462+
const u64 feature_len_off = 2 + 64;
14621463
size_t feature_len;
14631464

14641465
if (n->nann_off == 0)
@@ -1491,7 +1492,7 @@ bool gossmap_scidd_pubkey(struct gossmap *gossmap,
14911492
return sciddir_or_pubkey_from_node_id(sciddpk, &id);
14921493
}
14931494

1494-
size_t gossmap_lengths(const struct gossmap *map, size_t *total)
1495+
u64 gossmap_lengths(const struct gossmap *map, u64 *total)
14951496
{
14961497
*total = map->map_size;
14971498
return map->map_end;
@@ -1549,7 +1550,7 @@ const void *gossmap_stream_next(const tal_t *ctx,
15491550

15501551
while (iter->offset + sizeof(h.u.type) <= map->map_size) {
15511552
void *ret;
1552-
size_t len;
1553+
u64 len;
15531554

15541555
map_copy(map, iter->offset, &h, sizeof(h.u.type));
15551556

common/gossmap.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ struct sciddir_or_pubkey;
1212

1313
struct gossmap_node {
1414
/* Offset in memory map for node_announce, or 0. */
15-
u32 nann_off;
15+
u64 nann_off;
1616
u32 num_chans;
1717
u32 *chan_idxs;
1818
};
1919

2020
struct gossmap_chan {
21-
u32 cann_off;
22-
/* Technically redundant, but we have a hole anyway: from cann_off */
23-
u32 plus_scid_off;
21+
u64 cann_off;
22+
/* FIXME: Technically redundant */
23+
u64 plus_scid_off;
2424
/* Offsets of cupdates (0 if missing). Logically inside half_chan,
2525
* but that would add padding. */
26-
u32 cupdate_off[2];
26+
u64 cupdate_off[2];
2727
/* two nodes we connect (lesser idx first) */
2828
struct half_chan {
2929
/* Top bit indicates it's enabled */
@@ -57,7 +57,7 @@ struct gossmap *gossmap_load(const tal_t *ctx, const char *filename,
5757
typesafe_cb_preargs(bool, void *, (unknown_record), (cbarg), \
5858
struct gossmap *, \
5959
int type, \
60-
size_t off, \
60+
u64 off, \
6161
size_t msglen), \
6262
(cbarg))
6363

@@ -70,7 +70,7 @@ struct gossmap *gossmap_load_fd_(const tal_t *ctx, int fd,
7070
void *cb_arg),
7171
bool (*unknown_record)(struct gossmap *map,
7272
int type,
73-
size_t off,
73+
u64 off,
7474
size_t msglen,
7575
void *cb_arg),
7676
void *cb_arg);
@@ -296,7 +296,7 @@ void gossmap_iter_fast_forward(const struct gossmap *map,
296296
void gossmap_iter_end(const struct gossmap *map, struct gossmap_iter *iter);
297297

298298
/* For debugging: returns length read, and total known length of file */
299-
size_t gossmap_lengths(const struct gossmap *map, size_t *total);
299+
u64 gossmap_lengths(const struct gossmap *map, u64 *total);
300300

301301
/* Debugging: connectd wants to enumerate fds */
302302
int gossmap_fd(const struct gossmap *map);

gossipd/gossmap_manage.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -654,24 +654,24 @@ void gossmap_manage_handle_get_txout_reply(struct gossmap_manage *gm, const u8 *
654654

655655
/* We have reports of doubled-up channel_announcements, hence this check! */
656656
struct gossmap_chan *chan;
657-
size_t before_length_processed, before_total_length;
657+
u64 before_length_processed, before_total_length;
658658

659659
before_length_processed = gossmap_lengths(gm->raw_gossmap, &before_total_length);
660660
chan = gossmap_find_chan(gm->raw_gossmap, &scid);
661661
if (chan) {
662-
status_broken("Redundant channel_announce for scid %s at off %u (gossmap %zu/%zu, store %"PRIu64")",
662+
status_broken("Redundant channel_announce for scid %s at off %"PRIu64" (gossmap %"PRIu64"/%"PRIu64", store %"PRIu64")",
663663
fmt_short_channel_id(tmpctx, scid), chan->cann_off,
664664
before_length_processed, before_total_length,
665665
gossip_store_len_written(gm->daemon->gs));
666666
goto out;
667667
} else {
668-
size_t after_length_processed, after_total_length;
668+
u64 after_length_processed, after_total_length;
669669
/* Good, now try refreshing in case it somehow slipped in! */
670670
gossmap = gossmap_manage_get_gossmap(gm);
671671
after_length_processed = gossmap_lengths(gm->raw_gossmap, &after_total_length);
672672
chan = gossmap_find_chan(gm->raw_gossmap, &scid);
673673
if (chan) {
674-
status_broken("Redundant channel_announce *AFTER REFRESH* for scid %s at off %u (gossmap was %zu/%zu, now %zu/%zu, store %"PRIu64")",
674+
status_broken("Redundant channel_announce *AFTER REFRESH* for scid %s at off %"PRIu64" (gossmap was %"PRIu64"/%"PRIu64", now %"PRIu64"/%"PRIu64", store %"PRIu64")",
675675
fmt_short_channel_id(tmpctx, scid), chan->cann_off,
676676
before_length_processed, before_total_length,
677677
after_length_processed, after_total_length,

0 commit comments

Comments
 (0)