当前位置: 首页 > news >正文

PTA算法简析

ArkAnalyzer源码初步分析I:https://blog.csdn.net/2302_80118884/article/details/151627341?spm=1001.2014.3001.5501

首先,我们必须明确 PTA 的核心工作:它不再关心变量的“声明类型”,而是为程序中的每一个变量每一个对象字段维护一个**“指向集”(Points-to Set)。这个集合里包含了该变量可能指向的所有对象实例**。分析过程就是通过代码语句,不断更新和传递这些“指向集”。

我们还是使用 Animal 的例子,但这次会引入更复杂的结构。

// --- 我们的基础类 ---
abstract class Animal { abstract sound(): void; }
class Dog extends Animal { sound() { /* 汪汪 */ } }
class Cat extends Animal { sound() { /* 喵喵 */ } }
class Pig extends Animal { sound() { /* 哼哼 */ } } // Pig 还是存在,但我们看看 PTA 能否排除它// --- 更复杂的业务逻辑 ---
class PetStore {bestSeller: Animal | null = null;inventory: Animal[] = [];setBestSeller(pet: Animal) {this.bestSeller = pet;}stockInventory(pets: Animal[]) {this.inventory = pets;}promoteBestSeller() {if (this.bestSeller) {this.bestSeller.sound();}}
}function choosePet(isMorning: boolean): Animal {let chosenPet: Animal;if (isMorning) {chosenPet = new Dog();} else {chosenPet = new Cat();}return chosenPet;
}

现在,让我们分析一个使用这些复杂结构的 main 函数。

场景 1: 通过对象字段(Field Assignments)传递

代码:

function main1() {const store = new PetStore();const myDog = new Dog();// 1. 将 Dog 实例设置到 store 的字段中store.setBestSeller(myDog);// 2. 调用一个方法,该方法会使用这个字段store.promoteBestSeller(); 
}

PTA 分析过程:

  1. const store = new PetStore();

    • PTA 创建一个 PetStore 的实例,我们称之为 PetStore_obj1
    • 它的“指向集账本”记录:store -> { PetStore_obj1 }
  2. const myDog = new Dog();

    • PTA 创建一个 Dog 的实例,称之为 Dog_obj1
    • 账本记录:myDog -> { Dog_obj1 }
  3. store.setBestSeller(myDog);

    • 这是一个方法调用。PTA 会分析 setBestSeller 内部。
    • 内部执行 this.bestSeller = pet;
    • PTA 知道,this 指向 store (即 PetStore_obj1),参数 pet 指向 myDog (即 Dog_obj1)。
    • 于是,它执行了一次数据流传递:将 pet 的指向集 { Dog_obj1 } 赋给了 this.bestSeller 字段。
    • 账本更新:PetStore_obj1.bestSeller -> { Dog_obj1 }
  4. store.promoteBestSeller();

    • PTA 进入 promoteBestSeller 方法,this 仍然指向 PetStore_obj1
    • 分析到 this.bestSeller.sound();
    • PTA 查询 this.bestSeller 的指向集。账本上写着:PetStore_obj1.bestSeller -> { Dog_obj1 }
    • 结论: 指向集里只有一个 Dog 对象。因此,这里的 sound() 调用唯一的目标就是 Dog.sound()

对比 RTA: 如果 RTA 看到代码里别处有 new Cat(),它可能会错误地认为 this.bestSeller.sound() 也可能调用 Cat.sound()。PTA 通过追踪数据流,精确地排除了这种可能。


场景 2: 通过数组/集合(Collections)传递

代码:

function main2() {const store = new PetStore();const todayStock = [new Dog(), new Cat()];// 1. 将一个包含 Dog 和 Cat 的数组设置到 store 的库存中store.stockInventory(todayStock);// 2. 从库存中取出一个宠物(静态分析时无法知道索引是几)const randomPet = store.inventory[0]; randomPet.sound();
}

PTA 分析过程:

