Repository navigation
SPP prefetcher OOB bug #668
Copy link
Copy link
Open
Labels
Description
Describe the bug
The SPP prefetcher in prefetcher/spp_dev has out of bounds memory write:
[VMEM] WARNING: physical memory size is smaller than virtual memory size.
*** ChampSim Multicore Out-of-Order Simulator ***
Warmup Instructions: 200000000
Simulation Instructions: 500000000
Number of CPUs: 1
Page size: 4096
Initialize SIGNATURE TABLE
ST_SET: 1
ST_WAY: 256
ST_TAG_BIT: 16
Initialize PATTERN TABLE
PT_SET: 512
PT_WAY: 4
SIG_DELTA_BIT: 7
C_SIG_BIT: 4
C_DELTA_BIT: 4
Initialize PREFETCH FILTER
FILTER_SET: 1024
=================================================================
==958115==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5060002dd6e0 at pc 0x55e2f37a5336 bp 0x7ffe046055f0 sp 0x7ffe046055e8
WRITE of size 4 at 0x5060002dd6e0 thread T0
#0 0x55e2f37a5335 in spp_dev::PATTERN_TABLE::read_pattern(unsigned int, std::vector<long, std::allocator<long> >&, std::vector<unsigned int, std::allocator<unsigned int> >&, unsigned int&, unsigned int&, unsigned int&, unsigned int&) prefetcher/spp_dev/spp_dev.cc:363
#1 0x55e2f37a97f6 in spp_dev::prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, unsigned char, bool, access_type, unsigned int) prefetcher/spp_dev/spp_dev.cc:73
#2 0x55e2f359c3d0 in auto CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda(auto:1&)#1}::operator()<spp_dev>(spp_dev&) const /home/jiegec/ChampSim/inc/cache.h:355
#3 0x55e2f359c3d0 in auto CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}::operator()<spp_dev>(spp_dev&) const /home/jiegec/ChampSim/inc/cache.h:368
#4 0x55e2f359c3d0 in unsigned int std::__invoke_impl<unsigned int, CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, spp_dev&>(std::__invoke_other, CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}&&, spp_dev&) /usr/include/c++/14/bits/invoke.h:61
#5 0x55e2f359c3d0 in std::__invoke_result<CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, spp_dev&>::type std::__invoke<CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, spp_dev&>(CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}&&, spp_dev&) /usr/include/c++/14/bits/invoke.h:96
#6 0x55e2f359c3d0 in decltype(auto) std::__apply_impl<CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, std::tuple<spp_dev>&, 0ul>(CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}&&, std::tuple<spp_dev>&, std::integer_sequence<unsigned long, 0ul>) /usr/include/c++/14/tuple:2923
#7 0x55e2f359c3d0 in decltype(auto) std::apply<CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, std::tuple<spp_dev>&>(CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}&&, std::tuple<spp_dev>&) /usr/include/c++/14/tuple:2938
#8 0x55e2f359c3d0 in CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int) /home/jiegec/ChampSim/inc/cache.h:368
#9 0x55e2f3481d22 in CACHE::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int) const src/cache.cc:800
#10 0x55e2f3481d22 in CACHE::try_hit(CACHE::tag_lookup_type const&) src/cache.cc:268
#11 0x55e2f349394e in operator()<CACHE::tag_lookup_type> src/cache.cc:511
#12 0x55e2f349394e in operator()<std::_Deque_iterator<CACHE::tag_lookup_type, CACHE::tag_lookup_type&, CACHE::tag_lookup_type*> > /usr/include/c++/14/bits/predefined_ops.h:395
#13 0x55e2f349394e in __find_if<std::_Deque_iterator<CACHE::tag_lookup_type, CACHE::tag_lookup_type&, CACHE::tag_lookup_type*>, __gnu_cxx::__ops::_Iter_negate<CACHE::operate()::<lambda(const auto:49&)> > > /usr/include/c++/14/bits/stl_algobase.h:2137
#14 0x55e2f349394e in __find_if_not<std::_Deque_iterator<CACHE::tag_lookup_type, CACHE::tag_lookup_type&, CACHE::tag_lookup_type*>, __gnu_cxx::__ops::_Iter_pred<CACHE::operate()::<lambda(const auto:49&)> > > /usr/include/c++/14/bits/stl_algo.h:114
#15 0x55e2f349394e in __stable_partition<std::_Deque_iterator<CACHE::tag_lookup_type, CACHE::tag_lookup_type&, CACHE::tag_lookup_type*>, __gnu_cxx::__ops::_Iter_pred<CACHE::operate()::<lambda(const auto:49&)> > > /usr/include/c++/14/bits/stl_algo.h:1530
#16 0x55e2f34b2736 in stable_partition<std::_Deque_iterator<CACHE::tag_lookup_type, CACHE::tag_lookup_type&, CACHE::tag_lookup_type*>, CACHE::operate()::<lambda(const auto:49&)> > /usr/include/c++/14/bits/stl_algo.h:1579
#17 0x55e2f34b2736 in CACHE::operate() src/cache.cc:511
#18 0x55e2f36b0fd2 in champsim::operable::_operate() src/operable.cc:36
#19 0x55e2f36b0fd2 in champsim::operable::operate_on(champsim::chrono::clock const&) src/operable.cc:27
#20 0x55e2f34e6f4e in champsim::do_cycle(champsim::environment&, std::vector<champsim::tracereader, std::allocator<champsim::tracereader> >&, std::vector<unsigned long, std::allocator<unsigned long> >, champsim::chrono::clock&) src/champsim.cc:49
#21 0x55e2f34ec25b in champsim::do_phase(champsim::phase_info const&, champsim::environment&, std::vector<champsim::tracereader, std::allocator<champsim::tracereader> >&, champsim::chrono::clock&) src/champsim.cc:91
#22 0x55e2f3426002 in champsim::main(champsim::environment&, std::vector<champsim::phase_info, std::allocator<champsim::phase_info> >&, std::vector<champsim::tracereader, std::allocator<champsim::tracereader> >&) src/champsim.cc:193
#23 0x55e2f3430636 in main src/main.cc:123
#24 0x7f09275c4ca7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#25 0x7f09275c4d64 in __libc_start_main_impl ../csu/libc-start.c:360
#26 0x55e2f3431e40 in _start (/home/jiegec/ChampSim/bin/champsim+0x48e40) (BuildId: a5788edfb02cf186dbf7de56ad176a03450be9c5)
0x5060002dd6e0 is located 0 bytes after 64-byte region [0x5060002dd6a0,0x5060002dd6e0)
allocated by thread T0 here:
#0 0x7f0927c09778 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:95
#1 0x55e2f37a9191 in std::__new_allocator<unsigned int>::allocate(unsigned long, void const*) /usr/include/c++/14/bits/new_allocator.h:151
#2 0x55e2f37a9191 in std::allocator_traits<std::allocator<unsigned int> >::allocate(std::allocator<unsigned int>&, unsigned long) /usr/include/c++/14/bits/alloc_traits.h:515
#3 0x55e2f37a9191 in std::_Vector_base<unsigned int, std::allocator<unsigned int> >::_M_allocate(unsigned long) /usr/include/c++/14/bits/stl_vector.h:380
#4 0x55e2f37a9191 in std::_Vector_base<unsigned int, std::allocator<unsigned int> >::_M_create_storage(unsigned long) /usr/include/c++/14/bits/stl_vector.h:398
#5 0x55e2f37a9191 in std::_Vector_base<unsigned int, std::allocator<unsigned int> >::_Vector_base(unsigned long, std::allocator<unsigned int> const&) /usr/include/c++/14/bits/stl_vector.h:334
#6 0x55e2f37a9191 in std::vector<unsigned int, std::allocator<unsigned int> >::vector(unsigned long, std::allocator<unsigned int> const&) /usr/include/c++/14/bits/stl_vector.h:557
#7 0x55e2f37a9191 in spp_dev::prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, unsigned char, bool, access_type, unsigned int) prefetcher/spp_dev/spp_dev.cc:37
#8 0x55e2f359c3d0 in auto CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda(auto:1&)#1}::operator()<spp_dev>(spp_dev&) const /home/jiegec/ChampSim/inc/cache.h:355
#9 0x55e2f359c3d0 in auto CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}::operator()<spp_dev>(spp_dev&) const /home/jiegec/ChampSim/inc/cache.h:368
#10 0x55e2f359c3d0 in unsigned int std::__invoke_impl<unsigned int, CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, spp_dev&>(std::__invoke_other, CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}&&, spp_dev&) /usr/include/c++/14/bits/invoke.h:61
#11 0x55e2f359c3d0 in std::__invoke_result<CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, spp_dev&>::type std::__invoke<CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, spp_dev&>(CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}&&, spp_dev&) /usr/include/c++/14/bits/invoke.h:96
#12 0x55e2f359c3d0 in decltype(auto) std::__apply_impl<CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, std::tuple<spp_dev>&, 0ul>(CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}&&, std::tuple<spp_dev>&, std::integer_sequence<unsigned long, 0ul>) /usr/include/c++/14/tuple:2923
#13 0x55e2f359c3d0 in decltype(auto) std::apply<CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}, std::tuple<spp_dev>&>(CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int)::{lambda((auto:1&)...)#1}&&, std::tuple<spp_dev>&) /usr/include/c++/14/tuple:2938
#14 0x55e2f359c3d0 in CACHE::prefetcher_module_model<spp_dev>::impl_prefetcher_cache_operate(champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, champsim::address_slice<champsim::static_extent<(champsim::data::bits)64, (champsim::data::bits)0> >, bool, bool, access_type, unsigned int) /home/jiegec/ChampSim/inc/cache.h:368
SUMMARY: AddressSanitizer: heap-buffer-overflow prefetcher/spp_dev/spp_dev.cc:363 in spp_dev::PATTERN_TABLE::read_pattern(unsigned int, std::vector<long, std::allocator<long> >&, std::vector<unsigned int, std::allocator<unsigned int> >&, unsigned int&, unsigned int&, unsigned int&, unsigned int&)
Shadow bytes around the buggy address:
0x5060002dd400: 00 00 00 00 00 00 00 00 fa fa fa fa fd fd fd fd
0x5060002dd480: fd fd fd fd fa fa fa fa fd fd fd fd fd fd fd fd
0x5060002dd500: fa fa fa fa fd fd fd fd fd fd fd fd fa fa fa fa
0x5060002dd580: fd fd fd fd fd fd fd fd fa fa fa fa fd fd fd fd
0x5060002dd600: fd fd fd fd fa fa fa fa 00 00 00 00 00 00 00 00
=>0x5060002dd680: fa fa fa fa 00 00 00 00 00 00 00 00[fa]fa fa fa
0x5060002dd700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x5060002dd780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x5060002dd800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x5060002dd880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x5060002dd900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
==958115==ABORTING
To Reproduce
Steps to reproduce the behavior:
- Patch the code to use
spp_devand enable ASan:
diff --git a/Makefile b/Makefile
index 6aae9c9c..818953a4 100644
--- a/Makefile
+++ b/Makefile
@@ -16,9 +16,9 @@ override REPLACEMENT_ROOT += $(addsuffix /replacement,$(MODULE_ROOT))
# vcpkg integration
TRIPLET_DIR = $(patsubst %/,%,$(firstword $(filter-out $(ROOT_DIR)/vcpkg_installed/vcpkg/, $(wildcard $(ROOT_DIR)/vcpkg_installed/*/))))
-override CPPFLAGS += -I$(OBJ_ROOT)
+override CPPFLAGS += -I$(OBJ_ROOT) -g -fsanitize=address
override LDFLAGS += -L$(TRIPLET_DIR)/lib -L$(TRIPLET_DIR)/lib/manual-link
-override LDLIBS += -lCLI11 -llzma -lz -lbz2 -lfmt
+override LDLIBS += -lCLI11 -llzma -lz -lbz2 -lfmt -fsanitize=address
.PHONY: all clean compile_commands compile_commands_clean configclean test pytest maketest
diff --git a/champsim_config.json b/champsim_config.json
index d8a33e13..28f14b48 100644
--- a/champsim_config.json
+++ b/champsim_config.json
@@ -68,7 +68,7 @@
"prefetch_as_load": false,
"virtual_prefetch": false,
"prefetch_activate": "LOAD,PREFETCH",
- "prefetcher": "no"
+ "prefetcher": "spp_dev"
},
"L2C": {- Compile and run:
./config.sh champsim_config.json -v
make -j
bin/champsim --warmup-instructions 200000000 --simulation-instructions 500000000 600.perlbench_s-210B.champsimtrace.xzExpected behavior
It should not crash.
Output
Pasted above.
Desktop (please complete the following information):
- OS: Linux
- Compiler: GCC
- Version: Latest master commit 06de8d3
Additional context
The problem lies in pf_q_tail: it increases without bounds checking.
Reactions are currently unavailable
Activity
ngober commentedon Nov 25, 2025
This looks like it could be fixed if
confidence_qwas made into astd::vector. The problem here is that we really shouldn't be using arrays passed as pointers without any management.