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;
|
dcfg_Value *cur = evaled;
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
Token *t = &toks[i];
|
Token *t = &toks[i];
|
||||||
dcfg_Value *next = NULL;
|
dcfg_Value *next = NULL;
|
||||||
|
|
||||||
if (t->type == T_FIELD) {
|
if (t->type == T_FIELD) {
|
||||||
if (!dcfg_Value_get_object_field_ex(cur, t->v.field, &next, true)) {
|
if (!dcfg_Value_get_object_field_ex(cur, t->v.field, &next, true)) {
|
||||||
fprintf(stderr, "no such field\n");
|
fputs("no such field\n", stderr);
|
||||||
dcfg_destroy(evaled);
|
goto fail;
|
||||||
dcfg_destroy(root);
|
|
||||||
dcfg_destroy_instance(inst);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!dcfg_Value_get_array_item_ex(cur, t->v.index, &next, true)) {
|
if (!dcfg_Value_get_array_item_ex(cur, t->v.index, &next, true)) {
|
||||||
fprintf(stderr, "index out of bounds\n");
|
fputs("index out of bounds\n", stderr);
|
||||||
dcfg_destroy(evaled);
|
goto fail;
|
||||||
dcfg_destroy(root);
|
|
||||||
dcfg_destroy_instance(inst);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur != evaled)
|
if (cur != evaled) {
|
||||||
dcfg_destroy(cur);
|
dcfg_destroy(cur);
|
||||||
|
}
|
||||||
cur = next;
|
cur = next;
|
||||||
}
|
}
|
||||||
print_value(cur);
|
print_value(cur);
|
||||||
if (cur != evaled)
|
if (cur != evaled) {
|
||||||
dcfg_destroy(cur);
|
dcfg_destroy(cur);
|
||||||
|
}
|
||||||
|
|
||||||
dcfg_destroy(evaled);
|
dcfg_destroy(evaled);
|
||||||
dcfg_destroy(root);
|
dcfg_destroy(root);
|
||||||
dcfg_destroy_instance(inst);
|
dcfg_destroy_instance(inst);
|
||||||
return 0;
|
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;
|
StringView k;
|
||||||
Value *v;
|
Value *v;
|
||||||
bool key_allocated;
|
bool key_allocated;
|
||||||
|
bool owned;
|
||||||
} ValueObjectEntry;
|
} ValueObjectEntry;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -268,6 +269,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Value **valuev;
|
Value **valuev;
|
||||||
|
bool *ownedv;
|
||||||
} ValueArray;
|
} ValueArray;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -310,6 +312,8 @@ struct dcfg_Value {
|
|||||||
ValueMemberAccess ma;
|
ValueMemberAccess ma;
|
||||||
ValueFunctionCall c;
|
ValueFunctionCall c;
|
||||||
} v;
|
} v;
|
||||||
|
|
||||||
|
bool freed;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Environment {
|
typedef struct Environment {
|
||||||
@@ -1355,6 +1359,7 @@ Value *ast_to_value(dcfg_Instance *instance, AST *root)
|
|||||||
} else if (root->kind == ASTKind_Array) {
|
} else if (root->kind == ASTKind_Array) {
|
||||||
value->type = dcfg_ValueType_Array;
|
value->type = dcfg_ValueType_Array;
|
||||||
value->v.a.valuev = vector_create();
|
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++) {
|
for (size_t i = 0; i < vector_size(root->v.a.childv); i++) {
|
||||||
Value *v = ast_to_value(instance, root->v.a.childv[i]);
|
Value *v = ast_to_value(instance, root->v.a.childv[i]);
|
||||||
if (!v) {
|
if (!v) {
|
||||||
@@ -1366,6 +1371,7 @@ Value *ast_to_value(dcfg_Instance *instance, AST *root)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
vector_add(&value->v.a.valuev, Value *, v);
|
vector_add(&value->v.a.valuev, Value *, v);
|
||||||
|
vector_add(&value->v.a.ownedv, bool, true);
|
||||||
}
|
}
|
||||||
} else if (root->kind == ASTKind_Function) {
|
} else if (root->kind == ASTKind_Function) {
|
||||||
value->type = dcfg_ValueType_Function;
|
value->type = dcfg_ValueType_Function;
|
||||||
@@ -1527,38 +1533,55 @@ void dcfg_destroy(dcfg_Value *value)
|
|||||||
switch (value->type) {
|
switch (value->type) {
|
||||||
case dcfg_ValueType_Object:
|
case dcfg_ValueType_Object:
|
||||||
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++) {
|
||||||
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) {
|
if (value->v.o.entryv[i].key_allocated) {
|
||||||
value->instance->free((void *)value->v.o.entryv[i].k.data);
|
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);
|
vector_free(value->v.o.entryv);
|
||||||
|
value->v.o.entryv = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dcfg_ValueType_Array:
|
case dcfg_ValueType_Array:
|
||||||
for (size_t i = 0; i < vector_size(value->v.a.valuev); i++) {
|
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);
|
vector_free(value->v.a.valuev);
|
||||||
|
value->v.a.valuev = NULL;
|
||||||
|
vector_free(value->v.a.ownedv);
|
||||||
|
value->v.a.ownedv = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dcfg_ValueType_Function:
|
case dcfg_ValueType_Function:
|
||||||
if (!value->v.f.is_builtin) {
|
if (!value->v.f.is_builtin) {
|
||||||
dcfg_destroy(value->v.f.v.f.body);
|
dcfg_destroy(value->v.f.v.f.body);
|
||||||
|
value->v.f.v.f.body = NULL;
|
||||||
vector_free(value->v.f.v.f.argv);
|
vector_free(value->v.f.v.f.argv);
|
||||||
|
value->v.f.v.f.argv = NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dcfg_ValueType_FunctionCall:
|
case dcfg_ValueType_FunctionCall:
|
||||||
dcfg_destroy(value->v.c.function);
|
dcfg_destroy(value->v.c.function);
|
||||||
|
value->v.c.function = NULL;
|
||||||
for (size_t i = 0; i < vector_size(value->v.c.argv); i++) {
|
for (size_t i = 0; i < vector_size(value->v.c.argv); i++) {
|
||||||
dcfg_destroy(value->v.c.argv[i]);
|
dcfg_destroy(value->v.c.argv[i]);
|
||||||
|
value->v.c.argv[i] = NULL;
|
||||||
}
|
}
|
||||||
vector_free(value->v.c.argv);
|
vector_free(value->v.c.argv);
|
||||||
|
value->v.c.argv = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dcfg_ValueType_MemberAccess:
|
case dcfg_ValueType_MemberAccess:
|
||||||
vector_free(value->v.ma.accessv);
|
vector_free(value->v.ma.accessv);
|
||||||
|
value->v.ma.accessv = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1712,38 +1735,46 @@ dcfg_ValueType dcfg_Value_type_ex(dcfg_Value *value, bool evaluate)
|
|||||||
return value->type;
|
return value->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dcfg_Value_get_object_field_ex(dcfg_Value *value, dcfg_StringView key,
|
bool dcfg_Value_get_object_field_ex(
|
||||||
dcfg_Value **out_value, bool evaluate)
|
Value *obj, StringView key, Value **out, bool evaluate)
|
||||||
{
|
{
|
||||||
if (!value || value->type != dcfg_ValueType_Object)
|
if (!obj || obj->type != dcfg_ValueType_Object)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ValueObject *obj = &value->v.o;
|
for (size_t i = 0; i < vector_size(obj->v.o.entryv); ++i) {
|
||||||
for (size_t i = 0; i < vector_size(obj->entryv); ++i) {
|
ValueObjectEntry *e = &obj->v.o.entryv[i];
|
||||||
ValueObjectEntry *entry = &obj->entryv[i];
|
if (!sv_eq(e->k, key))
|
||||||
if (sv_eq(entry->k, key)) {
|
continue;
|
||||||
*out_value = entry->v;
|
|
||||||
if (evaluate)
|
*out = e->v;
|
||||||
dcfg_Value_evaluate(*out_value, out_value);
|
|
||||||
return true;
|
if (evaluate) {
|
||||||
|
if (!dcfg_Value_evaluate(*out, out))
|
||||||
|
return false;
|
||||||
|
e->v = *out;
|
||||||
|
e->owned = true;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dcfg_Value_get_array_item_ex(
|
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;
|
return false;
|
||||||
|
|
||||||
ValueArray *arr = &value->v.a;
|
*out = arr->v.a.valuev[idx];
|
||||||
if (index >= vector_size(arr->valuev))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*out_value = arr->valuev[index];
|
if (evaluate) {
|
||||||
if (evaluate)
|
if (!dcfg_Value_evaluate(*out, out))
|
||||||
dcfg_Value_evaluate(*out_value, out_value);
|
return false;
|
||||||
|
arr->v.a.valuev[idx] = *out;
|
||||||
|
arr->v.a.ownedv[idx] = true;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1880,45 +1911,30 @@ bool dcfg_Value_evaluate_in_env(
|
|||||||
v->type = dcfg_ValueType_Path;
|
v->type = dcfg_ValueType_Path;
|
||||||
v->v.p = value->v.p;
|
v->v.p = value->v.p;
|
||||||
} else if (value->type == dcfg_ValueType_Object) {
|
} else if (value->type == dcfg_ValueType_Object) {
|
||||||
|
|
||||||
v->type = dcfg_ValueType_Object;
|
v->type = dcfg_ValueType_Object;
|
||||||
v->v.o.entryv = vector_create();
|
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];
|
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 = {
|
ValueObjectEntry ne = {
|
||||||
.k = e->k,
|
.k = e->k,
|
||||||
.v = new_v,
|
.v = e->v,
|
||||||
.key_allocated = true,
|
.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);
|
vector_add(&v->v.o.entryv, ValueObjectEntry, ne);
|
||||||
}
|
}
|
||||||
} else if (value->type == dcfg_ValueType_Array) {
|
} else if (value->type == dcfg_ValueType_Array) {
|
||||||
v->type = dcfg_ValueType_Array;
|
v->type = dcfg_ValueType_Array;
|
||||||
v->v.a.valuev = vector_create();
|
v->v.a.valuev = vector_create();
|
||||||
for (size_t i = 0; i < vector_size(value->v.a.valuev); i++) {
|
v->v.a.ownedv = vector_create();
|
||||||
Value *val = NULL;
|
for (size_t i = 0; i < vector_size(value->v.a.valuev); ++i) {
|
||||||
bool res
|
vector_add(&v->v.a.valuev, Value *, value->v.a.valuev[i]);
|
||||||
= dcfg_Value_evaluate_in_env(value->v.a.valuev[i], frame, &val);
|
vector_add(&v->v.a.ownedv[i], bool, false);
|
||||||
if (!res) {
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
vector_add(&v->v.a.valuev, Value *, val);
|
|
||||||
}
|
}
|
||||||
} else if (value->type == dcfg_ValueType_Function) {
|
} else if (value->type == dcfg_ValueType_Function) {
|
||||||
Value *out_value_prev = *out_value;
|
v->type = dcfg_ValueType_Function;
|
||||||
bool res = dcfg_call_function(value, NULL, 0, out_value);
|
v->v.f = value->v.f;
|
||||||
if (!res) {
|
|
||||||
dcfg_destroy(out_value_prev);
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
} else if (value->type == dcfg_ValueType_MemberAccess) {
|
} else if (value->type == dcfg_ValueType_MemberAccess) {
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
ret = false;
|
ret = false;
|
||||||
@@ -1934,21 +1950,9 @@ bool dcfg_Value_evaluate_in_env(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (value->type == dcfg_ValueType_FunctionCall) {
|
} else if (value->type == dcfg_ValueType_FunctionCall) {
|
||||||
Value *function;
|
v->type = dcfg_ValueType_FunctionCall;
|
||||||
bool res
|
v->v.c.function = value->v.c.function;
|
||||||
= dcfg_Value_evaluate_in_env(value->v.c.function, frame, &function);
|
v->v.c.argv = value->v.c.argv;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
assert(0 && "Invalid value type");
|
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 };
|
Value *argv[1] = { lib };
|
||||||
bool ok = dcfg_call_function(top, argv, 1, out_value);
|
bool ok = dcfg_call_function(top, argv, 1, out_value);
|
||||||
vector_free(lib->v.o.entryv);
|
dcfg_destroy(lib);
|
||||||
inst->free(lib);
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user