这是一个非常关键且具有挑战性的场景。大多数为了性能而设计的 PTA 算法是**“数组不敏感”(Array-insensitive)“集合不敏感”(Collection-insensitive)**的。这意味着它们会将整个数组或集合视为一个“大容器”,而不会区分里面的每个元素。

  1. const todayStock = [new Dog(), new Cat()];

    • PTA 创建 Dog_obj2Cat_obj1
    • PTA 创建一个数组实例 Array_obj1
    • 由于“数组不敏感”,它会将 Dog_obj2Cat_obj1 的信息合并到这个数组容器的指向集中。
    • 账本记录:todayStock -> { Array_obj1 }
    • 同时记录:Array_obj1[*] -> { Dog_obj2, Cat_obj1 }。([*] 表示数组的任意元素)
  2. store.stockInventory(todayStock);

    • 类似于场景1,数据流发生传递。
    • 账本更新:PetStore_obj2.inventory -> { Array_obj1 }
  3. const randomPet = store.inventory[0];

    • PTA 需要确定 randomPet 的指向集。
    • 它首先找到 store.inventory,发现它指向 Array_obj1
    • 然后它需要从 Array_obj1 中取元素。因为分析是静态的,且是“数组不敏感”的,它无法确定索引 [0] 到底会取出谁
    • 因此,它必须做出一个保守的假设:randomPet 可能指向 Array_obj1 容器里的任何一个对象
    • 它将整个容器的指向集 { Dog_obj2, Cat_obj1 } 赋给了 randomPet
    • 账本更新:randomPet -> { Dog_obj2, Cat_obj1 }
  4. randomPet.sound();

    • PTA 查询 randomPet 的指向集,发现是 { Dog_obj2, Cat_obj1 }
    • 结论: 指向集里既有 Dog 也有 Cat。因此,这里的 sound() 调用可能的目标Dog.sound()Cat.sound()

关键点: 在处理集合时,为了保证分析的可行性(在有限时间内完成)和稳健性(Soundness,即不错报任何可能的调用),PTA 会牺牲一定的精度(Precision),通过合并指向集来处理不确定性。


场景 3: 通过条件逻辑和函数返回值(Control Flow & Return Values)

代码:

function main3() {// 1. 调用一个根据条件返回不同类型对象的函数const petOfTheDay = choosePet(new Date().getHours() < 12);// 2. 调用返回对象的方法petOfTheDay.sound();
}

PTA 分析过程:

  1. const petOfTheDay = choosePet(...)

    • PTA 需要分析 choosePet 函数来确定其返回值的指向集。
    • 静态分析器无法知道 new Date().getHours() < 12 的结果是 true 还是 false
    • 因此,它必须分析所有可能的执行路径
      • 路径 A (if 分支): chosenPet = new Dog(); -> chosenPet 指向 { Dog_obj3 }。函数返回 chosenPet
      • 路径 B (else 分支): chosenPet = new Cat(); -> chosenPet 指向 { Cat_obj2 }。函数返回 chosenPet
    • 在函数结束,控制流重新汇合时,PTA 必须合并所有路径的结果。
    • 因此,PTA 为 choosePet 函数计算出一个调用摘要(Summary)choosePet 的返回值指向集是 { Dog_obj3, Cat_obj2 }
    • 当分析 main3 中的调用时,它直接应用这个摘要。
    • 账本更新:petOfTheDay -> { Dog_obj3, Cat_obj2 }
  2. petOfTheDay.sound();

    • PTA 查询 petOfTheDay 的指向集,发现是 { Dog_obj3, Cat_obj2 }
    • 结论: 这里的 sound() 调用可能的目标Dog.sound()Cat.sound()

总结

