一种路径敏感的数据依赖分析算法

Falcon

  • 1.方法
    • 1.1.Basic Rule
    • 1.2.改进算法
    • 1.3.跨函数分析
  • 2.Evaluation
    • 2.1.设置
    • 2.2.value-flow分析
    • 2.3.Thin Slicing
    • 2.4.Bug Detection
  • 参考文献

这篇工作发表于PLDI 24,提出了一种context- 以semi-path-sensitive的数据依赖分析算法,解决path-sensitive的内存模型中存在的aliasing-path-explosion问题。

1.方法

现有sparse flow-sensitive pointer analysis缺点:

  • 1.auxiliary pre-analysis的精度缺失会导致后续分析大量冗余错误pointer-information的传播。

  • 2.auxiliary pre-analysis只用到了一个point-to集合,而随后的flow-sensitive分析在处理path-sensitive问题时后point-to集合会出现路径爆炸。

为了解决这些问题作者提出了Falcon,Falcon处理的程序语法如下:

请添加图片描述

1.1.Basic Rule

作者定义了两个集合 E E E S S S,还定义了对应的查询方式 ∏ φ \prod_{\varphi} φ

  • E [ p → { . . . } ] E[p \rightarrow \{...\}] E[p{...}] 表示top-level variable p p p 的指向环境集合,每一个环境为 ( φ , o ) (\varphi, o) (φ,o) 表示一个address-taken object及其对应的路径条件。

  • S [ o → { . . . } ] S[o \rightarrow \{...\}] S[o{...}],每一个元素 ( π , l , q ) (\pi, l, q) (π,l,q) 表示top-level variable q q q 在语句 l l l 处路径条件为 π \pi π 时赋值给了 o o ostore 指令)。比如语句 l : ∗ x = q l: *x = q l:x=q,该路径条件 π \pi π x x x 只指向 o o o,那么有 S ( o ) = S ( o ) ∪ ( π , l , q ) S(o) = S(o) \; \cup \; (\pi, l, q) S(o)=S(o)(π,l,q)

  • ∏ φ ( S ( o ) ) = { ( π ∧ φ , l , v ) ∣ ( π , l , v ) ∈ S ( o ) } \prod_{\varphi}(S(o)) = \{(\pi \land \varphi, l, v) \; | \; (\pi, l, v) \in S(o)\} φ(S(o))={(πφ,l,v)(π,l,v)S(o)} 表示address-taken variable o o o 在路径条件 φ \varphi φ 下可能的值。这里值用top-level variable表示,也就是存在value-flow v → φ o v \stackrel{\varphi}{\rightarrow} o vφo

  • ∏ φ ( E ( v ) ) = { ( π ∧ φ , o ) ∣ ( π , o ) ∈ E ( v ) } \prod_{\varphi}(E(v)) = \{(\pi \land \varphi, o)\ \; | \; (\pi, o) \in E(v)\} φ(E(v))={(πφ,o) (π,o)E(v)} 表示top-level variable 在路径条件 π \pi π 下的指向集合。

  • E ( v ) ⨄ E ′ ( v ′ ) = { ( π ∨ π ′ , o ) ∣ ∀ ( π , o ) ∈ E ( v ) , ∀ ( π ′ , o ) ∈ E ′ ( v ′ ) } E(v) \biguplus E^{'}(v^{'}) = \{(\pi \; \vee \; \pi^{'}, o) \; | \; \forall (\pi, o) \in E(v), \forall(\pi^{'}, o) \in E^{'}(v^{'})\} E(v)E(v)={(ππ,o)(π,o)E(v),(π,o)E(v)},表示两个 E E E 集合合并,一个应用的地方就是 Φ \Phi Φ 指令处合并不同的value时,不过关于具体操作paper里说的不是很明确,个人理解是如果 o o o 在两个 E E E 集合处都出现了,那么合并路径条件 π ∨ π ′ \pi \; \vee \; \pi^{'} ππ,反之则相当于 π ∨ f a l s e \pi \; \vee \; false πfalse 或者 f a l s e ∨ π ′ false \vee \; \pi^{'} falseπ

