# ASan demo for exercising the ASan Explorer VS Code extension.
#
#   make            # build with AddressSanitizer + debug info
#   make run-uaf    # run one bug; write logs/uaf.txt
#   make capture    # run all bugs and capture reports under logs/
#   make clean

CXX      ?= g++
BUILDDIR := build
TARGET   := $(BUILDDIR)/asan-demo
LOGDIR   := logs

CXXFLAGS := -std=c++17 -g -O0 -fno-omit-frame-pointer -fsanitize=address
CXXFLAGS += -Wall -Wextra -Wno-array-bounds -Wno-return-local-addr -Wno-stringop-overflow
LDFLAGS  := -fsanitize=address

SRCS := \
	src/main.cpp \
	src/heap_use_after_free.cpp \
	src/heap_buffer_overflow.cpp \
	src/stack_buffer_overflow.cpp \
	src/double_free.cpp \
	src/use_after_return.cpp

OBJS := $(patsubst src/%.cpp,$(BUILDDIR)/%.o,$(SRCS))

.PHONY: all clean capture logs run-uaf run-overflow run-stack run-double run-return

all: $(TARGET)

$(TARGET): $(OBJS)
	@mkdir -p $(BUILDDIR)
	$(CXX) $(LDFLAGS) -o $@ $^

$(BUILDDIR)/%.o: src/%.cpp src/bugs.hpp
	@mkdir -p $(BUILDDIR)
	$(CXX) $(CXXFLAGS) -c -o $@ $<

define run_bug
	@mkdir -p $(LOGDIR)
	@echo "==> running bug: $(1)"
	ASAN_OPTIONS=symbolize=1:detect_leaks=0:detect_stack_use_after_return=1 \
		./$(TARGET) $(1) >$(LOGDIR)/$(1).stdout.txt 2>$(LOGDIR)/$(1).txt || true
	@if [ "$(1)" = "uaf" ]; then cp $(LOGDIR)/$(1).txt log.txt; fi
	@echo "    wrote $(LOGDIR)/$(1).txt"
	@grep -q 'Sanitizer' $(LOGDIR)/$(1).txt \
		&& echo "    ok: sanitizer report detected" \
		|| echo "    warn: no sanitizer banner in report (check build flags)"
endef

run-uaf: $(TARGET)
	$(call run_bug,uaf)

run-overflow: $(TARGET)
	$(call run_bug,overflow)

run-stack: $(TARGET)
	$(call run_bug,stack)

run-double: $(TARGET)
	$(call run_bug,double)

run-return: $(TARGET)
	$(call run_bug,return)

capture: run-uaf run-overflow run-stack run-double run-return
	@echo ""
	@echo "All reports under $(LOGDIR)/ — load any with ASan Explorer."
	@ls -la $(LOGDIR)/*.txt

logs: capture

clean:
	rm -rf $(BUILDDIR) $(LOGDIR) log.txt
