Add lazy evaluation, and introduce use-after-free
Some checks failed
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=OFF (push) Failing after 11s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=OFF (push) Failing after 12s
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=ON (push) Failing after 11s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=ON (push) Failing after 12s
CMake / ubuntu-latest - shared=OFF, pthread=ON, posix=ON (push) Failing after 10s
CMake / ubuntu-latest - shared=ON, pthread=ON, posix=ON (push) Failing after 10s
Some checks failed
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=OFF (push) Failing after 11s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=OFF (push) Failing after 12s
CMake / ubuntu-latest - shared=OFF, pthread=OFF, posix=ON (push) Failing after 11s
CMake / ubuntu-latest - shared=ON, pthread=OFF, posix=ON (push) Failing after 12s
CMake / ubuntu-latest - shared=OFF, pthread=ON, posix=ON (push) Failing after 10s
CMake / ubuntu-latest - shared=ON, pthread=ON, posix=ON (push) Failing after 10s
Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
@@ -105,39 +105,40 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
dcfg_Value *cur = evaled;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
Token *t = &toks[i];
|
||||
dcfg_Value *next = NULL;
|
||||
|
||||
if (t->type == T_FIELD) {
|
||||
if (!dcfg_Value_get_object_field_ex(cur, t->v.field, &next, true)) {
|
||||
fprintf(stderr, "no such field\n");
|
||||
dcfg_destroy(evaled);
|
||||
dcfg_destroy(root);
|
||||
dcfg_destroy_instance(inst);
|
||||
return 1;
|
||||
fputs("no such field\n", stderr);
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (!dcfg_Value_get_array_item_ex(cur, t->v.index, &next, true)) {
|
||||
fprintf(stderr, "index out of bounds\n");
|
||||
dcfg_destroy(evaled);
|
||||
dcfg_destroy(root);
|
||||
dcfg_destroy_instance(inst);
|
||||
return 1;
|
||||
fputs("index out of bounds\n", stderr);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur != evaled)
|
||||
if (cur != evaled) {
|
||||
dcfg_destroy(cur);
|
||||
|
||||
}
|
||||
cur = next;
|
||||
}
|
||||
print_value(cur);
|
||||
if (cur != evaled)
|
||||
if (cur != evaled) {
|
||||
dcfg_destroy(cur);
|
||||
}
|
||||
|
||||
dcfg_destroy(evaled);
|
||||
dcfg_destroy(root);
|
||||
dcfg_destroy_instance(inst);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dcfg_destroy(evaled);
|
||||
dcfg_destroy(root);
|
||||
dcfg_destroy_instance(inst);
|
||||
return 1;
|
||||
}
|
||||
|
131
src/dcfg.c
131
src/dcfg.c
@@ -260,6 +260,7 @@ typedef struct {
|
||||
StringView k;
|
||||
Value *v;
|
||||
bool key_allocated;
|
||||
bool owned;
|
||||
} ValueObjectEntry;
|
||||
|
||||
typedef struct {
|
||||
@@ -268,6 +269,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
Value **valuev;
|
||||
bool *ownedv;
|
||||
} ValueArray;
|
||||
|
||||
typedef struct {
|
||||
@@ -310,6 +312,8 @@ struct dcfg_Value {
|
||||
ValueMemberAccess ma;
|
||||
ValueFunctionCall c;
|
||||
} v;
|
||||
|
||||
bool freed;
|
||||
};
|
||||
|
||||
typedef struct Environment {
|
||||
@@ -1355,6 +1359,7 @@ Value *ast_to_value(dcfg_Instance *instance, AST *root)
|
||||
} else if (root->kind == ASTKind_Array) {
|
||||
value->type = dcfg_ValueType_Array;
|
||||
value->v.a.valuev = vector_create();
|
||||
value->v.a.ownedv = vector_create();
|
||||
for (size_t i = 0; i < vector_size(root->v.a.childv); i++) {
|
||||
Value *v = ast_to_value(instance, root->v.a.childv[i]);
|
||||
if (!v) {
|
||||
@@ -1366,6 +1371,7 @@ Value *ast_to_value(dcfg_Instance *instance, AST *root)
|
||||
return NULL;
|
||||
}
|
||||
vector_add(&value->v.a.valuev, Value *, v);
|
||||
vector_add(&value->v.a.ownedv, bool, true);
|
||||
}
|
||||
} else if (root->kind == ASTKind_Function) {
|
||||
value->type = dcfg_ValueType_Function;
|
||||
@@ -1527,38 +1533,55 @@ void dcfg_destroy(dcfg_Value *value)
|
||||
switch (value->type) {
|
||||
case dcfg_ValueType_Object:
|
||||
for (size_t i = 0; i < vector_size(value->v.o.entryv); i++) {
|
||||
dcfg_destroy(value->v.o.entryv[i].v);
|
||||
if (value->v.o.entryv[i].owned) {
|
||||
dcfg_destroy(value->v.o.entryv[i].v);
|
||||
value->v.o.entryv[i].v = NULL;
|
||||
}
|
||||
if (value->v.o.entryv[i].key_allocated) {
|
||||
value->instance->free((void *)value->v.o.entryv[i].k.data);
|
||||
value->v.o.entryv[i].k.data = NULL;
|
||||
}
|
||||
}
|
||||
vector_free(value->v.o.entryv);
|
||||
value->v.o.entryv = NULL;
|
||||
break;
|
||||
|
||||
case dcfg_ValueType_Array:
|
||||
for (size_t i = 0; i < vector_size(value->v.a.valuev); i++) {
|
||||
dcfg_destroy(value->v.a.valuev[i]);
|
||||
if (value->v.a.ownedv[i]) {
|
||||
dcfg_destroy(value->v.a.valuev[i]);
|
||||
value->v.a.valuev[i] = NULL;
|
||||
}
|
||||
}
|
||||
vector_free(value->v.a.valuev);
|
||||
value->v.a.valuev = NULL;
|
||||
vector_free(value->v.a.ownedv);
|
||||
value->v.a.ownedv = NULL;
|
||||
break;
|
||||
|
||||
case dcfg_ValueType_Function:
|
||||
if (!value->v.f.is_builtin) {
|
||||
dcfg_destroy(value->v.f.v.f.body);
|
||||
value->v.f.v.f.body = NULL;
|
||||
vector_free(value->v.f.v.f.argv);
|
||||
value->v.f.v.f.argv = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case dcfg_ValueType_FunctionCall:
|
||||
dcfg_destroy(value->v.c.function);
|
||||
value->v.c.function = NULL;
|
||||
for (size_t i = 0; i < vector_size(value->v.c.argv); i++) {
|
||||
dcfg_destroy(value->v.c.argv[i]);
|
||||
value->v.c.argv[i] = NULL;
|
||||
}
|
||||
vector_free(value->v.c.argv);
|
||||
value->v.c.argv = NULL;
|
||||
break;
|
||||
|
||||
case dcfg_ValueType_MemberAccess:
|
||||
vector_free(value->v.ma.accessv);
|
||||
value->v.ma.accessv = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1712,38 +1735,46 @@ dcfg_ValueType dcfg_Value_type_ex(dcfg_Value *value, bool evaluate)
|
||||
return value->type;
|
||||
}
|
||||
|
||||
bool dcfg_Value_get_object_field_ex(dcfg_Value *value, dcfg_StringView key,
|
||||
dcfg_Value **out_value, bool evaluate)
|
||||
bool dcfg_Value_get_object_field_ex(
|
||||
Value *obj, StringView key, Value **out, bool evaluate)
|
||||
{
|
||||
if (!value || value->type != dcfg_ValueType_Object)
|
||||
if (!obj || obj->type != dcfg_ValueType_Object)
|
||||
return false;
|
||||
|
||||
ValueObject *obj = &value->v.o;
|
||||
for (size_t i = 0; i < vector_size(obj->entryv); ++i) {
|
||||
ValueObjectEntry *entry = &obj->entryv[i];
|
||||
if (sv_eq(entry->k, key)) {
|
||||
*out_value = entry->v;
|
||||
if (evaluate)
|
||||
dcfg_Value_evaluate(*out_value, out_value);
|
||||
return true;
|
||||
for (size_t i = 0; i < vector_size(obj->v.o.entryv); ++i) {
|
||||
ValueObjectEntry *e = &obj->v.o.entryv[i];
|
||||
if (!sv_eq(e->k, key))
|
||||
continue;
|
||||
|
||||
*out = e->v;
|
||||
|
||||
if (evaluate) {
|
||||
if (!dcfg_Value_evaluate(*out, out))
|
||||
return false;
|
||||
e->v = *out;
|
||||
e->owned = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dcfg_Value_get_array_item_ex(
|
||||
dcfg_Value *value, size_t index, dcfg_Value **out_value, bool evaluate)
|
||||
Value *arr, size_t idx, Value **out, bool evaluate)
|
||||
{
|
||||
if (!value || value->type != dcfg_ValueType_Array)
|
||||
if (!arr || arr->type != dcfg_ValueType_Array)
|
||||
return false;
|
||||
if (idx >= vector_size(arr->v.a.valuev))
|
||||
return false;
|
||||
|
||||
ValueArray *arr = &value->v.a;
|
||||
if (index >= vector_size(arr->valuev))
|
||||
return false;
|
||||
*out = arr->v.a.valuev[idx];
|
||||
|
||||
*out_value = arr->valuev[index];
|
||||
if (evaluate)
|
||||
dcfg_Value_evaluate(*out_value, out_value);
|
||||
if (evaluate) {
|
||||
if (!dcfg_Value_evaluate(*out, out))
|
||||
return false;
|
||||
arr->v.a.valuev[idx] = *out;
|
||||
arr->v.a.ownedv[idx] = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1880,45 +1911,30 @@ bool dcfg_Value_evaluate_in_env(
|
||||
v->type = dcfg_ValueType_Path;
|
||||
v->v.p = value->v.p;
|
||||
} else if (value->type == dcfg_ValueType_Object) {
|
||||
|
||||
v->type = dcfg_ValueType_Object;
|
||||
v->v.o.entryv = vector_create();
|
||||
for (size_t i = 0; i < vector_size(value->v.o.entryv); i++) {
|
||||
for (size_t i = 0; i < vector_size(value->v.o.entryv); ++i) {
|
||||
ValueObjectEntry *e = &value->v.o.entryv[i];
|
||||
Value *new_v;
|
||||
bool res = dcfg_Value_evaluate_in_env(e->v, frame, &new_v);
|
||||
if (!res) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
ValueObjectEntry ne = {
|
||||
.k = e->k,
|
||||
.v = new_v,
|
||||
.key_allocated = true,
|
||||
.v = e->v,
|
||||
.key_allocated = false,
|
||||
.owned = false,
|
||||
};
|
||||
ne.k.data = value->instance->alloc(ne.k.size + 1);
|
||||
memcpy((void *)ne.k.data, e->k.data, ne.k.size);
|
||||
((char *)ne.k.data)[ne.k.size] = '\0';
|
||||
vector_add(&v->v.o.entryv, ValueObjectEntry, ne);
|
||||
}
|
||||
} else if (value->type == dcfg_ValueType_Array) {
|
||||
v->type = dcfg_ValueType_Array;
|
||||
v->v.a.valuev = vector_create();
|
||||
for (size_t i = 0; i < vector_size(value->v.a.valuev); i++) {
|
||||
Value *val = NULL;
|
||||
bool res
|
||||
= dcfg_Value_evaluate_in_env(value->v.a.valuev[i], frame, &val);
|
||||
if (!res) {
|
||||
ret = false;
|
||||
}
|
||||
vector_add(&v->v.a.valuev, Value *, val);
|
||||
v->v.a.ownedv = vector_create();
|
||||
for (size_t i = 0; i < vector_size(value->v.a.valuev); ++i) {
|
||||
vector_add(&v->v.a.valuev, Value *, value->v.a.valuev[i]);
|
||||
vector_add(&v->v.a.ownedv[i], bool, false);
|
||||
}
|
||||
} else if (value->type == dcfg_ValueType_Function) {
|
||||
Value *out_value_prev = *out_value;
|
||||
bool res = dcfg_call_function(value, NULL, 0, out_value);
|
||||
if (!res) {
|
||||
dcfg_destroy(out_value_prev);
|
||||
ret = false;
|
||||
}
|
||||
v->type = dcfg_ValueType_Function;
|
||||
v->v.f = value->v.f;
|
||||
} else if (value->type == dcfg_ValueType_MemberAccess) {
|
||||
if (!frame) {
|
||||
ret = false;
|
||||
@@ -1934,21 +1950,9 @@ bool dcfg_Value_evaluate_in_env(
|
||||
}
|
||||
}
|
||||
} else if (value->type == dcfg_ValueType_FunctionCall) {
|
||||
Value *function;
|
||||
bool res
|
||||
= dcfg_Value_evaluate_in_env(value->v.c.function, frame, &function);
|
||||
if (!res || function->type != dcfg_ValueType_Function) {
|
||||
ret = false;
|
||||
} else {
|
||||
Value *out_value_prev = *out_value;
|
||||
bool res = dcfg_call_function(function, value->v.c.argv,
|
||||
vector_size(value->v.c.argv), out_value);
|
||||
if (!res) {
|
||||
ret = false;
|
||||
} else {
|
||||
dcfg_destroy(out_value_prev);
|
||||
}
|
||||
}
|
||||
v->type = dcfg_ValueType_FunctionCall;
|
||||
v->v.c.function = value->v.c.function;
|
||||
v->v.c.argv = value->v.c.argv;
|
||||
} else {
|
||||
assert(0 && "Invalid value type");
|
||||
}
|
||||
@@ -2078,8 +2082,7 @@ bool dcfg_Value_evaluate_toplevel(dcfg_Value *top, dcfg_Value **out_value,
|
||||
|
||||
Value *argv[1] = { lib };
|
||||
bool ok = dcfg_call_function(top, argv, 1, out_value);
|
||||
vector_free(lib->v.o.entryv);
|
||||
inst->free(lib);
|
||||
dcfg_destroy(lib);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user