基础的transfer function如下, E , S ⊢ l , φ : s t m t : E ′ , S ′ E, S \vdash l, \varphi : stmt : E^{′}, S^{′} E,Sl,φ:stmt:E,S 表示 E , S E, S E,S 集合经过路径条件 φ \varphi φ 下的语句 l l l 后更新为 E ′ , S ′ E^{′}, S^{′} E,S,其中:

  • alloca 指令 p = & a p = \&a p=&a p p p E E E 集合添加 { φ , a l l o c a a } \{\varphi, alloca_a\} {φ,allocaa}

  • store 指令 ∗ x = q *x = q x=q 更新了 p t s ( x ) pts(x) pts(x) 每个address-taken variable的 S S S 集合。往已有的 S ( o ) S(o) S(o) 集合中添加 ( π , l , q ) (\pi, l, q) (π,l,q) 表示value-flow关系 q → π o q \stackrel{\pi}{\rightarrow} o qπo。同时只有 store 指令会更新 S S S 集合的值,其它只更新 E E E 集合。和SFS类似,如果 ∣ ∏ φ ( E ( x ) ) ∣ = 1 |\prod_{\varphi}(E(x))| = 1 φ(E(x))=1 也就是 x x x 只指向一个address-taken variable ( π , o ) (\pi, o) (π,o),那么对 o o o 进行strong update,这也是kill功能的实现。

  • SequencingBranching 规则表明Falcon可能通过遍历CFG实现(paper没有明说),由于CFG遍历很费时,为了跳过不必要的CFG node,作者后面提出了一个优化方案。

  • load, phi, copy 指令则负责传播指针集合 E E E 的值。其中 load 的最为复杂,个人理解是对于 l , φ : p = ∗ y l, \varphi: p = *y l,φ:p=y,首先 ∏ φ ( E ( y ) ) = { ( π , o ) , . . . } \prod_\varphi(E(y)) = \{(\pi, o),...\} φ(E(y))={(π,o),...} 查询出满足路径条件的所有指向address-taken variable ( π , o ) (\pi, o) (π,o)(此时存在value-flow o → π p o \stackrel{\pi}{\rightarrow} p oπp),由于 load 指令主要是更新 p p p 的指向集 E ( p ) E(p) E(p),因此需要先查询每个 ( π , o ) (\pi, o) (π,o) 的所有值 ∏ π ( S ( o ) ) \prod_\pi(S(o)) π(S(o))(找出所有的 v → φ o v \stackrel{\varphi}{\rightarrow} o vφo),这样找到了value-flow v → φ p v \stackrel{\varphi}{\rightarrow} p vφp,随后合并所有 v v v 的指向集合更新 E ( p ) E(p) E(p)

请添加图片描述

value flow的构建规则如下图所示(value-flow只存在于 store --> load),对于语句 l 1 l_1 l1 处路径条件为 φ 1 \varphi_1 φ1 store 指令 ∗ x = q *x = q x=q,以及语句 l 2 l_2 l2 处路径条件 φ 2 \varphi_2 φ2load 指令 p = ∗ y p = *y p=y,查询路径条件 φ 2 \varphi_2 φ2 y y y 指向的所有address-taken variable ( π i , o i ) (\pi_i, o_i) (πi,oi),通过 ∏ φ i ( S ( o i ) ) \prod_{\varphi_i}(S(o_i)) φi(S(oi)) 查找 φ i \varphi_i φi o i o_i oi 所有可能的值 ( ( φ i , l 1 , q ) (\varphi_i, l_1, q) (φi,l1,q)),也就是value-flow q → φ i o i q \stackrel{\varphi_i}{\rightarrow} o_i qφioi,最后合并所有同source value-flow的路径条件,也就是构造value-flow边 q → ∨ φ i p q \stackrel{\vee \varphi_i}{\rightarrow} p qφip

