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

Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
2025-08-01 08:06:25 +03:00
parent 1d40c785f8
commit 4664ad3bfb
2 changed files with 82 additions and 78 deletions

View File

@@ -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;
}

View File

@@ -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;
}