大模型驱动的智能代码评审研究-预演评审代码集
作者:徐梦旗,发布于:2023年12月16日 23:00,字数:1.6k,预计阅读:8分钟
1. 背景
在软件开发过程中,提高代码质量最常用的途径有两个:一个是借助于静态代码扫描工具,一个是借助于团队代码评审。静态代码扫描可以发现代码中潜在的问题,以Sonar Rules为例,其将扫描规则分为以下四类:
Bug
:软件设计与实现中的缺陷,一般会影响软件的正常功能,如NPE,OOM等问题。Vulnerability
:可被利用产生不安全行为的漏洞,如SQL注入,跨站脚本攻击等漏洞。Security Hotspots
:安全热点问题,如越权,密码未加密等问题。Code Smells
:代码的坏味道,如变量命名不规范等问题。
而团队代码评审相比于静态代码扫描更能发现隐蔽的缺陷,并为代码的可读性及扩展性提供意见。为借助大模型实现智能代码评审,本文将提供预演评审代码集以检测大模型的代码评审能力。
We believe secure, quality software comes from secure, quality code. ——SonarSource
2. 预演评审代码集
2.1. 安全漏洞代码集
- SQL注入风险
import java.sql.*;
public class VulnerableSQLInjectionExample {
public static void main(String[] args) {
String username = "admin"; // 假设用户输入的用户名为admin
String password = "password123"; // 假设用户输入的密码为password123
try {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "root", "password");
Statement statement = connection.createStatement();
String sqlQuery = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
ResultSet resultSet = statement.executeQuery(sqlQuery);
if (resultSet.next()) {
System.out.println("登录成功!");
} else {
System.out.println("登录失败!");
}
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 反序列化漏洞
import java.io.ObjectInputStream;
public class VulnerableClass {
public static void main(String[] args) {
try {
ObjectInputStream ois = new ObjectInputStream(System.in);
Object obj = ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.2. 隐蔽缺陷代码集
- 空指针
Person person = null;
String name = person.getName();
String[] arr = new String[] { null, "hello", "world" };
for (String str : arr) {
System.out.println(str.length());
}
public static String printState(int flag) {
System.out.println(isOpen(flag) ? "Success" : "Fail");
}
public static Boolean isOpen(int flag) {
if (flag == 1) {
return true;
} else if (flag == 0) {
return false;
} else {
return null;
}
}
- 内存泄漏与内存溢出
import java.util.ArrayList;
public class MemoryLeakExample {
public static void main(String[] args) {
while (true) {
ArrayList<Object> list = new ArrayList<>();
list.add(new Object());
// 没有释放list内存
}
}
}
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
public class OOMMetaspaceTest {
public static void main(String[] args) {
// jdk1.8
// -verbose:class -XX:MaxMetaspaceSize=10m -XX:MetaspaceSize=10M
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMMetaspaceTest.class);
// 不使用缓存
enhancer.setUseCache(false);
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> method.invoke(o, objects));
enhancer.create();
}
}
}
public class MemoryLeakExample {
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
new Thread(() -> {
threadLocal.set("Value " + Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
- 死循环或递归
public class DeadlyRecursion {
public static void main(String[] args) {
int n = 0;
deadlyMethod(n);
}
public static void deadlyMethod(int n) {
deadlyMethod(n);
}
}
public static void run(int a, int b) {
while (true) {
a = a + 1;
b = b + 2;
System.out.print(a + ", " + b);
if (a > b) {
break;
}
}
}
- 除零
double a = 1000;
double b = 0;
double c = a / b;
public static double compute(double m, double n) {
double a = 100.0;
double b = m - n;
return divide(a, b);
}
public static double divide(double a, double b) {
return a / b;
}
- 使用资源未释放
import java.io.*;
public class UnclosedStreamExample {
public static void main(String[] args) {
try {
FileInputStream inputStream = new FileInputStream("example.txt");
int data = inputStream.read();
while (data != -1) {
System.out.print((char) data);
data = inputStream.read();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.3. 并发问题代码集
- 死锁
public class DeadlockExample {
public static void main(String[] args) {
Object lock1 = new Object();
Object lock2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1 acquired lock 1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 1 acquired lock 2");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread 2 acquired lock 2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("Thread 2 acquired lock 1");
}
}
});
t1.start();
t2.start();
}
}
- 未加锁
public class UnsafeIncrementExample {
private static int count = 0;
public static void increment() {
count++;
}
public static int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + getCount());
}
}
- 未释放锁
public class MyClass {
public void doSomething() {
Lock lock = new Lock();
lock.lock();
if (isInitialized()) {
// ...
lock.unlock();
}
}
}
2.4. 性能问题代码集
- for-each 插入大量数据
public class InsertDataExample {
@Autowired
private UserDao userDao;
public void saveUsers(List<String> users) {
// 使用for-each循环遍历数据并插入
for (String user : users) {
userDao.insert(user);
}
}
}
- 内存访问大量数据
public class GetMaxAgeExample {
@Autowired
private UserDao userDao;
public int getMaxAge() {
List<User> users = userDao.getAllUsers();
int maxAge = 0;
for (User user : users) {
if (user.getAge() > maxAge) {
maxAge = user.getAge();
}
}
return maxAge;
}
}
2.5. 坏味道代码集
- 变量命名不明确
double q = 10;
double w = 3.14;
double a = w * q * q;
System.out.println(a);
public double getA(double a, double b) {
return 3.14 * a * a * 2 + 2 * 3.14 * a * b;
}
- switch 没有 default
switch (param) {
case 0:
doSomething();
break;
case 1:
doSomethingElse();
break;
}
- 使用 == 而非 equals
public boolean same(Integer a, Integer b) {
return a == b;
}
- 代码命名不符合规范
public static final String bean_factory_name = "MyBeanFactory";
- 大量 IF-ELSE
public void sendMessageUsingIfElse(String code, String message) {
if ("aliyun".equals(code)) {
aliyunSender.sendMessage(message);
} else if ("baidu".equals(code)) {
baiduSender.sendMessage(message);
} else if ("huawei".equals(code)) {
huaweiSender.sendMessage(message);
} else {
throw new IllegalArgumentException("Not support code: " + code);
}
}
- try-with-resource
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(fileName);
br = new BufferedReader(fr);
return br.readLine();
} catch (...) {
// ...
} finally {
if (br != null) {
try {
br.close();
} catch(IOException e){...}
}
if (fr != null ) {
try {
br.close();
} catch(IOException e){...}
}
}