LeetCode滑动窗口最大值问题中AddressSanitizer堆释放后使用错误排查
关于LeetCode 239题滑动窗口最大值的堆释放后使用错误问题
我目前正在学习C++,尝试解决LeetCode上的239. Sliding Window Maximum问题。尽管代码中从未调用过free(),却持续遇到ERROR: AddressSanitizer: heap-use-after-free错误,请问可能的原因是什么?
我的代码:
#include <vector> #include <deque> class Solution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k) { if (k == 1) { return nums; } deque<int> q = {nums[k-1]}; deque<int> qi = {k-1}; for (int i = k-2; i >= 0; i--) { if (nums[i] > q.front()) { q.push_front(nums[i]); qi.push_front(i); } } vector<int> output = {q.front()}; for (int i = k; i < nums.size(); i++) { if (qi.front() < i - k + 1) { q.pop_front(); qi.pop_front(); } if (q.size() > 0) { while (q.back() <= nums[i]) { q.pop_back(); qi.pop_back(); } } q.push_back(nums[i]); qi.push_back(i); output.push_back(q.front()); } return output; } };
完整错误信息:
================================================================== ==23==ERROR: AddressSanitizer: heap-use-after-free on address 0x6150000009fc at pc 0x000000356a92 bp 0x7ffd9138ecb0 sp 0x7ffd9138eca8 READ of size 4 at 0x6150000009fc thread T0 #2 0x7f1796504082 (/lib/x86_64-linux-gnu/libc.so.6+0x24082) 0x6150000009fc is located 508 bytes inside of 512-byte region [0x615000000800,0x615000000a00) freed by thread T0 here: #4 0x7f1796504082 (/lib/x86_64-linux-gnu/libc.so.6+0x24082) previously allocated by thread T0 here: #4 0x7f1796504082 (/lib/x86_64-linux-gnu/libc.so.6+0x24082) Shadow bytes around the buggy address: 0x0c2a7fff80e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c2a7fff80f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c2a7fff8100: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2a7fff8110: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2a7fff8120: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd =>0x0c2a7fff8130: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd[fd] 0x0c2a7fff8140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c2a7fff8150: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2a7fff8160: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2a7fff8170: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2a7fff8180: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==23==ABORTING
问题原因及修复方案
核心问题:双端队列同步逻辑错误+空队列未检查
你的代码中q(存数值)和qi(存索引)需要严格同步,但初始化和滑动窗口处理的逻辑破坏了这种同步性,且未在访问队列元素前检查是否为空,导致访问已释放的队列内存,触发heap-use-after-free错误。
具体问题点:
- 初始化逻辑错误
原初始化代码只在nums[i] > q.front()时才添加元素,无法构建正确的单调递减队列,导致队列元素数量不足,后续滑动窗口处理时容易出现队列空了还访问的情况。 - 未检查队列是否为空就访问元素
- 滑动窗口循环中,直接调用
qi.front()而未检查qi是否为空,若队列已空,会访问已释放的内存。 while (q.back() <= nums[i])循环中,虽然有if (q.size() > 0)判断,但循环过程中q可能被清空,此时q.back()仍会访问空队列。
- 滑动窗口循环中,直接调用
- 窗口外元素移除不彻底
原代码用if判断移除窗口外元素,可能存在多个元素在窗口外的情况,未全部移除会导致队列状态异常。
修复步骤:
- 修正初始化逻辑
遍历第一个窗口的所有元素,维护单调递减队列:移除队列尾部所有小于等于当前元素的元素,再加入当前元素和索引,确保队首是窗口最大值。 - 访问队列前强制检查是否为空
所有调用front()或back()的操作前,都要加!empty()判断。 - 彻底移除窗口外元素
用while循环替换if,确保所有不在当前窗口内的元素都被移除。
修复后的完整代码:
#include <vector> #include <deque> class Solution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k) { if (k == 1) { return nums; } deque<int> q; deque<int> qi; // 初始化第一个窗口,构建单调递减队列 for (int i = 0; i < k; ++i) { while (!q.empty() && nums[i] >= q.back()) { q.pop_back(); qi.pop_back(); } q.push_back(nums[i]); qi.push_back(i); } vector<int> output = {q.front()}; for (int i = k; i < nums.size(); ++i) { // 移除所有不在当前窗口内的元素 while (!qi.empty() && qi.front() < i - k + 1) { q.pop_front(); qi.pop_front(); } // 维护单调递减队列 while (!q.empty() && nums[i] >= q.back()) { q.pop_back(); qi.pop_back(); } q.push_back(nums[i]); qi.push_back(i); output.push_back(q.front()); } return output; } };
为什么会触发heap-use-after-free?
C++标准库的deque在元素被弹出后,内部内存可能被释放。当队列为空时,调用front()或back()属于未定义行为,AddressSanitizer会检测到这种对已释放内存的访问,抛出该错误。你的代码中未检查队列是否为空,加上队列同步逻辑错误,最终导致了这个问题。
内容的提问来源于stack exchange,提问作者haoyu
相关产品推荐
相关产品推荐