请添加图片描述
以下图为例,(b)为传统value-flow构建方法, (c)为Falcon,以处理从 store ∗ x = a *x = a x=aload d = ∗ x d = *x d=x 为例,存在 E ( x ) = { ( φ 1 , o 1 ) , ( ¬ φ 1 , o 2 ) } E(x) = \{(\varphi_1, o_1), (\lnot \varphi_1, o_2)\} E(x)={(φ1,o1),(¬φ1,o2)} S ( o 1 ) = { φ 1 , l 1 , a } S(o_1) = \{\varphi_1, l_1, a\} S(o1)={φ1,l1,a} S ( o 2 ) = { ¬ φ 1 , l 2 , a } S(o_2) = \{\lnot \varphi_1, l_2, a\} S(o2)={¬φ1,l2,a} l 1 , l 2 l_1, l_2 l1,l2是占位符)。处理 d = ∗ x d = *x d=x 时query ∏ ¬ φ 2 ( E ( x ) ) \prod_{\lnot \varphi_2}(E(x)) ¬φ2(E(x)),发现 φ 1 ∧ ¬ φ 2 \varphi_1 \land \lnot \varphi_2 φ1¬φ2 ¬ φ 1 ∧ ¬ φ 2 \lnot\varphi_1 \land \lnot \varphi_2 ¬φ1¬φ2 都能满足,因此得到 ∏ ¬ φ 2 ( E ( x ) ) = { ( φ 1 , o 1 ) , ( ¬ φ 1 , o 2 ) } \prod_{\lnot \varphi_2}(E(x)) = \{(\varphi_1, o_1), (\lnot \varphi_1, o_2)\} ¬φ2(E(x))={(φ1,o1),(¬φ1,o2)},接着分别query ∏ φ 1 ( S ( o 1 ) ) \prod_{\varphi_1}(S(o_1)) φ1(S(o1)) ∏ ¬ φ 1 ( S ( o 2 ) ) \prod_{\lnot \varphi_1}(S(o_2)) ¬φ1(S(o2)) 得到 { φ 1 ∧ ¬ φ 2 , l 1 , a } \{\varphi_1 \land \lnot \varphi_2, l_1, a\} {φ1¬φ2,l1,a} { ¬ φ 1 ∧ ¬ φ 2 , l 2 , a } \{\lnot \varphi_1 \land \lnot \varphi_2, l_2, a\} {¬φ1¬φ2,l2,a}。最后得到value-flow a ⟶ ¬ φ 2 d a \stackrel{\lnot \varphi_2}{\longrightarrow} d a¬φ2d(路径条件简化)。与之相比传统方法的value-flow边就多多了。

请添加图片描述

1.2.改进算法

不过目前上图的算法还有优化空间,主要原因包括:

  • 1.直接在CFG上按上面规则进行传播开销过大。而Sparse分析的pre-analysis构建的SVFG包括太多false def-use。因此也会降低性能。

  • 2.大量guard的路径条件需要更新,可能会引起路径爆炸问题,如果严格的对路径条件求解开销过大。

针对问题1作者提出了一个CFG优化方案,主要针对 storeload 的遍历。算法如下图所示(Algo1为 store,Algo2为 load)。优化的重点是 S S S 集合的访问,首先,store 会修改 S S S 的值而 load 会读取其值。

针对问题1,作者优化了 storeload 的遍历规则,其中将 S ( o ) S(o) S(o) 替换为一系列 S l ( o ) S_l(o) Sl(o),表示每个指令 l l l 处address-taken variable o o o 的值。改进后的算法如下图所示,红框为改变处,主要是处理 store 指令时会顺便处理其所有的支配边界,处理 load 时会沿着其直接支配节点回溯。这里需要先进行控制依赖分析。

