aboutsummaryrefslogtreecommitdiff
path: root/src/server/analysis.odin
diff options
context:
space:
mode:
authorDaniel Gavin <danielgavin5@hotmail.com>2022-10-23 15:45:01 +0200
committerDaniel Gavin <danielgavin5@hotmail.com>2022-10-23 15:45:01 +0200
commitfe4d819a865b92118584ee5fbc0609e59ad8b2fb (patch)
treebcc70af39409493857f168892479b8c6497954df /src/server/analysis.odin
parentb7f489b4215b922a40fa88417e1ed777a2690a49 (diff)
Try to use recursion map on pointers to prevent stackoverflow crashes
Diffstat (limited to 'src/server/analysis.odin')
-rw-r--r--src/server/analysis.odin214
1 files changed, 131 insertions, 83 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index c7081c5..2630b79 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -70,28 +70,28 @@ DocumentLocal :: struct {
}
AstContext :: struct {
- locals: map[int]map[string][dynamic]DocumentLocal, //locals all the way to the document position
- globals: map[string]common.GlobalExpr,
- variables: map[string]bool,
- parameters: map[string]bool,
- in_package: map[string]string, //sometimes you have to extract types from arrays/maps and you lose package information
- usings: [dynamic]string,
- file: ast.File,
- allocator: mem.Allocator,
- imports: []Package, //imports for the current document
- current_package: string,
- document_package: string,
- use_globals: bool,
- use_locals: bool,
- local_id: int,
- call: ^ast.Call_Expr, //used to determene the types for generics and the correct function for overloaded functions
- position: common.AbsolutePosition,
- value_decl: ^ast.Value_Decl,
- field_name: ast.Ident,
- uri: string,
- fullpath: string,
- recursion_counter: int, //Sometimes the ast is so malformed that it causes infinite recursion.
- non_mutable_only: bool,
+ locals: map[int]map[string][dynamic]DocumentLocal, //locals all the way to the document position
+ globals: map[string]common.GlobalExpr,
+ variables: map[string]bool,
+ parameters: map[string]bool,
+ in_package: map[string]string, //sometimes you have to extract types from arrays/maps and you lose package information
+ recursion_map: map[rawptr]bool,
+ usings: [dynamic]string,
+ file: ast.File,
+ allocator: mem.Allocator,
+ imports: []Package, //imports for the current document
+ current_package: string,
+ document_package: string,
+ use_globals: bool,
+ use_locals: bool,
+ local_id: int,
+ call: ^ast.Call_Expr, //used to determene the types for generics and the correct function for overloaded functions
+ position: common.AbsolutePosition,
+ value_decl: ^ast.Value_Decl,
+ field_name: ast.Ident,
+ uri: string,
+ fullpath: string,
+ non_mutable_only: bool,
}
make_ast_context :: proc(
@@ -113,6 +113,7 @@ make_ast_context :: proc(
usings = make([dynamic]string, allocator),
parameters = make(map[string]bool, 0, allocator),
in_package = make(map[string]string, 0, allocator),
+ recursion_map = make(map[rawptr]bool, 0, allocator),
file = file,
imports = imports,
use_locals = true,
@@ -129,6 +130,12 @@ make_ast_context :: proc(
return ast_context
}
+reset_ast_context :: proc(ast_context: ^AstContext) {
+ ast_context.use_globals = true
+ ast_context.use_locals = true
+ clear(&ast_context.recursion_map)
+}
+
tokenizer_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) {
}
@@ -1029,12 +1036,26 @@ resolve_basic_directive :: proc(
)
ident.name = "Source_Code_Location"
ast_context.current_package = ast_context.document_package
- return resolve_type_identifier(ast_context, ident^)
+ return internal_resolve_type_identifier(ast_context, ident^)
}
return {}, false
}
+check_node_recursion :: proc(
+ ast_context: ^AstContext,
+ node: ^ast.Node,
+) -> bool {
+ raw := cast(rawptr)node
+
+ if raw in ast_context.recursion_map {
+ return true
+ }
+
+ ast_context.recursion_map[raw] = true
+
+ return false
+}
resolve_type_expression :: proc(
ast_context: ^AstContext,
@@ -1043,6 +1064,17 @@ resolve_type_expression :: proc(
Symbol,
bool,
) {
+ clear(&ast_context.recursion_map)
+ return internal_resolve_type_expression(ast_context, node)
+}
+
+internal_resolve_type_expression :: proc(
+ ast_context: ^AstContext,
+ node: ^ast.Expr,
+) -> (
+ Symbol,
+ bool,
+) {
if node == nil {
return {}, false
}
@@ -1053,25 +1085,19 @@ resolve_type_expression :: proc(
ast_context.current_package = saved_package
}
- if ast_context.recursion_counter > 200 {
- log.error("Recursion passed 200 attempts - giving up", node)
+ if check_node_recursion(ast_context, node) {
+ log.error("Recursion detected")
return {}, false
}
- ast_context.recursion_counter += 1
-
- defer {
- ast_context.recursion_counter -= 1
- }
-
using ast
#partial switch v in node.derived {
case ^ast.Value_Decl:
if v.type != nil {
- return resolve_type_expression(ast_context, v.type)
+ return internal_resolve_type_expression(ast_context, v.type)
} else if len(v.values) > 0 {
- return resolve_type_expression(ast_context, v.values[0])
+ return internal_resolve_type_expression(ast_context, v.values[0])
}
case ^Union_Type:
return make_symbol_union_from_ast(
@@ -1150,47 +1176,49 @@ resolve_type_expression :: proc(
case ^Basic_Lit:
return resolve_basic_lit(ast_context, v^)
case ^Type_Cast:
- return resolve_type_expression(ast_context, v.type)
+ return internal_resolve_type_expression(ast_context, v.type)
case ^Auto_Cast:
- return resolve_type_expression(ast_context, v.expr)
+ return internal_resolve_type_expression(ast_context, v.expr)
case ^Comp_Lit:
- return resolve_type_expression(ast_context, v.type)
+ return internal_resolve_type_expression(ast_context, v.type)
case ^Unary_Expr:
if v.op.kind == .And {
- symbol, ok := resolve_type_expression(ast_context, v.expr)
+ symbol, ok := internal_resolve_type_expression(ast_context, v.expr)
symbol.pointers += 1
return symbol, ok
} else {
- return resolve_type_expression(ast_context, v.expr)
+ return internal_resolve_type_expression(ast_context, v.expr)
}
case ^Deref_Expr:
- symbol, ok := resolve_type_expression(ast_context, v.expr)
+ symbol, ok := internal_resolve_type_expression(ast_context, v.expr)
symbol.pointers -= 1
return symbol, ok
case ^Paren_Expr:
- return resolve_type_expression(ast_context, v.expr)
+ return internal_resolve_type_expression(ast_context, v.expr)
case ^Slice_Expr:
- return resolve_type_expression(ast_context, v.expr)
+ return internal_resolve_type_expression(ast_context, v.expr)
case ^Tag_Expr:
- return resolve_type_expression(ast_context, v.expr)
+ return internal_resolve_type_expression(ast_context, v.expr)
case ^Helper_Type:
- return resolve_type_expression(ast_context, v.type)
+ return internal_resolve_type_expression(ast_context, v.type)
case ^Ellipsis:
- return resolve_type_expression(ast_context, v.expr)
+ return internal_resolve_type_expression(ast_context, v.expr)
case ^Implicit:
ident := new_type(Ident, v.node.pos, v.node.end, ast_context.allocator)
ident.name = v.tok.text
- return resolve_type_identifier(ast_context, ident^)
+ return internal_resolve_type_identifier(ast_context, ident^)
case ^Type_Assertion:
if unary, ok := v.type.derived.(^ast.Unary_Expr); ok {
if unary.op.kind == .Question {
- if symbol, ok := resolve_type_expression(ast_context, v.expr);
- ok {
+ if symbol, ok := internal_resolve_type_expression(
+ ast_context,
+ v.expr,
+ ); ok {
if union_value, ok := symbol.value.(SymbolUnionValue); ok {
if len(union_value.types) != 1 {
return {}, false
}
- return resolve_type_expression(
+ return internal_resolve_type_expression(
ast_context,
union_value.types[0],
)
@@ -1198,23 +1226,23 @@ resolve_type_expression :: proc(
}
}
} else {
- return resolve_type_expression(ast_context, v.type)
+ return internal_resolve_type_expression(ast_context, v.type)
}
case ^Proc_Lit:
if v.type.results != nil {
if len(v.type.results.list) == 1 {
- return resolve_type_expression(
+ return internal_resolve_type_expression(
ast_context,
v.type.results.list[0].type,
)
}
}
case ^Pointer_Type:
- symbol, ok := resolve_type_expression(ast_context, v.elem)
+ symbol, ok := internal_resolve_type_expression(ast_context, v.elem)
symbol.pointers += 1
return symbol, ok
case ^Index_Expr:
- indexed, ok := resolve_type_expression(ast_context, v.expr)
+ indexed, ok := internal_resolve_type_expression(ast_context, v.expr)
if !ok {
return {}, false
@@ -1224,15 +1252,18 @@ resolve_type_expression :: proc(
#partial switch v2 in indexed.value {
case SymbolDynamicArrayValue:
- symbol, ok = resolve_type_expression(ast_context, v2.expr)
+ symbol, ok = internal_resolve_type_expression(ast_context, v2.expr)
case SymbolSliceValue:
- symbol, ok = resolve_type_expression(ast_context, v2.expr)
+ symbol, ok = internal_resolve_type_expression(ast_context, v2.expr)
case SymbolFixedArrayValue:
- symbol, ok = resolve_type_expression(ast_context, v2.expr)
+ symbol, ok = internal_resolve_type_expression(ast_context, v2.expr)
case SymbolMapValue:
- symbol, ok = resolve_type_expression(ast_context, v2.value)
+ symbol, ok = internal_resolve_type_expression(
+ ast_context,
+ v2.value,
+ )
case SymbolMultiPointer:
- symbol, ok = resolve_type_expression(ast_context, v2.expr)
+ symbol, ok = internal_resolve_type_expression(ast_context, v2.expr)
}
symbol.type = indexed.type
@@ -1240,13 +1271,16 @@ resolve_type_expression :: proc(
return symbol, ok
case ^Call_Expr:
ast_context.call = cast(^Call_Expr)node
- return resolve_type_expression(ast_context, v.expr)
+ return internal_resolve_type_expression(ast_context, v.expr)
case ^Implicit_Selector_Expr:
return Symbol{}, false
case ^Selector_Call_Expr:
- return resolve_type_expression(ast_context, v.expr)
+ return internal_resolve_type_expression(ast_context, v.expr)
case ^Selector_Expr:
- if selector, ok := resolve_type_expression(ast_context, v.expr); ok {
+ if selector, ok := internal_resolve_type_expression(
+ ast_context,
+ v.expr,
+ ); ok {
ast_context.use_locals = false
#partial switch s in selector.value {
@@ -1276,7 +1310,10 @@ resolve_type_expression :: proc(
ast_context.current_package =
ast_context.document_package
}
- symbol, ok := resolve_type_expression(ast_context, s.expr)
+ symbol, ok := internal_resolve_type_expression(
+ ast_context,
+ s.expr,
+ )
symbol.type = .Variable
return symbol, ok
} else {
@@ -1303,7 +1340,10 @@ resolve_type_expression :: proc(
)
selector_expr.expr = s.return_types[0].type
selector_expr.field = v.field
- return resolve_type_expression(ast_context, selector_expr)
+ return internal_resolve_type_expression(
+ ast_context,
+ selector_expr,
+ )
}
case SymbolStructValue:
if selector.pkg != "" {
@@ -1315,7 +1355,7 @@ resolve_type_expression :: proc(
for name, i in s.names {
if v.field != nil && name == v.field.name {
ast_context.field_name = v.field^
- symbol, ok := resolve_type_expression(
+ symbol, ok := internal_resolve_type_expression(
ast_context,
s.types[i],
)
@@ -1341,7 +1381,7 @@ resolve_type_expression :: proc(
return Symbol{}, false
}
case:
- log.warnf("default node kind, resolve_type_expression: %T", v)
+ log.warnf("default node kind, internal_resolve_type_expression: %T", v)
if v == nil {
return {}, false
}
@@ -1474,10 +1514,21 @@ resolve_type_identifier :: proc(
Symbol,
bool,
) {
+ clear(&ast_context.recursion_map)
+ return internal_resolve_type_identifier(ast_context, node)
+}
+
+internal_resolve_type_identifier :: proc(
+ ast_context: ^AstContext,
+ node: ast.Ident,
+) -> (
+ Symbol,
+ bool,
+) {
using ast
- if ast_context.recursion_counter > 200 {
- log.error("Recursion passed 200 attempts - giving up", node)
+ if check_node_recursion(ast_context, node.derived.(^ast.Ident)) {
+ log.error("Recursion detected")
return {}, false
}
@@ -1487,12 +1538,6 @@ resolve_type_identifier :: proc(
ast_context.current_package = saved_package
}
- ast_context.recursion_counter += 1
-
- defer {
- ast_context.recursion_counter -= 1
- }
-
if pkg, ok := ast_context.in_package[node.name]; ok {
ast_context.current_package = pkg
}
@@ -1561,7 +1606,10 @@ resolve_type_identifier :: proc(
#partial switch v in local.derived {
case ^Ident:
- return_symbol, ok = resolve_type_identifier(ast_context, v^)
+ return_symbol, ok = internal_resolve_type_identifier(
+ ast_context,
+ v^,
+ )
case ^Union_Type:
return_symbol, ok =
make_symbol_union_from_ast(ast_context, v^, node), true
@@ -1655,7 +1703,10 @@ resolve_type_identifier :: proc(
#partial switch v in global.expr.derived {
case ^Ident:
- return_symbol, ok = resolve_type_identifier(ast_context, v^)
+ return_symbol, ok = internal_resolve_type_identifier(
+ ast_context,
+ v^,
+ )
case ^Struct_Type:
return_symbol, ok =
make_symbol_struct_from_ast(ast_context, v^, node), true
@@ -1713,7 +1764,7 @@ resolve_type_identifier :: proc(
return_symbol.name = node.name
return_symbol.type = global.mutable ? .Variable : .Constant
case:
- return_symbol, ok = resolve_type_expression(
+ return_symbol, ok = internal_resolve_type_expression(
ast_context,
global.expr,
)
@@ -2013,8 +2064,7 @@ resolve_location_selector :: proc(
Symbol,
bool,
) {
- ast_context.use_locals = true
- ast_context.use_globals = true
+ reset_ast_context(ast_context)
ast_context.current_package = ast_context.document_package
symbol, ok := resolve_type_expression(ast_context, selector.expr)
@@ -2657,8 +2707,7 @@ get_generic_assignment :: proc(
) {
using ast
- ast_context.use_locals = true
- ast_context.use_globals = true
+ reset_ast_context(ast_context)
#partial switch v in value.derived {
case ^Or_Return_Expr:
@@ -2788,8 +2837,7 @@ get_locals_stmt :: proc(
document_position: ^DocumentPositionContext,
save_assign := false,
) {
- ast_context.use_locals = true
- ast_context.use_globals = true
+ reset_ast_context(ast_context)
ast_context.current_package = ast_context.document_package
using ast
@@ -3420,8 +3468,8 @@ resolve_entire_decl :: proc(
}
data := cast(^Visit_Data)visitor.data
ast_context := data.ast_context
- ast_context.use_locals = true
- ast_context.use_globals = true
+
+ reset_ast_context(ast_context)
data.last_visit = node