proper error handling for dump edgecases

This commit is contained in:
CPunch 2023-05-28 12:16:00 -05:00
parent 4fe437ea4e
commit be49ec5af5
2 changed files with 71 additions and 47 deletions

View File

@ -4,6 +4,7 @@
#include "cmem.h" #include "cmem.h"
#include "cobj.h" #include "cobj.h"
#include "cvalue.h" #include "cvalue.h"
#include "cvm.h"
typedef struct typedef struct
{ {
@ -13,7 +14,12 @@ typedef struct
int writerStatus; int writerStatus;
} DumpState; } DumpState;
static void writeCValue(DumpState *dstate, CValue val); static bool writeCValue(DumpState *dstate, CValue val);
#define check(e) \
if (!e) { \
return false; \
}
static void initDumpState(CState *state, DumpState *dstate, cosmo_Writer writer, static void initDumpState(CState *state, DumpState *dstate, cosmo_Writer writer,
const void *userData) const void *userData)
@ -24,82 +30,92 @@ static void initDumpState(CState *state, DumpState *dstate, cosmo_Writer writer,
dstate->writerStatus = 0; dstate->writerStatus = 0;
} }
static void writeBlock(DumpState *dstate, const void *data, size_t size) static bool writeBlock(DumpState *dstate, const void *data, size_t size)
{ {
if (dstate->writerStatus == 0) { if (dstate->writerStatus == 0) {
dstate->writerStatus = dstate->writer(dstate->state, data, size, dstate->userData); dstate->writerStatus = dstate->writer(dstate->state, data, size, dstate->userData);
} }
return dstate->writerStatus == 0;
} }
static void writeu8(DumpState *dstate, uint8_t d) static bool writeu8(DumpState *dstate, uint8_t d)
{ {
writeBlock(dstate, &d, sizeof(uint8_t)); return writeBlock(dstate, &d, sizeof(uint8_t));
} }
static void writeu32(DumpState *dstate, uint32_t d) static bool writeu32(DumpState *dstate, uint32_t d)
{ {
writeBlock(dstate, &d, sizeof(uint32_t)); return writeBlock(dstate, &d, sizeof(uint32_t));
} }
static void writeSize(DumpState *dstate, size_t d) static bool writeSize(DumpState *dstate, size_t d)
{ {
writeBlock(dstate, &d, sizeof(size_t)); return writeBlock(dstate, &d, sizeof(size_t));
} }
static void writeVector(DumpState *dstate, const void *data, size_t size, size_t count) static bool writeVector(DumpState *dstate, const void *data, size_t size, size_t count)
{ {
writeSize(dstate, count); check(writeSize(dstate, count));
writeBlock(dstate, data, size * count); check(writeBlock(dstate, data, size * count));
return true;
} }
static void writeHeader(DumpState *dstate) static bool writeHeader(DumpState *dstate)
{ {
writeBlock(dstate, COSMO_MAGIC, COSMO_MAGIC_LEN); check(writeBlock(dstate, COSMO_MAGIC, COSMO_MAGIC_LEN));
/* after the magic, we write some platform information */ /* after the magic, we write some platform information */
writeu8(dstate, cosmoD_isBigEndian()); check(writeu8(dstate, cosmoD_isBigEndian()));
writeu8(dstate, sizeof(cosmo_Number)); check(writeu8(dstate, sizeof(cosmo_Number)));
writeu8(dstate, sizeof(size_t)); check(writeu8(dstate, sizeof(size_t)));
writeu8(dstate, sizeof(int)); check(writeu8(dstate, sizeof(int)));
return true;
} }
static void writeCObjString(DumpState *dstate, CObjString *obj) static bool writeCObjString(DumpState *dstate, CObjString *obj)
{ {
if (obj == NULL) { /* this is in case cobjfunction's name or module strings are null */ if (obj == NULL) { /* this is in case cobjfunction's name or module strings are null */
writeu32(dstate, 0); check(writeu32(dstate, 0));
return; return true;
} }
/* write string length */ /* write string length */
writeu32(dstate, obj->length); check(writeu32(dstate, obj->length));
/* write string data */ /* write string data */
writeBlock(dstate, obj->str, obj->length); check(writeBlock(dstate, obj->str, obj->length));
return true;
} }
static void writeCObjFunction(DumpState *dstate, CObjFunction *obj) static bool writeCObjFunction(DumpState *dstate, CObjFunction *obj)
{ {
writeCObjString(dstate, obj->name); check(writeCObjString(dstate, obj->name));
writeCObjString(dstate, obj->module); check(writeCObjString(dstate, obj->module));
writeu32(dstate, obj->args); check(writeu32(dstate, obj->args));
writeu32(dstate, obj->upvals); check(writeu32(dstate, obj->upvals));
writeu8(dstate, obj->variadic); check(writeu8(dstate, obj->variadic));
/* write chunk info */ /* write chunk info */
writeVector(dstate, obj->chunk.buf, sizeof(uint8_t), obj->chunk.count); check(writeVector(dstate, obj->chunk.buf, sizeof(uint8_t), obj->chunk.count));
/* write line info */ /* write line info */
writeVector(dstate, obj->chunk.lineInfo, sizeof(int), obj->chunk.count); check(writeVector(dstate, obj->chunk.lineInfo, sizeof(int), obj->chunk.count));
/* write constants */ /* write constants */
writeSize(dstate, obj->chunk.constants.count); check(writeSize(dstate, obj->chunk.constants.count));
for (int i = 0; i < obj->chunk.constants.count; i++) { for (int i = 0; i < obj->chunk.constants.count; i++) {
writeCValue(dstate, obj->chunk.constants.values[i]); check(writeCValue(dstate, obj->chunk.constants.values[i]));
} }
return true;
} }
static void writeCObj(DumpState *dstate, CObj *obj) static bool writeCObj(DumpState *dstate, CObj *obj)
{ {
/* /*
we can kind of cheat here since our parser only emits a few very limited CObjs... we can kind of cheat here since our parser only emits a few very limited CObjs...
@ -117,24 +133,27 @@ static void writeCObj(DumpState *dstate, CObj *obj)
/* write object payload/body */ /* write object payload/body */
switch (t) { switch (t) {
case COBJ_STRING: case COBJ_STRING:
writeCObjString(dstate, (CObjString *)obj); check(writeCObjString(dstate, (CObjString *)obj));
break; break;
case COBJ_FUNCTION: case COBJ_FUNCTION:
writeCObjFunction(dstate, (CObjFunction *)obj); check(writeCObjFunction(dstate, (CObjFunction *)obj));
break; break;
default: default:
break; cosmoV_error(dstate->state, "invalid cobj type: %d", t);
return false;
} }
return true;
} }
#define WRITE_VAR(dstate, type, expression) \ #define WRITE_VAR(dstate, type, expression) \
{ \ { \
type _tmp = expression; \ type _tmp = expression; \
writeBlock(dstate, &_tmp, sizeof(_tmp)); \ check(writeBlock(dstate, &_tmp, sizeof(_tmp))); \
break; \ break; \
} }
static void writeCValue(DumpState *dstate, CValue val) static bool writeCValue(DumpState *dstate, CValue val)
{ {
CosmoType t = GET_TYPE(val); CosmoType t = GET_TYPE(val);
@ -148,12 +167,16 @@ static void writeCValue(DumpState *dstate, CValue val)
case COSMO_TBOOLEAN: case COSMO_TBOOLEAN:
WRITE_VAR(dstate, bool, cosmoV_readBoolean(val)) WRITE_VAR(dstate, bool, cosmoV_readBoolean(val))
case COSMO_TREF: case COSMO_TREF:
writeCObj(dstate, cosmoV_readRef(val)); check(writeCObj(dstate, cosmoV_readRef(val)));
break;
case COSMO_TNIL: /* no body */
break; break;
case COSMO_TNIL: /* fallthrough, no body */
default: default:
break; cosmoV_error(dstate->state, "invalid value type: %d", t);
return false;
} }
return true;
} }
#undef WRITE_VAR #undef WRITE_VAR
@ -174,8 +197,8 @@ int cosmoD_dump(CState *state, CObjFunction *func, cosmo_Writer writer, const vo
DumpState dstate; DumpState dstate;
initDumpState(state, &dstate, writer, userData); initDumpState(state, &dstate, writer, userData);
writeHeader(&dstate); check(writeHeader(&dstate));
writeCObjFunction(&dstate, func); check(writeCObjFunction(&dstate, func));
return dstate.writerStatus; return dstate.writerStatus;
} }

View File

@ -172,10 +172,10 @@ static bool readCObj(UndumpState *udstate, CObj **obj)
static bool readCValue(UndumpState *udstate, CValue *val) static bool readCValue(UndumpState *udstate, CValue *val)
{ {
uint8_t type; uint8_t t;
check(readu8(udstate, &type)); check(readu8(udstate, &t));
switch (type) { switch (t) {
case COSMO_TNUMBER: case COSMO_TNUMBER:
READ_VAR(udstate, val, cosmo_Number, cosmoV_newNumber) READ_VAR(udstate, val, cosmo_Number, cosmoV_newNumber)
case COSMO_TBOOLEAN: case COSMO_TBOOLEAN:
@ -190,7 +190,8 @@ static bool readCValue(UndumpState *udstate, CValue *val)
*val = cosmoV_newNil(); *val = cosmoV_newNil();
break; break;
default: default:
break; cosmoV_error(udstate->state, "invalid value type: %d", t);
return false;
} }
return true; return true;