You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测CSharpScript.EvaluateAsync执行的代码是否陷入死循环?

检测并处理CSharpScript执行的无限运行代码

要避免CSharpScript.EvaluateAsync执行无限代码导致应用挂起,可从超时控制、静态代码分析和取消逻辑注入三个维度入手,以下是具体实现方案:


1. 异步超时+取消令牌(最实用的运行时检测)

直接同步调用.Result会阻塞线程,改用带超时的异步等待,结合CancellationTokenSource在超时后终止脚本执行,从根本上避免挂起。

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Scripting;

public static async Task<string> ExecuteScriptWithTimeout(string scriptContent, int timeoutMs)
{
    using var cancellationTokenSource = new CancellationTokenSource(timeoutMs);
    try
    {
        // 传入取消令牌,超时后自动终止脚本
        return await CSharpScript.EvaluateAsync<string>(
            scriptContent,
            cancellationToken: cancellationTokenSource.Token
        );
    }
    catch (OperationCanceledException)
    {
        throw new InvalidOperationException("脚本执行超时,疑似存在无限运行逻辑");
    }
    catch (Exception ex)
    {
        throw new InvalidOperationException("脚本执行失败", ex);
    }
}

// 调用示例
public static void TestScriptExecution()
{
    var endlessScript = @"string Run() { while(true){} return ""1"";} Run()";
    try
    {
        // 设置3秒超时
        var result = ExecuteScriptWithTimeout(endlessScript, 3000).GetAwaiter().GetResult();
        Console.WriteLine($"执行结果:{result}");
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine($"错误:{ex.Message}"); // 输出:脚本执行超时,疑似存在无限运行逻辑
    }
}

2. 静态代码分析(提前检测潜在死循环)

通过Roslyn语法分析器,提前扫描脚本中的无条件循环(如while(true)),在执行前预判风险。这种方式只能检测简单的静态死循环,无法识别依赖运行时变量的动态死循环,适合作为前置校验。

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

public static bool HasPotentialInfiniteLoop(string scriptContent)
{
    var syntaxTree = CSharpSyntaxTree.ParseText(scriptContent);
    var rootNode = syntaxTree.GetRoot();
    
    var loopDetector = new InfiniteLoopSyntaxDetector();
    loopDetector.Visit(rootNode);
    
    return loopDetector.DetectedInfiniteLoop;
}

// 自定义语法遍历器,检测无条件循环
private class InfiniteLoopSyntaxDetector : CSharpSyntaxWalker
{
    public bool DetectedInfiniteLoop { get; private set; }

    public override void VisitWhileStatement(WhileStatementSyntax node)
    {
        base.VisitWhileStatement(node);
        // 检查while条件是否为常量true
        if (node.Condition is LiteralExpressionSyntax literal && 
            literal.IsKind(SyntaxKind.TrueLiteralExpression))
        {
            DetectedInfiniteLoop = true;
        }
    }

    public override void VisitForStatement(ForStatementSyntax node)
    {
        base.VisitForStatement(node);
        // 检查for循环是否无终止条件(无判断条件或条件恒为true)
        if (node.Condition == null || 
            (node.Condition is LiteralExpressionSyntax literal && literal.IsKind(SyntaxKind.TrueLiteralExpression)))
        {
            DetectedInfiniteLoop = true;
        }
    }
}

// 调用示例
var riskyScript = @"string Run() { while(true){} return ""1"";} Run()";
if (HasPotentialInfiniteLoop(riskyScript))
{
    Console.WriteLine("警告:脚本包含潜在无限循环,禁止执行");
}

3. 脚本注入取消逻辑(可选,需修改脚本)

如果允许修改脚本内容,可以在脚本中注入取消令牌检查逻辑,让脚本主动响应终止信号。这种方式需要动态修改用户脚本,适合可控场景:

// 注入取消检查的脚本模板
var templateScript = @"
using System.Threading;
string Run(CancellationToken token) { 
    while(true) {
        token.ThrowIfCancellationRequested(); // 定期检查取消信号
        // 原有逻辑
    } 
    return ""1"";
}
Run(CancellationToken)";

// 执行时传入取消令牌
var result = await CSharpScript.EvaluateAsync<string>(
    templateScript,
    globals: new { CancellationToken = cancellationTokenSource.Token }
);

实际场景中,推荐静态分析前置校验+运行时超时控制的组合方案,既可以提前拦截明显的死循环脚本,又能应对动态产生的无限运行逻辑。

内容的提问来源于stack exchange,提问作者lucidgold

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 20:10:29