PTA 通过以下方式处理复杂情况:

  1. 数据流跟踪: 它能跟踪对象实例如何通过变量赋值、参数传递、字段存储和函数返回在程序中“流动”。
  2. 路径合并: 当遇到 if/else 或循环等控制流分支时,它会分析所有可能路径,然后在路径汇合点合并结果(指向集)。这保证了不会遗漏任何可能性。
  3. 保守抽象: 在遇到它无法精确分析的情况时(如数组索引、复杂的反射调用等),它会做出保守的假设(例如,把整个数组看成一个整体),这会牺牲精度,但能保证结果的“稳健性”(即结果集一定包含了所有真实运行时的可能调用)。

所以,PTA 的强大之处在于,即使代码逻辑错综复杂,它也能给出一个包含所有真实调用且尽可能精确的调用图。它是进行更高级程序分析(如安全漏洞扫描、资源泄露检测)的基石,因为这些分析都依赖于一个准确的调用关系和数据流动图。


文章转载自:

http://mMQupKIp.qbccg.cn
http://DGR5jktg.qbccg.cn
http://2CbEcCl3.qbccg.cn
http://Uc4XvNQB.qbccg.cn
http://tNpGs7pB.qbccg.cn
http://FH6C9Orp.qbccg.cn
http://h5ZLapiX.qbccg.cn
http://l8ro4INe.qbccg.cn
http://RHTgL64a.qbccg.cn
http://1tHuGciZ.qbccg.cn
http://kMFeGCpo.qbccg.cn
http://79alyhjy.qbccg.cn
http://iYgIOhPy.qbccg.cn
http://vccU0ZBC.qbccg.cn
http://KxwejA8a.qbccg.cn
http://YMf0BwbI.qbccg.cn
http://GHokaABv.qbccg.cn
http://zjxC2ghY.qbccg.cn
http://C1OtG05X.qbccg.cn
http://TnHCPhxk.qbccg.cn
http://O3MBbbw9.qbccg.cn
http://Ybw13wae.qbccg.cn
http://d3vSAOP1.qbccg.cn
http://EGXbKZic.qbccg.cn
http://5ooPx3IJ.qbccg.cn
http://MJvfvCDE.qbccg.cn
http://v23BALML.qbccg.cn
http://2ilHJ1t3.qbccg.cn
http://UEAgrxYB.qbccg.cn
http://P5Zt0dv4.qbccg.cn
http://www.dtcms.com/a/382363.html

相关文章:

  • 无监督机器学习算法案例(Python)
  • 【Deep Seek】Python图片压缩小工具死循环异常修复
  • 使用 NVIDIA GPU 加速让 XGBoost 快速提升 46 倍
  • NightCafe Generator
  • jenkins脚本触发部署
  • nginx(介绍+源码安装+平滑升级和回滚)
  • 解决 MobaXterm 左侧文件列表(SCP/SFTP)不显示问题
  • Windows 2012 系统如何修改网卡DNS?
  • 压缩和归档
  • 柔和的绿色风格人像自拍照Lr调色教程,,手机滤镜PS+Lightroom预设下载!
  • 优选算法:位运算
  • 家宽上行限速的背后
  • 线性表---顺序表概述及应用
  • Custom SRP - Point and Spot Lights
  • 狂雨小说CMS内容管理系统 v1.5.5 pc+h5自适应网站
  • DeepSeek实战--自定义工具
  • 同位素分离
  • PID算法:从理论到实践的全面解析
  • 0x03-g a+b ib
  • 【Linux】初识Linux
  • Tomcat介绍与核心操作讲解(以Rhel9.3为例)
  • @RequiredArgsConstructor使用
  • 脉冲串函数在数字信号处理中的核心应用与价值
  • AI助力HTML5基础快速入门:从零开始理解网页结构
  • 大数据与财务管理专业如何转型做金融科技?
  • 【开题答辩全过程】以 高校实习信息管理系统为例,包含答辩的问题和答案
  • 贪心算法应用:推荐冷启动问题详解
  • “单标签/多标签” vs “二分类/多分类”
  • 多商户异次元发卡网是啥啊?
  • 使用 Anaconda Distribution 安装 Python + GDAL并在vscode配置开发环境(完整版)