fix use after free for builtin completions (#914)
This commit is contained in:
		
							parent
							
								
									8d53a5382d
								
							
						
					
					
						commit
						4e4761b34c
					
				@ -34,7 +34,7 @@ config: *Config,
 | 
			
		||||
allocator: std.mem.Allocator = undefined,
 | 
			
		||||
arena: *std.heap.ArenaAllocator = undefined,
 | 
			
		||||
document_store: DocumentStore = undefined,
 | 
			
		||||
builtin_completions: std.ArrayListUnmanaged(types.CompletionItem),
 | 
			
		||||
builtin_completions: ?std.ArrayListUnmanaged(types.CompletionItem),
 | 
			
		||||
client_capabilities: ClientCapabilities = .{},
 | 
			
		||||
outgoing_messages: std.ArrayListUnmanaged([]const u8) = .{},
 | 
			
		||||
recording_enabled: bool,
 | 
			
		||||
@ -1289,6 +1289,49 @@ fn populateSnippedCompletions(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn completeBuiltin(server: *Server) error{OutOfMemory}!?[]types.CompletionItem {
 | 
			
		||||
    const tracy_zone = tracy.trace(@src());
 | 
			
		||||
    defer tracy_zone.end();
 | 
			
		||||
 | 
			
		||||
    const allocator = server.arena.allocator();
 | 
			
		||||
 | 
			
		||||
    const builtin_completions = if (server.builtin_completions) |completions|
 | 
			
		||||
        return completions.items
 | 
			
		||||
    else blk: {
 | 
			
		||||
        server.builtin_completions = try std.ArrayListUnmanaged(types.CompletionItem).initCapacity(server.allocator, data.builtins.len);
 | 
			
		||||
        break :blk &server.builtin_completions.?;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for (data.builtins) |builtin| {
 | 
			
		||||
        const insert_text = if (server.config.enable_snippets) builtin.snippet else builtin.name;
 | 
			
		||||
        builtin_completions.appendAssumeCapacity(.{
 | 
			
		||||
            .label = builtin.name,
 | 
			
		||||
            .kind = .Function,
 | 
			
		||||
            .filterText = builtin.name[1..],
 | 
			
		||||
            .detail = builtin.signature,
 | 
			
		||||
            .insertText = if (server.config.include_at_in_builtins) insert_text else insert_text[1..],
 | 
			
		||||
            .insertTextFormat = if (server.config.enable_snippets) .Snippet else .PlainText,
 | 
			
		||||
            .documentation = .{
 | 
			
		||||
                .MarkupContent = .{
 | 
			
		||||
                    .kind = .markdown,
 | 
			
		||||
                    .value = builtin.documentation,
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var completions = try allocator.alloc(types.CompletionItem, builtin_completions.items.len);
 | 
			
		||||
 | 
			
		||||
    if (server.client_capabilities.label_details_support) {
 | 
			
		||||
        for (builtin_completions.items) |item, i| {
 | 
			
		||||
            completions[i] = item;
 | 
			
		||||
            try formatDetailledLabel(&completions[i], allocator);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return completions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn completeGlobal(server: *Server, pos_index: usize, handle: *const DocumentStore.Handle) error{OutOfMemory}![]types.CompletionItem {
 | 
			
		||||
    const tracy_zone = tracy.trace(@src());
 | 
			
		||||
    defer tracy_zone.end();
 | 
			
		||||
@ -1691,14 +1734,6 @@ fn initializeHandler(server: *Server, request: types.InitializeParams) Error!typ
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // NOTE: everything is initialized, we got the client capabilities
 | 
			
		||||
    // so we can now format the prebuilt builtins items for labelDetails
 | 
			
		||||
    if (server.client_capabilities.label_details_support) {
 | 
			
		||||
        for (server.builtin_completions.items) |*item| {
 | 
			
		||||
            try formatDetailledLabel(item, server.arena.allocator());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (request.capabilities.workspace) |workspace| {
 | 
			
		||||
        server.client_capabilities.supports_apply_edits = workspace.applyEdit orelse false;
 | 
			
		||||
        server.client_capabilities.supports_configuration = workspace.configuration orelse false;
 | 
			
		||||
@ -2067,7 +2102,7 @@ fn completionHandler(server: *Server, request: types.CompletionParams) Error!?ty
 | 
			
		||||
    const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.text, source_index);
 | 
			
		||||
 | 
			
		||||
    const maybe_completions = switch (pos_context) {
 | 
			
		||||
        .builtin => server.builtin_completions.items,
 | 
			
		||||
        .builtin => try server.completeBuiltin(),
 | 
			
		||||
        .var_access, .empty => try server.completeGlobal(source_index, handle),
 | 
			
		||||
        .field_access => |loc| try server.completeFieldAccess(handle, source_index, loc),
 | 
			
		||||
        .global_error_set => try server.completeError(handle),
 | 
			
		||||
@ -3008,7 +3043,8 @@ fn processMessage(server: *Server, message: Message) Error!void {
 | 
			
		||||
            return error.InvalidRequest; // server received a request after shutdown!
 | 
			
		||||
        },
 | 
			
		||||
        .exiting_success,
 | 
			
		||||
        .exiting_failure, => unreachable,
 | 
			
		||||
        .exiting_failure,
 | 
			
		||||
        => unreachable,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const start_time = std.time.milliTimestamp();
 | 
			
		||||
@ -3116,32 +3152,11 @@ pub fn init(
 | 
			
		||||
    };
 | 
			
		||||
    errdefer document_store.deinit();
 | 
			
		||||
 | 
			
		||||
    var builtin_completions = try std.ArrayListUnmanaged(types.CompletionItem).initCapacity(allocator, data.builtins.len);
 | 
			
		||||
    errdefer builtin_completions.deinit(allocator);
 | 
			
		||||
 | 
			
		||||
    for (data.builtins) |builtin| {
 | 
			
		||||
        const insert_text = if (config.enable_snippets) builtin.snippet else builtin.name;
 | 
			
		||||
        builtin_completions.appendAssumeCapacity(.{
 | 
			
		||||
            .label = builtin.name,
 | 
			
		||||
            .kind = .Function,
 | 
			
		||||
            .filterText = builtin.name[1..],
 | 
			
		||||
            .detail = builtin.signature,
 | 
			
		||||
            .insertText = if (config.include_at_in_builtins) insert_text else insert_text[1..],
 | 
			
		||||
            .insertTextFormat = if (config.enable_snippets) .Snippet else .PlainText,
 | 
			
		||||
            .documentation = .{
 | 
			
		||||
                .MarkupContent = .{
 | 
			
		||||
                    .kind = .markdown,
 | 
			
		||||
                    .value = builtin.documentation,
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return Server{
 | 
			
		||||
        .config = config,
 | 
			
		||||
        .allocator = allocator,
 | 
			
		||||
        .document_store = document_store,
 | 
			
		||||
        .builtin_completions = builtin_completions,
 | 
			
		||||
        .builtin_completions = null,
 | 
			
		||||
        .recording_enabled = recording_enabled,
 | 
			
		||||
        .replay_enabled = replay_enabled,
 | 
			
		||||
        .status = .uninitialized,
 | 
			
		||||
@ -3152,7 +3167,7 @@ pub fn deinit(server: *Server) void {
 | 
			
		||||
    server.document_store.deinit();
 | 
			
		||||
    analysis.deinit();
 | 
			
		||||
 | 
			
		||||
    server.builtin_completions.deinit(server.allocator);
 | 
			
		||||
    if (server.builtin_completions) |*completions| completions.deinit(server.allocator);
 | 
			
		||||
 | 
			
		||||
    for (server.outgoing_messages.items) |message| {
 | 
			
		||||
        server.allocator.free(message);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user