在 SQL CLR 中使用 "Unsafe" 有多不安全?

How unsafe can be the usage of "Unsafe" in SQL CLR?

由于客户无法访问 SQL CLR 程序集,因此我们只需要担心我们自己的错误。如果小心使用,"unsafe" 是非常安全的。你怎么看?

"Unsafe" 并不总是谁在执行代码的问题,而是执行什么代码的问题 and/or 它是如何编码的。 UNSAFE 程序集允许代码,即使在理想/正确的使用中,也可以破坏 SQL 服务器的稳定性,或允许安全漏洞,或允许奇怪的/意外的行为。例如,使用 TimeZoneInfo 在时区之间转换时间需要不安全,即使它应该是一个稍微简单的计算。问题在于该代码库中的某处存在导致内存泄漏的原因。尝试对日期列进行批量更新的人都遇到过这种情况。 UNSAFE 也用于 可能 是安全的但尚未经过 Microsoft 验证的代码,因此无法保证。就使用不受支持的 .NET Framework 库而言,这些不仅不能保证按预期工作(或没有内存泄漏或线程安全),而且甚至不能保证它们在任何未来的 .NET Framework 更新中工作(恰当的例子:ServiceModel 在 .NET Framework v 4.0 中成为混合模式,因此从 SQL Server 2012 开始,任何将 ServiceModel 导入 SQL Server 2005、2008 的人, 或 2008 R2 无法再导入它,如果他们想升级 SQL 服务器,则必须重写一堆代码。

但回到问题,当你控制代码时,它有多不安全?您可能不允许任何安全漏洞,但您肯定会陷入内存泄漏和 "odd" 由于共享内存(即静态变量)/同步问题而导致的行为的情况,这些问题确实很难重现和调试。例如,以下是关于 DBA.StackExchange 的一个问题,该错误仅在系统开始更频繁地调用 SQLCLR 函数时才开始发生。问题是由于使用静态变量来存储状态,然后多个会话覆盖值并在他们从该变量读取时返回意外值:

SQLCLR assembly throws error when multiple queries run simultaneously

UNSAFE 程序集可以使用 "safely" 吗?当然。如果您使用静态变量进行缓存,并在它为空时重新加载,那应该没问题。或者,可能 加载不受支持的 .NET Framework 库(几乎总是必须标记为 UNSAFE)但仅在其中使用 "safe" 方法(只是因为程序集的代码是 "unsafe" 并不意味着 "unsafe" 代码将永远被执行)。缺点是:1) 你不知道所有这些库在做什么,即使你确实在 reference.microsoft.com 上查看了其中的一些内容;和 2) 你仍然面临这样的可能性,即在某个时候库将更新为混合模式,然后你必须重写所有内容。