aboutsummaryrefslogtreecommitdiffstats
path: root/core/module-save.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/module-save.c')
-rw-r--r--core/module-save.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/core/module-save.c b/core/module-save.c
index 19e9684..1055b4f 100644
--- a/core/module-save.c
+++ b/core/module-save.c
@@ -198,9 +198,14 @@ static unsigned char *layout_fields(const PureLayout *l, unsigned at, unsigned c
return out;
}
+/* 0 without room for the record's graph. */
static size_t image_header(const PureModule *m, uint32_t record, uint64_t seq, unsigned char *out) {
PureLayout l;
- pure_layout_of(m, record, &l);
+ pure_layout_begin(&l);
+ if (!pure_layout_of(m, record, &l)) {
+ pure_layout_done(&l);
+ return 0;
+ }
memcpy(out, image_magic, 4);
out[4] = (unsigned char)l.record[0].count;
unsigned char *at = layout_fields(&l, 0, out + 5);
@@ -210,6 +215,7 @@ static size_t image_header(const PureModule *m, uint32_t record, uint64_t seq, u
*at++ = (unsigned char)l.record[k].count;
at = layout_fields(&l, k, at);
}
+ pure_layout_done(&l);
return (size_t)(put_le(at, seq, 8) - out);
}
@@ -485,7 +491,8 @@ PureResult pure_save_image(PureApp *app, const PureModule *m, uint32_t state, co
unsigned char *header = malloc(header_room(m));
if (!header) return PURE_ALLOCATION;
size_t header_size = image_header(m, m->state_ref[state], app->seq, header);
- PureResult result = write_image(directory_of(app), m->state_names[state], header, header_size, list);
+ PureResult result = header_size ? write_image(directory_of(app), m->state_names[state], header, header_size, list)
+ : PURE_ALLOCATION;
free(header);
return result;
}
@@ -511,7 +518,9 @@ PURE_COLD PureResult pure_save_open_list(PureApp *app, const PureModule *m, uint
}
/* The stored record graph: its fields' kinds (PURE_CELL_...: a record's, its lists' PURE_CELL_LIST) and names, and
* the records of the lists in its fields (an image's alone, 027's stage 3). */
- PureLayout stored_layout = {.records = 1};
+ PureLayout stored_layout, layout;
+ pure_layout_begin(&stored_layout), pure_layout_begin(&layout);
+ stored_layout.records = 1;
unsigned count = 0;
size_t at = 0, items = 0;
uint64_t holds = 0;
@@ -523,7 +532,7 @@ PURE_COLD PureResult pure_save_open_list(PureApp *app, const PureModule *m, uint
at = 5;
ok = ok && read_fields(bytes, size, &at, count, &stored_layout, 0, 256, &lists) && (image || !lists);
if (ok && lists) { /* the graph's other records */
- ok = at < size && bytes[at] < PURE_MODULE_RECORDS;
+ ok = at < size && pure_layout_room(&stored_layout, 1u + bytes[at]);
stored_layout.records = ok ? 1u + bytes[at++] : 1;
for (unsigned k = 1; ok && k < stored_layout.records; ++k)
ok = at < size && bytes[at] <= PURE_RECORD_FIELDS &&
@@ -564,10 +573,10 @@ PURE_COLD PureResult pure_save_open_list(PureApp *app, const PureModule *m, uint
saved->logged += change->records.size;
}
}
- PureLayout layout;
- pure_layout_of(m, record, &layout);
- bool same = stored && pure_layout_same(&stored_layout, &layout);
+ if (result == PURE_OK && !pure_layout_of(m, record, &layout)) result = PURE_ALLOCATION;
+ bool same = stored && result == PURE_OK && pure_layout_same(&stored_layout, &layout);
if (result == PURE_OK && same && image) {
+ pure_layout_done(&stored_layout), pure_layout_done(&layout);
*out = from;
saved->image = holds;
return PURE_OK;
@@ -587,6 +596,7 @@ PURE_COLD PureResult pure_save_open_list(PureApp *app, const PureModule *m, uint
}
}
pure_list_free(from);
+ pure_layout_done(&stored_layout), pure_layout_done(&layout);
if (result != PURE_OK) {
pure_list_free(*out);
pure_draft_close(*legacy);
@@ -718,6 +728,11 @@ PureCheckpoint *pure_app_checkpoint(PureApp *app) {
c->header_size = pick == PURE_LIST_OUTBOX ? outbox_header(m, c->seq, c->header) :
pick >= PURE_LIST_HEARD ? runtime_header(pick, c->seq, c->header) :
image_header(m, m->state_ref[pick], c->seq, c->header);
+ if (!c->header_size) { /* no room for its record's graph: none now */
+ pure_snapshot_release(c->snapshot);
+ free(c->directory), free(c->header), free(c);
+ return NULL;
+ }
c->logged = app->logged[slot];
c->since = app->logged_since[slot];
app->checkpoint = c;