From b36f072e9a572efd52b5d737f8b6a3fe398452e2 Mon Sep 17 00:00:00 2001 From: RenFengJiang <1111> Date: Fri, 19 Jan 2024 11:53:54 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9AC++=E4=BE=86?= =?UTF-8?q?=E8=87=AA=E7=94=A8=E6=88=B6=E7=9A=84=E6=95=B4=E5=9E=8B=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=BF=9B=E8=A1=8C=E7=AE=97=E6=9C=AF=E8=BF=90=E7=AE=97?= =?UTF-8?q?=E5=BA=94=E8=BF=9B=E8=A1=8C=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../checkers/IntegerCountVerifyChecker.java | 151 ++++++++++++++++++ .../IntegerCountVerifyCheckerTest.java | 36 +++++ .../checkers/IntegerCountVerifyChecker.cc | 14 ++ 3 files changed, 201 insertions(+) create mode 100644 sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyChecker.java create mode 100644 sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyCheckerTest.java create mode 100644 sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyChecker.cc diff --git a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyChecker.java b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyChecker.java new file mode 100644 index 0000000..3f50a22 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyChecker.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ + +package com.keyware.sonar.cxx.rules.checkers; + +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.annotations.ActivatedByDefault; +import org.sonar.cxx.squidbridge.annotations.SqaleConstantRemediation; +import org.sonar.cxx.squidbridge.checks.SquidCheck; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * TODO IntegerCountVerifyChecker + * + * @author RenFengJiang + * @date 2024/1/18 + */ +@Rule(key = "IntegerCountVerifyChecker", name = "來自用戶的整型数据进行算术运算应进行验证", description = "对来自用户的整形数据作算术运算前进行验证,确保运算结果不会溢出", priority = Priority.INFO, tags = {"28suo"}) +@ActivatedByDefault +@SqaleConstantRemediation("5min") +public class IntegerCountVerifyChecker extends SquidCheck { + @Override + public void init() { + // 指定当前访问器需要访问的节点类型,functionBody(函数)主体节点 + this.subscribeTo( + CxxGrammarImpl.functionBody + ); + } + + /** + * 访问AST节点 + * + * @param node 要处理的AST节点,该节点类型为通过subscribeTo方法订阅的类型 + */ + @Override + public void visitNode(@Nonnull AstNode node) { + //存放用户输入的整形变量 + List cinList = verdictUserParam(node); + //获取到if判断中的参数 + Map map = ifParam(node); + //获取到算术表达式 + List descendants = node.getDescendants(CxxGrammarImpl.multiplicativeExpression); + descendants.addAll(node.getDescendants(CxxGrammarImpl.additiveExpression)); + for (AstNode desc:descendants) { + //获取到算术表达式中的参数 + List children = desc.getChildren(); + for(AstNode dren:children){ + //过滤掉无用的参数 + if("IDENTIFIER".equals(dren.getName())){ + //判断是否存在于用户传递的参数集合中 + if(cinList.contains(dren.getTokenValue())){ + //判断是否进行过校验 + if(map.containsKey(dren.getTokenValue())){ + Integer integer = map.get(dren.getTokenValue()); + //判断校验是否在算术之前 + if(integer > dren.getTokenLine()){ + getContext().createLineViolation(this,"來自用戶的整型数据进行算术运算应进行验证",dren); + } + }else { + getContext().createLineViolation(this,"來自用戶的整型数据进行算术运算应进行验证",dren); + } + } + } + } + } + } + + //获取用户输入的整形变量 + public static List verdictUserParam(AstNode node){ + //存放整型变量 + List lists = new ArrayList<>(); + //存放用户输入的整形变量 + List cinList = new ArrayList<>(); + //获取所有的语句 + List statList = node.getDescendants(CxxGrammarImpl.statement); + for (AstNode stList : statList){ + //判断是否是整形变量 + if("int".equals(stList.getTokenValue())){ + List listDescendants = stList.getDescendants(CxxGrammarImpl.initDeclarator); + for(AstNode desc : listDescendants){ + lists.add(desc.getTokenValue()); + } + //判断是否是std类型 + }else if("std".equals(stList.getTokenValue())){ + //获取到方法名称 + AstNode firstDescendant = stList.getFirstDescendant(CxxGrammarImpl.qualifiedId); + List children = firstDescendant.getChildren(); + for(AstNode desc : children){ + //判断是否是用户输入方法 + if("cin".equals(desc.getTokenValue())){ + //获取用户输入中的参数变量 + AstNode descendant = stList.getFirstDescendant(CxxGrammarImpl.shiftExpression); + List descendantChildren = descendant.getChildren(); + for(AstNode dant:descendantChildren){ + if("IDENTIFIER".equals(dant.getName())){ + //判断输入的是否是整形变量 + if(lists.contains(dant.getTokenValue())){ + cinList.add(dant.getTokenValue()); + } + } + } + } + } + } + } + return cinList; + } + + public static Map ifParam(AstNode node){ + Map map = new HashMap<>(); + //选择节点语句 + List nodeDescendants = node.getDescendants(CxxGrammarImpl.selectionStatement); + for (AstNode astNode:nodeDescendants) { + //判断节点是不是if节点 + if("if".equals(astNode.getToken().getValue())){ + //获取其中的参数 + List astNodeList = astNode.getDescendants(CxxGrammarImpl.expressionList); + astNodeList.addAll(astNode.getDescendants(CxxGrammarImpl.condition)); + for (AstNode expr:astNodeList) { + map.put(expr.getTokenValue(),expr.getTokenLine()); + } + //判断第二种情况获取到if里面的参数 + if(astNodeList.size() == 0){ + List astNodes = astNode.getDescendants(CxxGrammarImpl.relationalExpression); + for (AstNode as:astNodes) { + List children = as.getChildren(); + for (AstNode chil:children) { + map.put(chil.getTokenValue(),chil.getTokenLine()); + } + } + } + } + } + return map; + } + + +} diff --git a/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyCheckerTest.java b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyCheckerTest.java new file mode 100644 index 0000000..42b290f --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyCheckerTest.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ + +package com.keyware.sonar.cxx.rules.checkers; + +import com.keyware.sonar.cxx.CxxFileTesterHelper; +import org.junit.jupiter.api.Test; +import org.sonar.cxx.CxxAstScanner; +import org.sonar.cxx.squidbridge.api.SourceFile; +import org.sonar.cxx.squidbridge.checks.CheckMessagesVerifier; + +import java.io.IOException; + +/** + * TODO IntegerCountVerifyCheckerTest + * + * @author RenFengJiang + * @date 2024/1/18 + */ +public class IntegerCountVerifyCheckerTest { + + @Test + public void checkTest() throws IOException { + var checker = new IntegerCountVerifyChecker(); + var tester = CxxFileTesterHelper.create("IntegerCountVerifyChecker.cc"); + SourceFile file = CxxAstScanner.scanSingleInputFile(tester.asInputFile(), checker); + CheckMessagesVerifier.verify(file.getCheckMessages()) + .next().atLine(10).withMessage("來自用戶的整型数据进行算术运算应进行验证") + .next().atLine(10).withMessage("來自用戶的整型数据进行算术运算应进行验证") + .noMore(); + } +} diff --git a/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyChecker.cc b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyChecker.cc new file mode 100644 index 0000000..7f19d4f --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/IntegerCountVerifyChecker.cc @@ -0,0 +1,14 @@ +#include +int main() { + int num1, num2; + // 输入两个整数 +// std::cout << "请输入两个整数:"; + std::cin >> num1 >> num2; + // 执行算术运算并打印结果 +// if(num1 > 0){ +// } + std::cout << "两数之和:" << num1 + num2 << std::endl; +// std::cout << "两数之差:" << num1 - num2 << std::endl; +// std::cout << "两数之积:" << num1 * num2 << std::endl; + return 0; +} \ No newline at end of file From 228d68a4095e4c5a8e26c87200e1811e8407889f Mon Sep 17 00:00:00 2001 From: RenFengJiang <1111> Date: Fri, 19 Jan 2024 11:54:43 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=97=A0=E7=94=A8=E4=BB=A3=E7=A0=81=EF=BC=8C=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E5=85=A8=E5=B1=80=E5=A3=B0=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cxx/rules/checkers/SendMessageChecker.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/SendMessageChecker.java b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/SendMessageChecker.java index 237e154..3ef34d9 100644 --- a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/SendMessageChecker.java +++ b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/SendMessageChecker.java @@ -36,6 +36,12 @@ public class SendMessageChecker extends SquidCheck { CxxGrammarImpl.functionBody ); } + private static List lists = new ArrayList(){{ + add("weapon"); + add("unit"); + add("param"); + }}; + /** * 访问AST节点 @@ -45,10 +51,7 @@ public class SendMessageChecker extends SquidCheck { @Override public void visitNode(@Nonnull AstNode node) { //创建集合存入违规敏感字段 - List lists = new ArrayList(); - lists.add("weapon"); - lists.add("unit"); - lists.add("param"); + //获取到所有的表达式 List descendants = node.getDescendants(CxxGrammarImpl.expression); for (AstNode des:descendants) { @@ -62,7 +65,8 @@ public class SendMessageChecker extends SquidCheck { if("STRING".equals(astNode.getName())){ }else { - if(lists.contains(astNode.getTokenValue())){ + //判斷其中是否包含敏感字段 + if(lists.contains(astNode.getTokenValue().toLowerCase())){ getContext().createLineViolation(this,"发送敏感信息前应对敏感信息进行加密",des); } } From 8d3bc23687d3cb6a19ce8fe5acddf94f8bd67bc2 Mon Sep 17 00:00:00 2001 From: RenFengJiang <1111> Date: Fri, 19 Jan 2024 18:08:09 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9AC++=E5=9C=A8?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E5=8A=A0=E8=BD=BD=E5=BA=93=E5=89=8D=E5=AF=B9?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=95=B0=E6=8D=AE=E8=BF=9B=E8=A1=8C=E9=AA=8C?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cxx/rules/checkers/DLLVerifyChecker.java | 157 ++++++++++++++++++ .../rules/checkers/DLLVerifyCheckerTest.java | 35 ++++ .../cxx/rules/checkers/DLLVerifyChecker.cc | 57 +++++++ 3 files changed, 249 insertions(+) create mode 100644 sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.java create mode 100644 sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyCheckerTest.java create mode 100644 sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.cc diff --git a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.java b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.java new file mode 100644 index 0000000..add7916 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ + +package com.keyware.sonar.cxx.rules.checkers; + +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.annotations.ActivatedByDefault; +import org.sonar.cxx.squidbridge.annotations.SqaleConstantRemediation; +import org.sonar.cxx.squidbridge.checks.SquidCheck; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * TODO DLLVerifyChecker + * + * @author RenFengJiang + * @date 2024/1/19 + */ +@Rule(key = "DLLVerifyChecker", name = "在动态加载库前对输入数据进行验证", description = "检测代码调用动态库时,判断为动态库传参的类型与动态库要求是否一致", priority = Priority.INFO, tags = {"28suo"}) +@ActivatedByDefault +@SqaleConstantRemediation("5min") +public class DLLVerifyChecker extends SquidCheck { + + private static String name = "在动态加载库前对输入数据进行验证"; + @Override + public void init() { + // 指定当前访问器需要访问的节点类型,functionBody(函数)主体节点 + this.subscribeTo( + CxxGrammarImpl.functionBody + ); + } + + /** + * 访问AST节点 + * + * @param node 要处理的AST节点,该节点类型为通过subscribeTo方法订阅的类型 + */ + @Override + public void visitNode(@Nonnull AstNode node) { + Map map = ifParam(node); + List simps = node.getDescendants(CxxGrammarImpl.simpleDeclaration); + for(AstNode simp :simps){ + //判断动态加载库类型 + if("HINSTANCE".equals(simp.getTokenValue())){ + loadParam(map,simp); + }else if ("void".equals(simp.getTokenValue())){ + openParam(map,simp); + } + } + } + + //判断是否是dlopen格式的动态加载库 + public void openParam(Map map,AstNode simp){ + //获取方法名 + List descendants = simp.getDescendants(CxxGrammarImpl.postfixExpression); + if(descendants != null){ + for(AstNode desc : descendants){ + //判断是否式动态加载库 + if("dlopen".equals(desc.getTokenValue())){ + //获取其中的参数列表 + AstNode firstDescendant = desc.getFirstDescendant(CxxGrammarImpl.additiveExpression); + if(firstDescendant != null){ + List children = firstDescendant.getChildren(); + for(AstNode dren : children){ + //获取参数并进行判断是否是传入的参数 + if("IDENTIFIER".equals(dren.getName())){ + if(map.containsKey(dren.getTokenValue())){ + //判断参数是否进行过校验 + Integer integer = map.get(dren.getTokenValue()); + //判断参数校验是否在使用之前 + if(dren.getTokenLine() > integer){ + getContext().createLineViolation(this,name,dren); + } + }else { + getContext().createLineViolation(this,name,dren); + } + } + } + }else { + getContext().createLineViolation(this,name,desc); + } + } + } + } + } + + //对LoadLibrary格式的动态加载库进行校验 + public void loadParam(Map map,AstNode simp){ + //获取方法名 + AstNode firstDescendant = simp.getFirstDescendant(CxxGrammarImpl.postfixExpression); + if(firstDescendant != null){ + if("LoadLibrary".equals(firstDescendant.getTokenValue())){ + //获取其中的参数列表 + List descendants = firstDescendant.getDescendants(CxxGrammarImpl.expressionList); + if(descendants != null){ + for (AstNode desc : descendants){ + //判断参数是否进行过校验 + if (map.containsKey(desc.getTokenValue())){ + //判断参数校验是否在使用之前 + int tokenLine = map.get(desc.getTokenValue()); + if(desc.getTokenLine() > tokenLine){ + getContext().createLineViolation(this,name,desc); + break; + } + }else { + getContext().createLineViolation(this,name,desc); + break; + } + } + }else { + getContext().createLineViolation(this,name,firstDescendant); + } + } + } + } + + //获取if判断中的参数 + public static Map ifParam(AstNode node){ + Map map = new HashMap<>(); + //选择节点语句 + List nodeDescendants = node.getDescendants(CxxGrammarImpl.selectionStatement); + for (AstNode astNode:nodeDescendants) { + //判断节点是不是if节点 + if("if".equals(astNode.getToken().getValue())){ + //获取其中的参数 + List astNodeList = astNode.getDescendants(CxxGrammarImpl.expressionList); + astNodeList.addAll(astNode.getDescendants(CxxGrammarImpl.condition)); + for (AstNode expr:astNodeList) { + map.put(expr.getTokenValue(),expr.getTokenLine()); + } + //判断第二种情况获取到if里面的参数 + if(astNodeList.size() == 0){ + List astNodes = astNode.getDescendants(CxxGrammarImpl.relationalExpression); + for (AstNode as:astNodes) { + List children = as.getChildren(); + for (AstNode chil:children) { + map.put(chil.getTokenValue(),chil.getTokenLine()); + } + } + } + } + } + return map; + } + +} diff --git a/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyCheckerTest.java b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyCheckerTest.java new file mode 100644 index 0000000..74388d6 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyCheckerTest.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ + +package com.keyware.sonar.cxx.rules.checkers; + +import com.keyware.sonar.cxx.CxxFileTesterHelper; +import org.junit.jupiter.api.Test; +import org.sonar.cxx.CxxAstScanner; +import org.sonar.cxx.squidbridge.api.SourceFile; +import org.sonar.cxx.squidbridge.checks.CheckMessagesVerifier; + +import java.io.IOException; + +/** + * TODO DLLVerifyCheckerTest + * + * @author RenFengJiang + * @date 2024/1/19 + */ +public class DLLVerifyCheckerTest { + @Test + public void checkTest() throws IOException { + var checker = new DLLVerifyChecker(); + var tester = CxxFileTesterHelper.create("DLLVerifyChecker.cc"); + SourceFile file = CxxAstScanner.scanSingleInputFile(tester.asInputFile(), checker); + CheckMessagesVerifier.verify(file.getCheckMessages()) + .next().atLine(13).withMessage("在动态加载库前对输入数据进行验证") + .next().atLine(36).withMessage("在动态加载库前对输入数据进行验证") + .noMore(); + } +} diff --git a/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.cc b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.cc new file mode 100644 index 0000000..8676653 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.cc @@ -0,0 +1,57 @@ +#include +#ifdef _WIN32 + #include +#else + #include +#endif +int main() +{ + + std::String a = "your_dll.dll"; + if(a != "a"){ + } + HINSTANCE hInsts = LoadLibrary(a);//error + //加载dll +// HINSTANCE hInst = LoadLibrary("your_dll.dll"); + if (hInst == NULL) { + std::cout << "无法加载库" << std::endl; + return -1; + } + //获取函数 + typedef void (*FuncType)(); + FuncType func = (FuncType)GetProcAddress(hInst, "函数名称"); + if (func == NULL) { + std::cout << "无法获取函数" << std::endl; + return -1; + } + //调用函数 + func(); + //卸载dll + FreeLibrary(hInst); + + std::String b = "c"; + //加载so库 + if(b != "a"){ + } + void *handle = dlopen(b, RTLD_LAZY);//error + if (!handle) { + std::cerr << "无法打开库:" << dlerror() << '\n'; + return 1; + } + //获取函数 + typedef void (*FuncType)(); + dlerror(); + FuncType func = (FuncType)dlsym(handle, "函数名称"); + const char *dlsym_error = dlerror(); + if (dlsym_error) { + std::cerr << "无法加载符号 '函数名称':" << dlsym_error << '\n'; + dlclose(handle); + return 1; + } + //调用函数 + func(); + //关闭库文件 + dlclose(handle); +#endif + return 0; +} \ No newline at end of file