请添加图片描述
一个示例如下图所示:

  • 在处理 store 语句 l 4 : ∗ x = d l_4: *x = d l4:x=d 时,更新完 S l 4 ( a l l o c m ) S_{l_4}(alloc_m) Sl4(allocm) { ( φ , l 4 , d ) } \{(\varphi, l_4, d)\} {(φ,l4,d)} 后,接着找到 l 4 l_4 l4 的支配边界 l 6 l_6 l6,更新 S l 6 ( a l l o c m ) = { φ , l 4 , d } S_{l_6}(alloc_m) = \{\varphi, l_4, d\} Sl6(allocm)={φ,l4,d}。同理,访问 l 5 l_5 l5 也会做对应的更新。

  • 在处理 load 语句 l 6 : f = ∗ x l_6: f = *x l6:f=x 时, x x x 指向 a l l o c m alloc_m allocm,首先读取 S l 6 ( a l l o c m ) S_{l_6}(alloc_m) Sl6(allocm) 的值,获的 ( φ , l 4 , d ) (\varphi, l_4, d) (φ,l4,d),表示value-flow d ⟶ φ f d \stackrel{\varphi}{\longrightarrow} f dφf;随后,追溯到 l 6 l_6 l6 的直接支配节点 l 3 l_3 l3,读取 ( t r u e , l 3 , c ) (true, l_3, c) (true,l3,c) 的值后,根据Algo2第9行 φ = π ∧ σ ∧ β \varphi = \pi \land \sigma \land \beta φ=πσβ 和第14行 σ = ¬ π ∧ β \sigma = \lnot \pi \land \beta σ=¬πβ 的规则更新为 ( ¬ φ , l 3 , c ) (\lnot \varphi, l_3, c) (¬φ,l3,c),表示value-flow c ⟶ ¬ φ f c \stackrel{\lnot \varphi}{\longrightarrow} f c¬φf c c c 会在 φ \varphi φ 下被kill掉)。根据这两个value-flow更新 E ( f ) E(f) E(f)

请添加图片描述

针对问题2,作者将程序的表达式都抽象为bool skeleton,比如将 x < 2, x >=2, y = 100/2 抽象为布尔谓词 p p p, ¬ p \lnot p ¬p, q q q。其次,Falcon并不使用功能齐全的SAT求解器,而是采用几种线性时间的半决策程序,如unit-propagation,用于识别“简单”的不可满足约束,并执行轻量级的逻辑简化,如消除重言式。在实验中,作者发现约70%的路径条件是可满足的。对于其余的路径条件,其中80%是简单约束,可以通过半决策程序解决。value-flow边的修剪和合并例子如下图所示。

请添加图片描述

1.3.跨函数分析

与SVF不同,作者依然采用采用一个按照call-graph的拓扑序自底向上先构造每个函数的Value-Flow Graph然后以summary-based方法先构造整体value-flow graph,也就是先独立分析每个函数生成summary,然后按需获取summary进行进一步分析。

通常summary需要注意的是side-effect,对于下图(a)所示代码片段,在对 foo 函数生成摘要时,通常会假设参数 y 指向一个address-taken variable o。按照作者的设定,foo 初始处有 E ( y ) = { ( t r u e , o ) } E(y) = \{(true, o)\} E(y)={(true,o)},分析完整个程序后, S ( o ) = { ( φ , l 2 , c ) , ( ¬ φ , l 3 , a ) } S(o) = \{(\varphi, l_2, c), (\lnot \varphi, l_3, a)\} S(o)={(φ,l2,c),(¬φ,l3,a)}。由于 y y yfoo 和其 caller 的接口,因此 foo 的side-effect只涉及到 y y y,因此 E ( y ) E(y) E(y) S ( o ) S(o) S(o) 就是需要的side-effect。

