利用--wrap重定向函数排查内存泄露

本文介绍了如何在GCC编译时通过LD_PRELOAD环境变量和-Wrap选项控制程序不使用系统默认的malloc/free等库函数,而是使用自定义的实现。通过示例代码展示了如何编写和编译包装函数,以及如何在运行时观察效果。这种方法在内存泄露排查中有一定应用。

背景

在使用GCC编译器时,如果不想工程使用系统的库函数,例如在自己的工程中可以根据选项来控制是否使用系统中提供的malloc/free函数,可以有两种方法:

(1). 使用LD_PRELOAD环境变量:可以设置共享库的路径,并且该库将在任何其它库之前加载,即这个动态库中符号优先级是最高的。
(2). 使用GCC的–wrap选项:对symbol使用包装函数(wrapper function),任何对symbol未定义的引用(undefined reference)会被解析成__wrap_symbol,而任何对__real_symbol未定义的引用会被解析成symbol。即当一个名为symbol符号使用wrap功能时,工程中任何用到symbol符号的地方实际使用的是__wrap_symbol符号,任何用到__real_symbol的地方实际使用的是真正的symbol。注意:当__wrap_symbol是使用C++实现时,一定要加上extern “C”,否则将会出现”undefined reference to __wrap_symbol”。

示例

以下是对–wrap使用的测试代码:
wrap_symbol.h:

#ifndef FBC_LINUX_CODE_TEST_WRAP_SYMBOL_HPP_
#define FBC_LINUX_CODE_TEST_WRAP_SYMBOL_HPP_
 
#include <stdlib.h>
 
