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

View File

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