请添加图片描述
summary最终会在分析call语句的时候用到,这里 quxbar 函数都调用了 foo,同时 quxbar 的参数和 bar 一致,假设在 qux 的调用处, E ( x ) = { ( φ 1 ′ , o 1 ) , ( φ 2 ′ , o 2 ) , ( φ 3 ′ , o 3 ) } E(x) = \{(\varphi^{'}_1, o_1), (\varphi^{'}_2, o_2), (\varphi^{'}_3, o_3)\} E(x)={(φ1,o1),(φ2,o2),(φ3,o3)},那么将summary展开后就有了 S ( o 1 ) = { ( φ ∧ φ 1 ′ , l 2 , c ) , ( ¬ φ ∧ φ 1 ′ , l 3 , a ) } S(o_1) = \{(\varphi \land \varphi^{'}_1, l_2, c), (\lnot \varphi \land \varphi^{'}_1, l_3, a)\} S(o1)={(φφ1,l2,c),(¬φφ1,l3,a)}, S ( o 2 ) = { ( φ ∧ φ 2 ′ , l 2 , c ) , ( ¬ φ ∧ φ 2 ′ , l 3 , a ) } S(o_2) = \{(\varphi \land \varphi^{'}_2, l_2, c), (\lnot \varphi \land \varphi^{'}_2, l_3, a)\} S(o2)={(φφ2,l2,c),(¬φφ2,l3,a)}, S ( o 3 ) = { ( φ ∧ φ 3 ′ , l 2 , c ) , ( ¬ φ ∧ φ 3 ′ , l 3 , a ) } S(o_3) = \{(\varphi \land \varphi^{'}_3, l_2, c), (\lnot \varphi \land \varphi^{'}_3, l_3, a)\} S(o3)={(φφ3,l2,c),(¬φφ3,l3,a)}。如果调用有多层,那么摘要数量可能指数爆炸。

针对这个问题,作者引入了一个辅助变量 R R R,上面 foo 的摘要变成 E ( y ) = { ( t r u e , o ) } E(y) = \{(true, o)\} E(y)={(true,o)}, S ( o ) = { ( t r u e , l 4 , R ) } S(o) = \{(true, l_4, R)\} S(o)={(true,l4,R)}, R = { ( φ , l 2 , c ) , ( ¬ φ , l 3 , a ) } R = \{(\varphi, l_2, c), (\lnot \varphi, l_3, a)\} R={(φ,l2,c),(¬φ,l3,a)}。具体的构造方法如下图所示,在添加辅助变量的同时,对于 void 返回类型,算法还会添加一个额外返回值,示例如上图(b)所示

请添加图片描述
假设分析 foo

  • 独立分析完 foo 后有: E ( y ) = { ( t r u e , o ) } E(y) = \{(true, o)\} E(y)={(true,o)}, S ( o ) = { ( φ , l 2 , c ) , ( ¬ φ , l 3 , a ) } S(o) = \{(\varphi, l_2, c), (\lnot \varphi, l_3, a)\} S(o)={(φ,l2,c),(¬φ,l3,a)}, E ( c ) = { t r u e , j } E(c) = \{true, j\} E(c)={true,j}, E ( a ) = { t r u e , k } E(a) = \{true, k\} E(a)={true,k}。(此时 a a a, c c c 均为一阶指针,对其指向集进行指针分析意义不大,故忽略 k , j k, j k,j 的指向集)。value-flow edge包括: ( c = & j ) → ( ∗ y = c ) (c = \&j) \rightarrow (*y = c) (c=&j)(y=c) ( a = & k ) → ( ∗ y = a ) (a = \&k) \rightarrow (*y = a) (a=&k)(y=a) ( ∗ y = c ) ⟶ φ ( R = ∗ y ) (*y = c) \stackrel{\varphi}{\longrightarrow} (R = *y) (y=c)φ(R=y) ( ∗ y = a ) ⟶ ¬ φ ( R = ∗ y ) (*y = a) \stackrel{\lnot \varphi}{\longrightarrow} (R = *y) (y=a)¬φ(R=y)

  • 用Algo3分析后得到 E ( y ) = { t r u e , o y } E(y) = \{true, o_y\} E(y)={true,oy}( o y o_y oy 为新建object), S ( o y ) = { ( t r u e , , R ) } S(o_y) = \{(true, \; , R)\} S(oy)={(true,,R)} E ( R ) = { ( φ , j ) , ( ¬ φ , k ) } E(R) = \{(\varphi, j), (\lnot \varphi, k)\} E(R)={(φ,j),(¬φ,k)}

利用 f f f 的summary分析caller语句 l , φ : r = f ( u ) l, \varphi: r = f(u) l,φ:r=f(u) 的规则如下,以caller qux 中的 foo(x) 为例,假设 E ( x ) = { ( φ 1 , o 1 ) } E(x) = \{(\varphi_1, o_1)\} E(x)={(φ1,o1)}

  • (1).在callee的summary中替换形参( y y y)和返回值( R R R),构造中间变量 E f ′ ( y ) = { ( φ 1 , o 1 ) } E^{'}_f(y) = \{(\varphi_1, o_1)\} Ef(y)={(φ1,o1)}, S f ′ ( o 1 ) = { ( φ 1 , , R ) } S^{'}_f(o_1) = \{(\varphi_1, , R)\} Sf(o1)={(φ1,,R)} E ( R ) = { ( φ 1 ∧ φ , j ) , ( φ 1 ∧ ¬ φ , k ) } E(R) = \{(\varphi_1 \land \varphi, j), (\varphi_1 \land \lnot \varphi, k)\} E(R)={(φ1φ,j),(φ1¬φ,k)}

  • (2).合并后为 E ′ ( x ) = { ( φ 1 , o 1 ) } E^{'}(x) = \{(\varphi_1, o_1)\} E(x)={(φ1,o1)}, S f ′ ( o 1 ) = { ( φ 1 , , L 1 ) } S^{'}_f(o_1) = \{(\varphi_1, , L_1)\} Sf(o1)={(φ1,,L1)}, E ( L 1 ) = { ( φ 1 ∧ φ , j ) , ( φ 1 ∧ ¬ φ , k ) } E(L_1) = \{(\varphi_1 \land \varphi, j), (\varphi_1 \land \lnot \varphi, k)\} E(L1)={(φ1φ,j),(φ1¬φ,k)}

请添加图片描述在上述示例中,qux 的call语句后面还添加了 store 语句 *x = L1,接着 foo(x) 分析,那么更新了 S ( o 1 ) S(o_1) S(o1) 的值为 { ( φ 1 , l ′ , L 1 ) } \{(\varphi_1, l^{'}, L_1)\} {(φ1,l,L1)}。这里 l ′ l^{'} lstore 语句。

在call分析完后,value-flow中会添加summary edge,主要从callee的return value对应的 store(可能是已有的也可能是新添加的)连接到caller后面的 load 处,在上上张图示例(b)中,foo 结尾插入 R = *y 以及 return R,以及在 quxbar 的caller处添加返回值 L1(还有 L2)以及后面跟着 store 语句 *x = L1 (还有 *z = L2),那么会在新添加的callee的 load 和caller的 store 中间添加一个summary edge。(这里感觉首先需要对IR进行语义等价转换,可能方法和Pinpoint一样)。

2.Evaluation

2.1.设置

下游任务包括:(1).Thin Slicing for Program Understanding、(2).Value-flow Bug Finding: 主要是use-after-free。

baseline包括:

  • (a).指针分析的比较对比:(1).SVF (主要是SVF实现的Andersen算法)、(2).SFS(稀疏值流分析)、(3).DSA (unionfication-based, flow-insensitive, context-sensitive算法,实现采用sea-dsa)

  • (b).slicing与SUPA-FSCS进行对比

  • ©.bug finding与CRED、clang-static-analyzer (CSA) 进行对比。

benchmark采用了6个SPEC INT 2010程序以及10个开源程序。

2.2.value-flow分析

value-flow分析主要对比时间开销,结果如下表和下图所示,SVF、SFS、DSA为baseline,Falcon(PI)和Falcon(SAT)为消融实验,分别表示采用path-insensitive和采用全量SAT进行约束求解的开销。可以看到Falcon的时间开销相比其它方法有着巨大优势。

请添加图片描述

请添加图片描述

2.3.Thin Slicing

为了生成真实的slicing query,作者使用typestate分析提得到的bug report。从对应程序位置的问题变量开始backward分析,结果可以帮助开发人员理解这些报告。主要比较每个slicing query的处理时间(排除value-flow graph的时间),precison和recall。后两者有两位作者进行了人工验证。

时间开销:Falcon对每个slicing query的处理时间少于240ms。总的来说,它比SUPA-FSCS快302倍,平均加速54倍。这一性能提升归因于Falcon生成的value-flow graph比SUPA-FSCS更紧凑。

Precision:Falcon生成的slicing平均大小比SVF、SFS、DSA和SUPA-FSCS分别小5.5倍、1.9倍、2.6倍和1.3倍。表示过滤了很多错误的语句。

Recall:Falcon假设函数参数之间不存在别名,这一不sound的假设对超过90%的query没有影响,经过手动检查结果得到了验证。两项先前的研究也表明,真实世界的C/C++程序中的函数参数往往具有很少的别名关系。

2.4.Bug Detection

use-after-free bug检测的结果如下图所示,分别对比了时间开销和误报率。可以看出,Falcon在大多数大规模程序中超越了CRED和CSA,平均速度提升分别达到10.3倍和1620.8倍(以工具完成的项目为基准)。尽管表中未显示,但作者观察到,如果允许10个线程并发分析,Falcon可以在两小时内完成每个程序的检查。CRED、CSA和Falcon的虚假正例率分别为40.0%、33.3%和27.8%。我们注意到,CSA报告的警告明显少于CRED和Falcon,部分原因是频繁超时和在跨编译单元分析路径时能力有限。Falcon符合工业界对30%误报率的常见要求。

请添加图片描述

参考文献

[1].Yao P, Zhou J, Xiao X, et al. Falcon: A Fused Approach to Path-Sensitive Sparse Data Dependence Analysis[J]. Proceedings of the ACM on Programming Languages, 2024, 8(PLDI): 567-592.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/437943.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css中背景色、背景图的使用

1、同时使用背景色、背景图片 参考链接&#xff1a;链接 以下样式&#xff0c;背景色在图片下方(缺点&#xff1a;图片不透明时&#xff0c;背景色会被完全遮挡。) .header {height: 100%;width: 100%;background-color: #000;background-image: url(/static/images/back.pn…

thinkphp6开发的通用网站系统源码

thinkphp6开发的通用网站系统源码。 基于ThinkPHP6框架开发的通用后台权限管理系统&#xff0c;底层采用国内最流行的ThinkPHP6框架&#xff0c; 支持内容管理、文章管理、用户管理、权限管理、角色管理等功能。 代码下载百度网盘

jenkins部署Maven和NodeJS项目

在 Java 项目开发中&#xff0c;项目的编译、测试、打包等是比较繁琐的&#xff0c;属于重复劳动的工作&#xff0c;浪费人力和时间成本。以往开发项目时&#xff0c;程序员往往需要花较多的精力在引用 jar 包搭建项目环境上&#xff0c;跨部门甚至跨人员之间的项目结构都有可能…

基于SSM的宿舍管理系统 (源码+定制+文档)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

【MAUI】CommunityToolkit社区工具包介绍

一、为什么需要声明式开发 .NET的MVVM,始于WPF,很古典,它甚至可能是现代前端框架“声明式开发”的鼻祖。声明式开发,之所以出现,是因为命令式开发在UI层和代码层上无法解耦的问题。如下图所示: 1、命令式开发:后台代码需要调用UI层的控件(label.Text),如果更新UI层…

stm32 bootloader跳转程序设计

文章目录 1、bootloader跳转程序设计&#xff08;1&#xff09;跳转程序&#xff08;2&#xff09;、app程序中需要注意<1>、在keil中ROM起始地址和分配的空间大小<2>、在system_stm32f4xx.c中设置VECT_TAB_OFFSET为需要偏移的地址<3>、main函数中使能中断 总…

C初阶(六)--- static 来喽

前言&#xff1a;C语言中有许多关键字&#xff08;关键字是预先保留的标识符&#xff0c;具有特殊意义&#xff0c;不能用作变量 名、函数名等普通标识符。&#xff09; 比如&#xff1a;前面在变量与常量那一节提到的extern 就是一个关键字&#xff0c;应该还记得e…

Grafana链接iframe嵌入Web前端一直跳登录页面的问题记录

概述 公司有个项目使用到Grafana作为监控界面,因为项目方的环境极其复杂,仅物理隔离的环境就有三四个,而且每个都得部署项目,今天在某个环境测试,查看界面遇到一个比较奇怪的Grafana问题,后面针对该问题进行跟踪分析并解决,故而博文记录,用于备忘。 问题 登录项目We…

Pikachu-Sql Inject-insert/update/delete注入

insert 注入 插入语句 insert into tables values(value1,value2,value3); 如&#xff1a;插入用户表 insert into users (id,name,password) values (id,username,password); 当点击注册 先判断是否有SQL注入漏洞&#xff0c;经过判断之后发现存在SQL漏洞。构造insert的pa…

Redis 篇-深入了解在 Linux 的 Redis 网络模型结构及其流程(阻塞 IO、非阻塞 IO、IO 多路复用、异步 IO、信号驱动 IO)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 用户空间与内核空间概述 2.0 Redis 网络模型 2.1 Redis 网络模型 - 阻塞 IO 2.2 Redis 网络模型 - 非阻塞 IO 2.3 Redis 网络模型 - IO 多路复用 2.3.1 IO 多路复…

【mmengine】配置器(config)(入门)读取与使用

一、 介绍 MMEngine 实现了抽象的配置类&#xff08;Config&#xff09;&#xff0c;为用户提供统一的配置访问接口。 配置类能够支持不同格式的配置文件&#xff0c;包括 python&#xff0c;json&#xff0c;yaml&#xff0c;用户可以根据需求选择自己偏好的格式。 配置类提供…

【网路通信基础与实践番外二】TCP协议的流量控制和拥塞控制以及二者区别和例题

TCP协议是端对端的协议&#xff0c;因此在数据进行传输的过程受发送方&#xff0c;数据通道&#xff0c;接收方三方状态的影响。我们用水龙头来比喻数据发送方&#xff0c;水管来比喻数据通道&#xff0c;水桶来表示数据接收方。 图(a)表示水桶太小&#xff0c;来不及接受注入…

Unity实战案例全解析:RTS游戏的框选和阵型功能(3)生成范围检测框 +重置框选操作

前篇&#xff1a;Unity实战案例全解析&#xff1a;RTS游戏的框选和阵型功能&#xff08;2&#xff09; 生成选择框-CSDN博客 本案例来源于unity唐老狮&#xff0c;有兴趣的小伙伴可以去泰克在线观看该课程 我只是对重要功能进行分析和做出笔记分享&#xff0c;并未无师自通&…

给出向量求叉乘(在垂直的时候可以简化)

1、可以用那个求行列式的方法求叉乘。 2、在两个向量垂直的时候&#xff0c;可以用简化方法&#xff0c;前面幅度相乘&#xff0c;然后ex叉乘ey是ez 注意叉乘结果无论原向量是不是垂直&#xff0c;叉乘结果都与两个向量垂直

深入探秘 Java 网络编程:从基础到多线程服务器的全方位指南

我的主页&#xff1a;2的n次方_ Java 作为一门功能强大的编程语言&#xff0c;不仅在桌面应用、移动开发、后端开发等领域表现出色&#xff0c;还在网络编程中拥有广泛的应用。网络编程涉及在两个或多个设备之间通过网络进行通信&#xff0c;这对于构建分布式系统、客户端…

【Linux】进程管理:状态与优先级调度的深度分析

✨ 山海自有归期&#xff0c;风雨自有相逢 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;Linux—登神长阶 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1…

spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)

文章目录 【README】【1】文件上传与MultipartResolver【1.1】使用MultipartResolver进行文件上传【1.2】springmvc处理multipart多部件请求流程【1.3】使用springmvc上传文件代码实现&#xff08;springmvc6.10版本&#xff09;&#xff1a; 【2】Handler与HandlerAdaptor&…

stm32单片机学习 - MDK仿真调试

1 进行环境配置 点击 Options for Target&#xff0c;也就是我们俗称的魔法棒。 将"C/C"中的Optimization选项选为Level 0(-O0) 作用:优化等级调为0级,便于调试时分析代码 勾选"Debug"中的Load Application at Starup 和 Run to main() 选项 作用:Load…

Emergency Stop (ES)

文章目录 1. 介绍2. Feature List3. 紧急停止信号触发方式3.1 Port触发紧急停止信号3.2 SMU事件触发紧急停止信号3.3 软件触发紧急停止信号 4. 应用场景4.1 Port4.2 MSC 1. 介绍 Emergency Stop (ES)是Ifx System Control Units (SCU)六大模块之一。详细信息可以参考Infineon-…

latex有哪些颜色中文叫什么,Python绘制出来

latex有哪些颜色中文叫什么&#xff0c;Python绘制出来 为了展示xcolor包预定义的颜色及其对应的中文名称&#xff0c;并使用Python打印出来&#xff0c;我们可以先列出常见的预定义颜色名称&#xff0c;然后将它们翻译成中文&#xff0c;并最后用Python打印出来。 步骤 列出…