extern "C" {
   
   
 
void* __wrap_malloc(size_t size);
void __wrap_free(void* ptr);
 
void* __real_malloc(size_t size);
void __real_free(void* ptr);
 
int foo();
int __wrap_foo();
 
// c++filt: _Znwm ==> operator new(unsigned long)
void
第一个小蓝窗:”安装最新的 PowerShell,了解新功能和改进!https://aka.ms/PSWindows PS C:\Users\Administrator> # 修正后的启动命令(包含完整的 try/catch) >> function Monitor-Project { >> param( >> [string]$ProjectName, >> [string]$StartCommand >> ) >> >> $logDir = Join-Path $projectRoot "Logs" >> $logFile = Join-Path $logDir "$ProjectName-$(Get-Date -Format 'yyyyMMdd').log" >> >> # 检查进程是否运行 >> $isRunning = $false >> if ($ProjectName -eq "APIServer") { >> $isRunning = Get-Process -Name "node" -ErrorAction SilentlyContinue | >> Where-Object { $_.Path -like "*$ProjectName*" } >> } >> else { >> $isRunning = Get-Process -Name $ProjectName -ErrorAction SilentlyContinue >> } >> >> if (-not $isRunning) { >> Write-Host "⚠️ 项目 $ProjectName 未运行,正在启动..." -ForegroundColor Yellow >> >> # 修复的重定向命令 >> try { >> # 使用 2>&1 合并输出流 >> Start-Process -FilePath "pwsh" ` >> -ArgumentList "-Command `"$StartCommand 2>&1`"" ` >> -RedirectStandardOutput $logFile ` >> -WindowStyle Hidden >> Write-Host "✅ 项目 $ProjectName 已启动" -ForegroundColor Green >> } >> catch { >> Write-Host "❌ 启动 $ProjectName 失败: $_" -ForegroundColor Red >> Send-Alert -Project $ProjectName -Error $_ >> } >> } >> else { >> Write-Host "✅ 项目 $ProjectName 运行正常" -ForegroundColor Cyan >> } >> } >> PS C:\Users\Administrator> # 完整的 Git 处理函数 >> function Update-Project { >> param( >> [string]$ProjectName, >> [string]$RepoUrl >> ) >> >> $projectDir = Join-Path $projectRoot $ProjectName >> $gitDir = Join-Path $projectDir ".git" >> >> if (-not (Test-Path $gitDir)) { >> # 检查目录是否非空 >> if (Test-Path $projectDir -PathType Container) { >> $items = Get-ChildItem -Path $projectDir -ErrorAction SilentlyContinue >> if ($items.Count -gt 0) { >> # 备份现有目录 >> $backupDir = "$projectDir.backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')" >> Move-Item -Path $projectDir -Destination $backupDir -Force >> Write-Host "⚠️ 已备份现有目录到: $backupDir" -ForegroundColor Yellow >> } >> } >> >> # 首次克隆仓库 >> Write-Host "🌱 正在克隆 $ProjectName 仓库..." -ForegroundColor Magenta >> git clone $RepoUrl $projectDir >> } >> else { >> # 更新现有仓库 >> Write-Host "🔄 正在更新 $ProjectName 代码..." -ForegroundColor Blue >> Set-Location $projectDir >> git pull origin main >> } >> >> # 修复的属性访问方式 >> $projectConfig = $config.Projects | Where-Object { $_.Name -eq $ProjectName } >> if (-not $projectConfig) { >> Write-Host "❌ 找不到项目配置: $ProjectName" -ForegroundColor Red >> return >> } >> >> $projectType = $projectConfig.Type >> switch ($projectType) { >> "DotNet" { >> dotnet build >> dotnet publish -c Release -o (Join-Path $projectRoot "Binaries\$ProjectName") >> } >> "NodeJS" { >> npm install >> npm run build >> } >> "Python" { >> pip install -r requirements.txt >> } >> default { >> Write-Host "❌ 未知项目类型: $projectType" -ForegroundColor Red >> } >> } >> >> Write-Host "🚀 $ProjectName 更新完成" -ForegroundColor Green >> } >> PS C:\Users\Administrator> param( >> [Parameter(Mandatory=$true)] >> [ValidateSet("Install", "Uninstall", "Start", "Stop")] >> [string]$Action >> ) >> >> $serviceName = "ProjectEcosystemManager" >> $scriptPath = "E:\ProjectEcosystem\ProjectMonitor\Scripts\ProjectEcosystemManager.ps1" >> >> # 验证脚本是否存在 >> if (-not (Test-Path $scriptPath)) { >> Write-Host "❌ 主脚本不存在: $scriptPath" -ForegroundColor Red >> exit 1 >> } >> >> switch ($Action) { >> "Install" { >> # 检查服务是否已存在 >> $service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue >> if ($service) { >> Write-Host "ℹ️ 服务已存在,先卸载..." -ForegroundColor Yellow >> & $PSCommandPath -Action Uninstall >> } >> >> # 创建新服务 >> $binaryPath = "powershell.exe -ExecutionPolicy Bypass -File `"$scriptPath`" -WindowStyle Hidden" >> New-Service -Name $serviceName ` >> -BinaryPathName $binaryPath ` >> -DisplayName "Project Ecosystem Manager" ` >> -Description "自动化管理项目生态系统" ` >> -StartupType Automatic | Out-Null >> >> # 启动服务 >> Start-Service -Name $serviceName >> Write-Host "✅ 服务安装成功" -ForegroundColor Green >> } >> "Uninstall" { >> $service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue >> if ($service) { >> # 停止服务 >> if ($service.Status -eq 'Running') { >> Stop-Service -Name $serviceName -Force >> } >> >> # 删除服务 >> sc.exe delete $serviceName | Out-Null >> Write-Host "✅ 服务卸载成功" -ForegroundColor Green >> } >> else { >> Write-Host "ℹ️ 服务不存在,无需卸载" -ForegroundColor Cyan >> } >> } >> "Start" { >> Start-Service -Name $serviceName >> Write-Host "✅ 服务已启动" -ForegroundColor Green >> } >> "Stop" { >> Stop-Service -Name $serviceName -Force >> Write-Host "✅ 服务已停止" -ForegroundColor Yellow >> } >> } >> 位于命令管道位置 1 的 cmdlet 请为以下参数提供值: Action: “ 第二个小蓝窗:”PS C:\Users\Administrator> <!DOCTYPE html> >> <html lang="zh-CN"> >> <head> >> <meta charset="UTF-8"> >> <title>项目生态系统仪表板</title> >> <style> >> :root { >> --primary-color: #2c3e50; >> --secondary-color: #3498db; >> --success-color: #2ecc71; >> --warning-color: #f39c12; >> --danger-color: #e74c3c; >> } >> body { >> font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; >> margin: 0; >> padding: 20px; >> background: #f5f7fa; >> } >> .dashboard { >> display: grid; >> grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); >> gap: 20px; >> } >> .card { >> background: white; >> border-radius: 10px; >> box-shadow: 0 4px 12px rgba(0,0,0,0.1); >> overflow: hidden; >> transition: transform 0.3s ease; >> } >> .card:hover { >> transform: translateY(-5px); >> } >> .card-header { >> background: var(--primary-color); >> color: white; >> padding: 15px; >> font-weight: bold; >> } >> .card-body { >> padding: 20px; >> } >> .status { >> display: flex; >> align-items: center; >> margin-bottom: 15px; >> } >> .status-indicator { >> width: 12px; >> height: 12px; >> border-radius: 50%; >> margin-right: 10px; >> } >> .status-running { >> background: var(--success-color); >> } >> .status-stopped { >> background: var(--danger-color); >> } >> .btn { >> background: var(--secondary-color); >> color: white; >> border: none; >> padding: 8px 15px; >> border-radius: 4px; >> cursor: pointer; >> margin-right: 10px; >> transition: background 0.3s; >> } >> .btn:hover { >> opacity: 0.9; >> } >> .metrics { >> display: grid; >> grid-template-columns: 1fr 1fr; >> gap: 10px; >> margin-bottom: 15px; >> } >> .metric { >> background: #f8f9fa; >> padding: 10px; >> border-radius: 5px; >> font-size: 0.9em; >> } >> .metric-title { >> font-weight: bold; >> color: #7f8c8d; >> margin-bottom: 3px; >> } >> </style> >> </head> >> <body> >> <h1>项目生态系统监控仪表板</h1> >> >> <div class="dashboard" id="dashboard"> >> <!-- 动态生成项目卡片 --> >> </div> >> >> <script> >> // API端点 >> const API_URL = "http://localhost:5000/api/status"; >> >> // 初始项目数据 >> let projects = []; >> >> // 从API获取状态 >> async function fetchProjectStatus() { >> try { >> const response = await fetch(API_URL); >> if (!response.ok) throw new Error('Network error'); >> projects = await response.json(); >> renderDashboard(); >> } catch (error) { >> console.error('获取状态失败:', error); >> // 回退到静态数据 >> projects = [ >> { id: 1, name: "APIServer", type: "NodeJS", status: "running", cpu: "15%", memory: "120MB", uptime: "12小时" }, >> { id: 2, name: "BackendService", type: ".NET", status: "running", cpu: "22%", memory: "210MB", uptime: "8小时" }, >> { id: 3, name: "DataAnalysis", type: "Python", status: "stopped", cpu: "0%", memory: "0MB", uptime: "N/A" }, >> { id: 4, name: "EcoMonitor", type: "PowerShell", status: "running", cpu: "5%", memory: "80MB", uptime: "24小时" } >> ]; >> renderDashboard(); >> } >> } >> >> // 渲染仪表板 >> function renderDashboard() { >> const dashboard = document.getElementById('dashboard'); >> dashboard.innerHTML = ''; >> >> projects.forEach(project => { >> const card = document.createElement('div'); >> card.className = 'card'; >> card.id = `project-${project.id}`; >> >> const statusClass = project.status === 'running' ? >> 'status-running' : 'status-stopped'; >> const statusText = project.status === 'running' ? '运行中' : '已停止'; >> >> card.innerHTML = ` >> <div class="card-header">${project.name}</div> >> <div class="card-body"> >> <div class="status"> >> <div class="status-indicator ${statusClass}"></div> >> <span><strong>状态:</strong> ${statusText}</span> >> </div> >> <div class="metrics"> >> <div class="metric"> >> <div class="metric-title">类型</div> >> ${project.type} >> </div> >> <div class="metric"> >> <div class="metric-title">CPU</div> >> ${project.cpu} >> </div> >> <div class="metric"> >> <div class="metric-title">内存</div> >> ${project.memory} >> </div> >> <div class="metric"> >> <div class="metric-title">运行时间</div> >> ${project.uptime} >> </div> >> </div> >> <div class="actions"> >> <button class="btn restart-btn" data-id="${project.id}">重启</button> >> <button class="btn logs-btn" data-id="${project.id}" style="background: #7f8c8d;">查看日 志</button> >> </div> >> </div> >> `; >> >> dashboard.appendChild(card); >> }); >> >> // 添加事件监听器 >> document.querySelectorAll('.restart-btn').forEach(btn => { >> btn.addEventListener('click', () => restartProject(btn.dataset.id)); >> }); >> >> document.querySelectorAll('.logs-btn').forEach(btn => { >> btn.addEventListener('click', () => viewLogs(btn.dataset.id)); >> }); >> } >> >> // 项目操作函数 >> async function restartProject(id) { >> const project = projects.find(p => p.id == id); >> try { >> const response = await fetch(`${API_URL}/restart/${id}`, { method: 'POST' }); >> if (response.ok) { >> alert(`✅ ${project.name} 重启指令已发送`); >> } else { >> throw new Error('重启失败'); >> } >> } catch (error) { >> alert(`❌ 重启失败: ${error.message}`); >> } >> } >> >> function viewLogs(id) { >> const project = projects.find(p => p.id == id); >> window.open(`logs.html?project=${encodeURIComponent(project.name)}`, '_blank'); >> } >> >> // 初始加载 >> fetchProjectStatus(); >> >> // 定时更新数据 (每5秒) >> setInterval(fetchProjectStatus, 5000); >> </script> >> </body> >> </html> >> 所在位置 行:8 字符: 15 + --primary-color: #2c3e50; + ~ 一元运算符“--”后面缺少表达式。 所在位置 行:8 字符: 15 + --primary-color: #2c3e50; + ~~~~~~~~~~~~~~ 表达式或语句中包含意外的标记“primary-color:”。 所在位置 行:9 字符: 15 + --secondary-color: #3498db; + ~ 一元运算符“--”后面缺少表达式。 所在位置 行:9 字符: 15 + --secondary-color: #3498db; + ~~~~~~~~~~~~~~~~ 表达式或语句中包含意外的标记“secondary-color:”。 所在位置 行:10 字符: 15 + --success-color: #2ecc71; + ~ 一元运算符“--”后面缺少表达式。 所在位置 行:10 字符: 15 + --success-color: #2ecc71; + ~~~~~~~~~~~~~~ 表达式或语句中包含意外的标记“success-color:”。 所在位置 行:11 字符: 15 + --warning-color: #f39c12; + ~ 一元运算符“--”后面缺少表达式。 所在位置 行:11 字符: 15 + --warning-color: #f39c12; + ~~~~~~~~~~~~~~ 表达式或语句中包含意外的标记“warning-color:”。 所在位置 行:12 字符: 15 + --danger-color: #e74c3c; + ~ 一元运算符“--”后面缺少表达式。 所在位置 行:12 字符: 15 + --danger-color: #e74c3c; + ~~~~~~~~~~~~~ 表达式或语句中包含意外的标记“danger-color:”。 并未报告所有分析错误。请更正报告的错误并重试。 + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : MissingExpressionAfterOperator PS C:\Users\Administrator> # 1. 保存修复后的主脚本 >> $ecosystemManagerScript = @' >> # 完整修复后的 ProjectEcosystemManager.ps1 内容 >> # 包含之前的所有修复 >> '@ >> >> Set-Content -Path "E:\ProjectEcosystem\ProjectMonitor\Scripts\ProjectEcosystemManager.ps1" -Value $ecosystemManagerScript >> >> # 2. 保存服务安装脚本 >> $serviceScript = @' >> # 完整修复后的 Install-EcosystemService.ps1 内容 >> '@ >> >> Set-Content -Path "E:\Install-EcosystemService.ps1" -Value $serviceScript >> >> # 3. 创建仪表板目录 >> $dashboardDir = "E:\ProjectEcosystem\Dashboard" >> if (-not (Test-Path $dashboardDir)) { >> New-Item -ItemType Directory -Path $dashboardDir -Force | Out-Null >> } >> >> # 4. 保存仪表板文件 >> $dashboardHtml = @' >> # 上面修复后的 index.html 内容 >> '@ >> >> Set-Content -Path "$dashboardDir\index.html" -Value $dashboardHtml -Encoding UTF8 >> >> # 5. 安装服务(强制卸载旧版本后再安装) >> & "E:\Install-EcosystemService.ps1" -Action Uninstall >> & "E:\Install-EcosystemService.ps1" -Action Install >> >> # 6. 启动服务 >> Start-Service -Name ProjectEcosystemManager >> >> # 7. 验证服务状态 >> Get-Service -Name ProjectEcosystemManager >> Start-Service : 由于以下错误无法启动服务“ProjectEcosystemManager (ProjectEcosystemManager)”: 无法启动计算机“.”上的 服务 ProjectEcosystemManager。 所在位置 行:34 字符: 1 + Start-Service -Name ProjectEcosystemManager + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : OpenError: (System.ServiceProcess.ServiceController:ServiceController) [Start-Service], ServiceCommandException + FullyQualifiedErrorId : CouldNotStartService,Microsoft.PowerShell.Commands.StartServiceCommand Status Name DisplayName ------ ---- ----------- Stopped ProjectEcosyste... ProjectEcosystemManager PS C:\Users\Administrator> .\ProjectEcosystemManager.ps1 >> .\ProjectEcosystemManager.ps1 : 无法将“.\ProjectEcosystemManager.ps1”项识别为 cmdlet、函数、脚本文件或可运行程序的名 称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。 所在位置 行:1 字符: 1 + .\ProjectEcosystemManager.ps1 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (.\ProjectEcosystemManager.ps1:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException PS C:\Users\Administrator> Get-EventLog -LogName Application -Source "ProjectEcosystemManager" -Newest 20 >> Get-EventLog : 未找到匹配项 所在位置 行:1 字符: 1 + Get-EventLog -LogName Application -Source "ProjectEcosystemManager" - ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (:) [Get-EventLog], ArgumentException + FullyQualifiedErrorId : GetEventLogNoEntriesFound,Microsoft.PowerShell.Commands.GetEventLogCommand PS C:\Users\Administrator> # 测试监控功能 >> .\ProjectEcosystemManager.ps1 -TestMonitor >> >> # 测试Git更新 >> .\ProjectEcosystemManager.ps1 -TestGit >> .\ProjectEcosystemManager.ps1 : 无法将“.\ProjectEcosystemManager.ps1”项识别为 cmdlet、函数、脚本文件或可运行程序的名 称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。 所在位置 行:2 字符: 1 + .\ProjectEcosystemManager.ps1 -TestMonitor + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (.\ProjectEcosystemManager.ps1:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException .\ProjectEcosystemManager.ps1 : 无法将“.\ProjectEcosystemManager.ps1”项识别为 cmdlet、函数、脚本文件或可运行程序的名 称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。 所在位置 行:5 字符: 1 + .\ProjectEcosystemManager.ps1 -TestGit + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (.\ProjectEcosystemManager.ps1:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException PS C:\Users\Administrator> sc.exe qc ProjectEcosystemManager >> [SC] QueryServiceConfig 成功 SERVICE_NAME: ProjectEcosystemManager TYPE : 10 WIN32_OWN_PROCESS START_TYPE : 2 AUTO_START ERROR_CONTROL : 1 NORMAL BINARY_PATH_NAME : # 使用完整路径执行安装脚本 LOAD_ORDER_GROUP : TAG : 0 DISPLAY_NAME : ProjectEcosystemManager DEPENDENCIES : SERVICE_START_NAME : LocalSystem PS C:\Users\Administrator> “
最新发布
08-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值