jcs
/subtext
/amendments
/333
bile: Cope with malloc/realloc failures gracefully when possible
jcs made amendment 333 about 1 year ago
--- bile.c Wed Mar 1 09:19:35 2023
+++ bile.c Thu Mar 2 09:32:44 2023
@@ -51,11 +51,15 @@ bile_create(const Str255 filename, short vrefnum, cons
{
struct bile *bile = NULL;
size_t len;
+ short fh = -1;
char *tmp;
- short fh;
_bile_error = 0;
+ bile = xmalloczero(sizeof(struct bile));
+ if (bile == NULL)
+ return NULL;
+
/* create file */
_bile_error = Create(filename, vrefnum, creator, type);
if (_bile_error)
@@ -70,54 +74,56 @@ bile_create(const Str255 filename, short vrefnum, cons
return NULL;
SetFPos(fh, fsFromStart, 0);
- bile = xmalloczero(sizeof(struct bile), "bile_create");
memcpy(bile->magic, BILE_MAGIC, sizeof(bile->magic));
bile->vrefnum = vrefnum;
- bile->frefnum = fh;
bile->map_ptr.type = BILE_TYPE_MAPPTR;
memcpy(bile->filename, filename, sizeof(bile->filename));
/* write magic */
len = BILE_MAGIC_LEN;
- tmp = xstrdup(BILE_MAGIC, "bile_create magic");
- _bile_error = FSWrite(bile->frefnum, &len, tmp);
+ tmp = xstrdup(BILE_MAGIC);
+ if (tmp == NULL)
+ goto create_bail;
+ _bile_error = FSWrite(fh, &len, tmp);
xfree(&tmp);
if (_bile_error)
goto create_bail;
/* write header pointing to blank map */
len = sizeof(bile->map_ptr);
- _bile_error = FSWrite(bile->frefnum, &len, &bile->map_ptr);
+ _bile_error = FSWrite(fh, &len, &bile->map_ptr);
if (_bile_error)
goto create_bail;
len = sizeof(bile->old_map_ptr);
- _bile_error = FSWrite(bile->frefnum, &len, &bile->old_map_ptr);
+ _bile_error = FSWrite(fh, &len, &bile->old_map_ptr);
if (_bile_error)
goto create_bail;
/* padding */
len = BILE_HEADER_LEN - BILE_MAGIC_LEN - BILE_OBJECT_SIZE -
BILE_OBJECT_SIZE;
- tmp = xmalloczero(len, "bile_create padding");
- _bile_error = FSWrite(bile->frefnum, &len, tmp);
- if (_bile_error)
+ tmp = xmalloczero(len);
+ if (tmp == NULL)
goto create_bail;
+ _bile_error = FSWrite(fh, &len, tmp);
xfree(&tmp);
+ if (_bile_error)
+ goto create_bail;
GetFPos(fh, &bile->file_size);
if (bile->file_size != BILE_HEADER_LEN)
panic("bile_create: incorrect length after writing: %ld (!= %ld)",
bile->file_size, (long)BILE_HEADER_LEN);
-
+
+ bile->frefnum = fh;
return bile;
create_bail:
- FSClose(bile->frefnum);
- bile->frefnum = -1;
- if (bile != NULL)
- xfree(&bile);
+ if (fh != -1)
+ FSClose(fh);
+ xfree(&bile);
return NULL;
}
@@ -127,14 +133,18 @@ bile_open(const Str255 filename, short vrefnum)
struct bile *bile = NULL;
char magic[BILE_MAGIC_LEN + 1];
size_t file_size, size;
- short fh;
+ short fh = -1;
_bile_error = 0;
+ bile = xmalloczero(sizeof(struct bile));
+ if (bile == NULL)
+ return NULL;
+
/* open file */
_bile_error = FSOpen(filename, vrefnum, &fh);
if (_bile_error)
- return NULL;
+ goto open_bail;
_bile_error = SetFPos(fh, fsFromLEOF, 0);
if (_bile_error)
@@ -142,10 +152,8 @@ bile_open(const Str255 filename, short vrefnum)
GetFPos(fh, &file_size);
SetFPos(fh, fsFromStart, 0);
- bile = xmalloczero(sizeof(struct bile), "bile_open");
memcpy(bile->magic, BILE_MAGIC, sizeof(bile->magic));
bile->vrefnum = vrefnum;
- bile->frefnum = fh;
memcpy(bile->filename, filename, sizeof(bile->filename));
bile->file_size = file_size;
@@ -165,13 +173,13 @@ bile_open(const Str255 filename, short vrefnum)
/* load map pointer */
size = sizeof(bile->map_ptr);
- _bile_error = FSRead(bile->frefnum, &size, &bile->map_ptr);
+ _bile_error = FSRead(fh, &size, &bile->map_ptr);
if (_bile_error)
goto open_bail;
/* old map pointer */
size = sizeof(bile->old_map_ptr);
- _bile_error = FSRead(bile->frefnum, &size, &bile->old_map_ptr);
+ _bile_error = FSRead(fh, &size, &bile->old_map_ptr);
if (_bile_error)
goto open_bail;
@@ -181,6 +189,8 @@ bile_open(const Str255 filename, short vrefnum)
bile->map_ptr = bile->old_map_ptr;
}
+ bile->frefnum = fh;
+
if (bile->map_ptr.size) {
if (bile_read_map(bile, &bile->map_ptr) != 0) {
warn("bile_open: Failed reading map");
@@ -191,9 +201,9 @@ bile_open(const Str255 filename, short vrefnum)
return bile;
open_bail:
- FSClose(fh);
- if (bile != NULL)
- xfree(&bile);
+ if (fh != -1)
+ FSClose(fh);
+ xfree(&bile);
return NULL;
}
@@ -203,6 +213,10 @@ bile_check_sanity(struct bile *bile)
if (bile == NULL)
panic("bile_check_sanity: NULL bile");
+ /*
+ * We check this at file open time, so if we got here and the magic
+ * is bad, we're pointing at a bogus address
+ */
if (memcmp(bile->magic, BILE_MAGIC, sizeof(bile->magic)) != 0)
panic("bile_check_sanity: bogus magic");
}
@@ -232,7 +246,7 @@ bile_flush(struct bile *bile, bool and_vol)
short ret;
bile_check_sanity(bile);
-
+
memset(&pb, 0, sizeof(pb));
pb.ioRefNum = bile->frefnum;
/* if we're not flushing the volume, write async */
@@ -268,7 +282,6 @@ struct bile_object *
bile_find(struct bile *bile, const OSType type, const unsigned long id)
{
struct bile_object *o, *ocopy;
- char note[MALLOC_NOTE_SIZE];
bile_check_sanity(bile);
@@ -276,9 +289,12 @@ bile_find(struct bile *bile, const OSType type, const
if (o == NULL)
return NULL;
- snprintf(note, sizeof(note), "bile_find %s %lu", OSTypeToString(type),
- id);
- ocopy = xmalloc(BILE_OBJECT_SIZE, note);
+ ocopy = xmalloc(BILE_OBJECT_SIZE);
+ if (ocopy == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return NULL;
+ }
+
memcpy(ocopy, o, BILE_OBJECT_SIZE);
return ocopy;
@@ -320,8 +336,13 @@ bile_ids_by_type(struct bile *bile, const OSType type,
if (o->type != type)
continue;
- EXPAND_TO_FIT(ids, size, count * sizeof(size_t), sizeof(size_t),
- 10 * sizeof(size_t));
+ if (!grow_to_fit(&ids, &size, count * sizeof(size_t), sizeof(size_t),
+ 10 * sizeof(size_t))) {
+ if (ids != NULL)
+ xfree(&ids);
+ *ret = NULL;
+ return 0;
+ }
ids[count++] = o->id;
}
@@ -337,7 +358,11 @@ bile_sorted_ids_by_type(struct bile *bile, const OSTyp
unsigned long *ids = NULL;
count = bile_ids_by_type(bile, type, &ids);
-
+ if (count == 0) {
+ *ret = NULL;
+ return 0;
+ }
+
for (n = 0; n < count; n++) {
for (j = 0; j < count - n - 1; j++) {
if (ids[j] > ids[j + 1]) {
@@ -358,7 +383,6 @@ bile_get_nth_of_type(struct bile *bile, const unsigned
{
struct bile_object *o, *ocopy;
size_t n, count = 0;
- char note[MALLOC_NOTE_SIZE];
bile_check_sanity(bile);
@@ -370,9 +394,11 @@ bile_get_nth_of_type(struct bile *bile, const unsigned
continue;
if (count == index) {
- snprintf(note, sizeof(note), "bile_get_nth %s %lu",
- OSTypeToString(type), index);
- ocopy = xmalloc(BILE_OBJECT_SIZE, note);
+ ocopy = xmalloc(BILE_OBJECT_SIZE);
+ if (ocopy == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return NULL;
+ }
memcpy(ocopy, o, BILE_OBJECT_SIZE);
return ocopy;
}
@@ -405,6 +431,8 @@ bile_next_id(struct bile *bile, const OSType type)
if (highest > id)
id = highest + 1;
}
+ if (_bile_error)
+ return 0;
return id;
}
@@ -424,7 +452,8 @@ bile_delete(struct bile *bile, const OSType type, cons
o = bile_object_in_map(bile, type, id);
if (o == NULL) {
- _bile_error = bile->last_error = -1;
+ if (_bile_error)
+ return _bile_error;
return -1;
}
@@ -466,6 +495,8 @@ bile_delete(struct bile *bile, const OSType type, cons
/* store the type as the id, and the highest id as the data */
bile_write(bile, BILE_TYPE_HIGHESTID, type, &highest,
sizeof(unsigned long));
+ if (_bile_error)
+ return -1;
/* bile_write wrote a new map for us */
} else if (flags & BILE_DELETE_FLAG_PURGE) {
@@ -586,9 +617,7 @@ bile_read_alloc(struct bile *bile, const OSType type,
const unsigned long id, void *data_ptr)
{
struct bile_object *o;
- size_t ret;
char **data;
- char note[MALLOC_NOTE_SIZE];
bile_check_sanity(bile);
@@ -605,12 +634,13 @@ bile_read_alloc(struct bile *bile, const OSType type,
return 0;
}
- snprintf(note, sizeof(note), "bile_read_alloc %s %ld",
- OSTypeToString(type), id);
- *data = xmalloc(o->size, note);
- ret = bile_read_object(bile, o, *data, o->size);
+ *data = xmalloc(o->size);
+ if (*data == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return 0;
+ }
- return ret;
+ return bile_read_object(bile, o, *data, o->size);
}
size_t
@@ -630,7 +660,11 @@ bile_resize(struct bile *bile, const OSType type,
}
/* if we're growing, fill new space with zero */
- data = xmalloczero(MAX(o->size, new_size), "bile_resize_object");
+ data = xmalloczero(MAX(o->size, new_size));
+ if (data == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ }
+
ret = bile_read_object(bile, o, data, o->size);
if (ret != o->size) {
_bile_error = bile->last_error = -1;
@@ -664,6 +698,10 @@ bile_write(struct bile *bile, const OSType type, const
old->type = BILE_TYPE_PURGE;
new_obj = bile_alloc(bile, type, id, len);
+ if (new_obj == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return 0;
+ }
wrote = bile_xwriteat(bile, new_obj->pos, new_obj, BILE_OBJECT_SIZE);
if (wrote != BILE_OBJECT_SIZE || bile->last_error)
@@ -685,7 +723,7 @@ bile_write(struct bile *bile, const OSType type, const
short
bile_marshall_object(struct bile *bile,
const struct bile_object_field *fields, const size_t nfields,
- void *object, void *ret_ptr, size_t *ret_size, char *note)
+ void *object, void *ret_ptr, size_t *ret_size)
{
char **ret;
char *data, *ptr;
@@ -740,7 +778,11 @@ iterate_fields:
}
if (!write) {
- data = xmalloc(size, note);
+ data = xmalloc(size);
+ if (data == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return BILE_ERR_NO_MEMORY;
+ }
write = true;
size = 0;
goto iterate_fields;
@@ -756,7 +798,7 @@ short
bile_unmarshall_object(struct bile *bile,
const struct bile_object_field *fields, const size_t nfields,
const void *data, const size_t data_size, void *object,
- const size_t object_size, bool deep, char *note)
+ const size_t object_size, bool deep)
{
size_t off, fsize = 0, n;
char *ptr, *dptr;
@@ -782,7 +824,11 @@ bile_unmarshall_object(struct bile *bile,
memset(ptr, 0, sizeof(dptr));
continue;
}
- dptr = xmalloc(fsize, note);
+ dptr = xmalloc(fsize);
+ if (dptr == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return BILE_ERR_NO_MEMORY;
+ }
memcpy(ptr, &dptr, sizeof(dptr));
ptr = dptr;
}
@@ -804,7 +850,6 @@ bile_unmarshall_object(struct bile *bile,
return 0;
}
-
short
bile_verify(struct bile *bile)
{
@@ -859,6 +904,7 @@ bile_alloc(struct bile *bile, const OSType type, const
{
size_t last_pos = BILE_HEADER_LEN;
size_t n, map_pos;
+ struct bile_object *new_map;
bile_check_sanity(bile);
@@ -890,9 +936,14 @@ bile_alloc(struct bile *bile, const OSType type, const
}
}
+ new_map = xreallocarray(bile->map, bile->nobjects + 1,
+ BILE_OBJECT_SIZE);
+ if (new_map == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return NULL;
+ }
+ bile->map = new_map;
bile->nobjects++;
- bile->map = xreallocarray(bile->map, bile->nobjects, BILE_OBJECT_SIZE);
-
if (map_pos + 1 < bile->nobjects) {
/* shift remaining objects up */
memmove(&bile->map[map_pos + 1], &bile->map[map_pos],
@@ -951,7 +1002,11 @@ bile_read_map(struct bile *bile, struct bile_object *m
/* read entire map */
size = map_obj.size;
- map = xmalloczero(size, "bile_read_map");
+ map = xmalloczero(size);
+ if (map == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return -1;
+ }
_bile_error = FSRead(bile->frefnum, &size, map);
if (_bile_error) {
xfree(&map);
@@ -989,8 +1044,17 @@ bile_write_map(struct bile *bile)
new_map_size = BILE_OBJECT_SIZE * new_nobjects;
new_map_obj = bile_alloc(bile, BILE_TYPE_MAP, new_map_id,
new_map_size);
- new_map = xcalloc(BILE_OBJECT_SIZE, new_nobjects, "bile_write_map");
-
+ if (new_map_obj == NULL) {
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return BILE_ERR_NO_MEMORY;
+ }
+ new_map = xcalloc(BILE_OBJECT_SIZE, new_nobjects);
+ if (new_map == NULL) {
+ xfree(&new_map_obj);
+ _bile_error = bile->last_error = BILE_ERR_NO_MEMORY;
+ return BILE_ERR_NO_MEMORY;
+ }
+
for (n = 0, new_nobjects = 0; n < bile->nobjects; n++) {
obj = &bile->map[n];
--- bile.h Wed Mar 1 09:19:35 2023
+++ bile.h Wed Mar 1 13:21:29 2023
@@ -76,6 +76,7 @@ struct bile_object {
#define BILE_ERR_NEED_UPGRADE_1 -4000
#define BILE_ERR_BOGUS_OBJECT -4001
+#define BILE_ERR_NO_MEMORY -4002
#define BILE_DELETE_FLAG_ZERO (1 << 0)
#define BILE_DELETE_FLAG_PURGE (1 << 1)
@@ -146,11 +147,11 @@ short bile_verify(struct bile *bile);
short bile_marshall_object(struct bile *bile,
const struct bile_object_field *fields,
const size_t nfields, void *object,
- void *ret_ptr, size_t *ret_size, char *note);
+ void *ret_ptr, size_t *ret_size);
short bile_unmarshall_object(struct bile *bile,
const struct bile_object_field *fields,
const size_t nfields, const void *data,
const size_t data_size, void *object,
- const size_t object_size, bool deep, char *note);
+ const size_t object_size, bool deep);
#endif