Skip to content

Commit

Permalink
Disable escaping from namespaces for inner functions.
Browse files Browse the repository at this point in the history
It should be invalid to reference a local variable from an outer scope, and the
check is a work in progress right now.

For the purpose of catching invalid variable references, a set of new 'function
scopes' has been introduced into Context. Every variable will keep track of its
function scope. A variable can be referenced as a value if and only if its
function scope is equal to the current function scope, or its function scope is
the global scope.
  • Loading branch information
ChengCat committed Oct 19, 2018
1 parent 844936c commit 16ce652
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 86 deletions.
56 changes: 20 additions & 36 deletions src/dale/Context/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,42 +54,6 @@ Context::~Context() { deleteNamespaces(namespaces); }

Namespace *Context::ns() { return active_ns_nodes.back()->ns; }

bool Context::popUntilNamespace(Namespace *ns) {
assert(ns && "null argument to popUntilNamespace");

for (;;) {
if (active_ns_nodes.size() == 0) {
fprintf(stderr,
"Internal error: no active namespaces left.\n");
abort();
}
if (active_ns_nodes.back()->ns == ns) {
break;
}
active_ns_nodes.pop_back();
}
std::vector<NSNode *> new_used_nodes;
for (;;) {
if (used_ns_nodes.size() == 0) {
fprintf(stderr,
"Internal error: no used namespaces left.\n");
abort();
}
if (used_ns_nodes.back()->ns == ns) {
break;
}
if (used_ns_nodes.back()->ns->name.compare(0, 4, "anon")) {
new_used_nodes.push_back(used_ns_nodes.back());
}
used_ns_nodes.pop_back();
}
std::reverse(new_used_nodes.begin(), new_used_nodes.end());
std::copy(new_used_nodes.begin(), new_used_nodes.end(),
back_inserter(used_ns_nodes));

return true;
}

