aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorCalvin Rose <calsrose@gmail.com>2019-06-20 12:37:57 -0400
committerCalvin Rose <calsrose@gmail.com>2019-06-20 12:37:57 -0400
commit522545287ee3c20c103d29f5dae9f041de7b1fbf (patch)
treeedc94572739edb9bbea8ee4fdca0dd3cbd34a19f
parentBe more complete with JANET_NO_SOURCEMAPS (diff)
Add janet_abstract_begin and janet_abstract_end
This will allow some one constructing an abstract to only make it visible to the garbage collector after it is in a valid state. If code in the constructing cfunction panics before janet_abstract_end is called, the GC will not try to mark the incomplete abstract type. This is often not needed through careful programming, but should work well.
-rw-r--r--src/core/abstract.c13
-rw-r--r--src/core/peg.c5
-rw-r--r--src/include/janet.h4
3 files changed, 19 insertions, 3 deletions
diff --git a/src/core/abstract.c b/src/core/abstract.c
index 1132c470..0536fc98 100644
--- a/src/core/abstract.c
+++ b/src/core/abstract.c
@@ -26,10 +26,19 @@
#endif
/* Create new userdata */
-void *janet_abstract(const JanetAbstractType *atype, size_t size) {
- JanetAbstractHead *header = janet_gcalloc(JANET_MEMORY_ABSTRACT,
+void *janet_abstract_begin(const JanetAbstractType *atype, size_t size) {
+ JanetAbstractHead *header = janet_gcalloc(JANET_MEMORY_NONE,
sizeof(JanetAbstractHead) + size);
header->size = size;
header->type = atype;
return (void *) & (header->data);
}
+
+void *janet_abstract_end(void *x) {
+ janet_gc_settype((void *)(janet_gc_header(x)), JANET_MEMORY_ABSTRACT);
+ return x;
+}
+
+void *janet_abstract(const JanetAbstractType *atype, size_t size) {
+ return janet_abstract_end(janet_abstract_begin(atype, size));
+}
diff --git a/src/core/peg.c b/src/core/peg.c
index 85b907e3..924ea665 100644
--- a/src/core/peg.c
+++ b/src/core/peg.c
@@ -990,6 +990,11 @@ static void peg_unmarshal(void *p, JanetMarshalContext *ctx) {
peg->bytecode = NULL;
peg->constants = NULL;
+ /* Ensure not too large */
+ if (constants_start + sizeof(Janet) * peg->num_constants > janet_abstract_size(p)) {
+ janet_panic("size mismatch");
+ }
+
for (size_t i = 0; i < peg->bytecode_len; i++)
bytecode[i] = (uint32_t) janet_unmarshal_int(ctx);
for (uint32_t j = 0; j < peg->num_constants; j++)
diff --git a/src/include/janet.h b/src/include/janet.h
index 335b909f..e92700fd 100644
--- a/src/include/janet.h
+++ b/src/include/janet.h
@@ -1219,7 +1219,9 @@ JANET_API const JanetKV *janet_dictionary_next(const JanetKV *kvs, int32_t cap,
#define janet_abstract_head(u) ((JanetAbstractHead *)((char *)u - offsetof(JanetAbstractHead, data)))
#define janet_abstract_type(u) (janet_abstract_head(u)->type)
#define janet_abstract_size(u) (janet_abstract_head(u)->size)
-JANET_API void *janet_abstract(const JanetAbstractType *type, size_t size);
+JANET_API void *janet_abstract_begin(const JanetAbstractType *type, size_t size);
+JANET_API void *janet_abstract_end(void *);
+JANET_API void *janet_abstract(const JanetAbstractType *type, size_t size); /* begin and end in one call */
/* Native */
typedef void (*JanetModule)(JanetTable *);