bool Context::activateNamespace(const char *name) {
assert(active_ns_nodes.size() && "no active namespace nodes");

Expand Down Expand Up @@ -182,6 +146,26 @@ bool Context::deactivateAnonymousNamespace() {
return true;
}

static int function_scope_count = 0;

int Context::activateFunctionScope() {
int new_scope = ++function_scope_count;
active_function_scopes.push_back(new_scope);
return new_scope;
}

void Context::deactivateFunctionScope(int scope) {
assert((active_function_scopes.size() &&
active_function_scopes.back() == scope)
&& "unmatched function scope");
active_function_scopes.pop_back();
}

int Context::getCurrentFunctionScope() {
if (!active_function_scopes.size()) return -1;
return active_function_scopes.back();
}

NSNode *getNSNodeFromNode(std::vector<std::string> *ns_parts,
NSNode *current) {
for (std::vector<std::string>::iterator b = ns_parts->begin(),
Expand Down
28 changes: 22 additions & 6 deletions src/dale/Context/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class Context {
std::vector<Variable *> retrieved_var;
/*! Functions that have been retrieved. */
std::vector<Function *> retrieved_fn;
/*! Active function scopes. It will be an empty vector for global
* variables. */
std::vector<int> active_function_scopes;

public:
/*! The native types for the context. Used primarily for type
Expand Down Expand Up @@ -87,12 +90,6 @@ class Context {
/*! Get the currently-active namespace.
*/
Namespace *ns();
/*! Pop active namespaces until the given namespace has been
* reached. Does the same thing for used namespaces, save that
* only anonymous namespaces are removed.
* @param ns The namespace that needs to be reached.
*/
bool popUntilNamespace(Namespace *ns);

/*! Activate the namespace with the given name.
* @param name The name of the namespace.
Expand Down Expand Up @@ -135,6 +132,25 @@ class Context {
*/
bool deactivateAnonymousNamespace();

/*! Activate a function scope.
*
* The function scopes is a set of scopes parallel to namespaces,
* and used to catch invalid variable references to a local
* variable in a different function.
* @return The new function scope. The value is guaranteed to be
* positive.
*/
int activateFunctionScope();
/*! Deactivate the current function scope.
* @param scope The function scope to deactivate.
*/
void deactivateFunctionScope(int scope);
/*! Get the current active scope.
* @return Returns -1 if currently it's outside of any function
* scope (i.e. the function scope of global variables).
*/
int getCurrentFunctionScope();

/*! Retrieve a namespace node by name.
* @param name The name of the namespace.
* @param ignore_last Whether to ignore the last segment of the
Expand Down
12 changes: 0 additions & 12 deletions src/dale/Form/Proc/Def/Def.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,10 @@ bool typeRequiresExplicitInit(Context *ctx, Type *type) {

llvm::Constant *parseGlobalLiteral(Units *units, Type *type,
Node *node) {
Context *ctx = units->top()->ctx;

std::vector<NSNode *> active_ns_nodes = ctx->active_ns_nodes;
std::vector<NSNode *> used_ns_nodes = ctx->used_ns_nodes;
if (!units->prefunction_ns) {
units->prefunction_ns = ctx->active_ns_nodes.front()->ns;
}
ctx->popUntilNamespace(units->prefunction_ns);

llvm::Constant *init = NULL;
int size;
init = FormValueParse(units, type, node, &size);

ctx->active_ns_nodes = active_ns_nodes;
ctx->used_ns_nodes = used_ns_nodes;

return init;
}

Expand Down
12 changes: 0 additions & 12 deletions src/dale/Form/Proc/Inst/Inst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,6 @@ bool createAnonymousFunction(Units *units, llvm::BasicBlock *block,
Context *ctx = units->top()->ctx;
int preindex = ctx->lv_index;

std::vector<NSNode *> active_ns_nodes = ctx->active_ns_nodes;
std::vector<NSNode *> used_ns_nodes = ctx->used_ns_nodes;
if (!units->prefunction_ns) {
units->prefunction_ns = ctx->active_ns_nodes.front()->ns;
}
ctx->popUntilNamespace(units->prefunction_ns);

int error_count_begin =
ctx->er->getErrorTypeCount(ErrorType::Error);

Expand All @@ -49,8 +42,6 @@ bool createAnonymousFunction(Units *units, llvm::BasicBlock *block,
int error_count_end = ctx->er->getErrorTypeCount(ErrorType::Error);

if (error_count_begin != error_count_end) {
ctx->active_ns_nodes = active_ns_nodes;
ctx->used_ns_nodes = used_ns_nodes;
return false;
}

Expand All @@ -76,9 +67,6 @@ bool createAnonymousFunction(Units *units, llvm::BasicBlock *block,
(*b)->index = 0;
}

ctx->active_ns_nodes = active_ns_nodes;
ctx->used_ns_nodes = used_ns_nodes;

return true;
}

Expand Down
6 changes: 6 additions & 0 deletions src/dale/Form/ProcBody/ProcBody.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ bool FormProcBodyParse(Units *units, Node *node, Function *fn,
llvm::Function *llvm_fn, int skip,
bool is_anonymous, llvm::Value *return_value) {
Context *ctx = units->top()->ctx;
int fnscope = ctx->activateFunctionScope();

std::vector<Node *> *lst = node->list;

Expand Down Expand Up @@ -372,6 +373,7 @@ bool FormProcBodyParse(Units *units, Node *node, Function *fn,
bool res = Operation::Copy(units->top()->ctx, fn, (*b),
&res_pr, &res_pr);
if (!res) {
ctx->deactivateFunctionScope(fnscope);
return false;
}
last_value = res_pr.getValue(ctx);
Expand All @@ -382,6 +384,7 @@ bool FormProcBodyParse(Units *units, Node *node, Function *fn,
bool res =
Operation::Destruct(ctx, &res_pr, &destruct_pr);
if (!res) {
ctx->deactivateFunctionScope(fnscope);
return false;
}
next = destruct_pr.block;
Expand All @@ -391,17 +394,20 @@ bool FormProcBodyParse(Units *units, Node *node, Function *fn,

bool res = resolveDeferredGotos(ctx, node, fn, block);
if (!res) {
ctx->deactivateFunctionScope(fnscope);
return false;
}

res = terminateBlocks(ctx, fn, llvm_fn, last_value, last_type,
last_position);
if (!res) {
ctx->deactivateFunctionScope(fnscope);
return false;
}

removePostTerminators(llvm_fn);
units->top()->popGlobalBlock();
ctx->deactivateFunctionScope(fnscope);

return true;
}
Expand Down
17 changes: 7 additions & 10 deletions src/dale/Form/Value/Value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,13 @@ bool parseFunction(Units *units, Type *type, Node *top, Function *fn) {
nodes.push_back(top);
Node *copy_top = new Node(&nodes);

std::vector<NSNode *> active_ns_nodes = ctx->active_ns_nodes;
std::vector<NSNode *> used_ns_nodes = ctx->used_ns_nodes;
if (!units->prefunction_ns) {
units->prefunction_ns = ctx->active_ns_nodes.front()->ns;
}
ctx->popUntilNamespace(units->prefunction_ns);

units->top()->pushGlobalFunction(fn);
ctx->activateAnonymousNamespace();
std::string anon_name = ctx->ns()->name;
FormProcBodyParse(units, copy_top, fn, llvm_fn, 0, 0);
ctx->deactivateNamespace(anon_name.c_str());
units->top()->popGlobalFunction();

ctx->active_ns_nodes = active_ns_nodes;
ctx->used_ns_nodes = used_ns_nodes;

int error_count_end = ctx->er->getErrorTypeCount(ErrorType::Error);
if (error_count_begin != error_count_end) {
llvm_fn->replaceAllUsesWith(
Expand Down Expand Up @@ -134,12 +124,14 @@ llvm::Function *createCopyFunction(Units *units, Type *type, Node *top,
llvm::Constant *FormValueParse(Units *units, Type *type, Node *top,
int *size) {
Context *ctx = units->top()->ctx;
int fnscope = ctx->activateFunctionScope();

/* Try to parse the value as a literal first. */

ParseResult pr;
bool res = FormLiteralParse(units, type, top, &pr);
if (res) {
ctx->deactivateFunctionScope(fnscope);
return llvm::dyn_cast<llvm::Constant>(pr.getValue(ctx));
}

Expand All @@ -153,10 +145,12 @@ llvm::Constant *FormValueParse(Units *units, Type *type, Node *top,
Function *fn = createFunction(units, type, top);
fn->cto = true;
if (!fn) {
ctx->deactivateFunctionScope(fnscope);
return NULL;
}
res = parseFunction(units, type, top, fn);
if (!res) {
ctx->deactivateFunctionScope(fnscope);
return NULL;
}
std::string name;
Expand Down Expand Up @@ -196,18 +190,21 @@ llvm::Constant *FormValueParse(Units *units, Type *type, Node *top,
fn->llvm_function->eraseFromParent();

if (parsed) {
ctx->deactivateFunctionScope(fnscope);
return parsed;
}

int error_count_end = ctx->er->getErrorTypeCount(ErrorType::Error);
if (error_count_begin != error_count_end) {
ctx->deactivateFunctionScope(fnscope);
return NULL;
}

std::string type_str;
type->toString(&type_str);
Error *e = new Error(CannotParseLiteral, top, type_str.c_str());
ctx->er->addError(e);
ctx->deactivateFunctionScope(fnscope);
return NULL;
}
}
10 changes: 0 additions & 10 deletions src/dale/Introspection/Introspection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -869,20 +869,10 @@ bool eval_2D_expression(MContext *mc, DNode *type_form, DNode *form,

units->top()->makeTemporaryGlobalFunction();

std::vector<NSNode *> active_ns_nodes = ctx->active_ns_nodes;
std::vector<NSNode *> used_ns_nodes = ctx->used_ns_nodes;
if (!units->prefunction_ns) {
units->prefunction_ns = ctx->active_ns_nodes.front()->ns;
}
ctx->popUntilNamespace(units->prefunction_ns);

llvm::Constant *init = NULL;
int size;
init = FormValueParse(units, type, n, &size);

ctx->active_ns_nodes = active_ns_nodes;
ctx->used_ns_nodes = used_ns_nodes;

units->top()->removeTemporaryGlobalFunction();

int error_count_end = ctx->er->getErrorTypeCount(ErrorType::Error);
Expand Down
4 changes: 4 additions & 0 deletions src/dale/Variable/Variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "llvm/Support/raw_ostream.h"

namespace dale {
struct Function;

/*! Variable
A class for storing the details of a variable.
Expand Down Expand Up @@ -42,6 +44,8 @@ class Variable {
int linkage;
/*! Whether the variable should be serialised. */
bool serialise;
/*! The function scope the variable is in */
int fnscope;

Variable();
/*! Construct a new variable with the given name and type.
Expand Down

0 comments on commit 16ce652

Please sign in to comment.