Term Project Ideas

CS 5187 — Software Analysis · Monsoon 2026 · Dept. of CSE, IIT Guwahati
Proposal due Sun 20 Sep 2026 · do not start work before written approval.
These are only some project ideas — you are free to propose your own.
Submit the proposal on the project proposal form · one submission per team — the team leader fills the form, other members must not submit it again.
Start from the Problem line: if the problem does not interest you, no amount of tooling will make the semester enjoyable. Then read one or two of the linked papers — abstract and evaluation section first. If you cannot picture what you would build after reading them, pick a different entry. You are equally welcome to propose an idea that is not here at all; the project rules apply either way.

A · Fuzzing & greybox testing Topic 2 · L14–L16

A1Automated fuzz-harness generation for a C library

Problem
No test driver ever calls most of the API The fuzzer works fine. Nothing calls most of the library’s functions, so that code is never tested.
Example targets
libarchive, libxml2, FFmpeg demuxers, OpenSSL, libpng, zlib-ng.
Read

A2Making sanitizers cheap: decoupled sanitization

Problem
Bug detection is too slow to leave switched on The sanitizer would catch the bug. It slows every run down so much that you cannot afford to use it on all of them.
Example targets
Any OSS-Fuzz project with a heavy sanitizer cost — SQLite, FFmpeg, Wireshark dissectors.
Read

A3Grammar-aware fuzzing for one structured format

Problem
Random inputs are rejected before they reach the code If the parser throws an input out, nothing behind the parser is ever tested. The inputs have to be valid first.
Example targets
SQLite / Postgres (SQL), V8 or SpiderMonkey (JS), FFmpeg (containers), Yosys / Verilator (HDL).
Read

A4Seed scheduling as a control problem

Problem
Which input should the fuzzer spend the next second on? A scheduling question. The hard part is showing your answer is better, because fuzzing results are noisy.
Example targets
FuzzBench-style benchmark for the measurement, one real project for the bug hunt.
Read

B · Coverage, mutation & test adequacy Topic 2 · L13

B1Differential testing of coverage measurement tools

Problem
The tool that measures your testing is itself untested Everyone trusts coverage tools and nobody checks them. Run several on the same program: where they disagree, one is wrong.
Example targets
LLVM's llvm-cov, GCC's gcov, JaCoCo, coverage.py — all with live issue trackers.
Read

B2The equivalent-mutant problem, revisited with LLMs

Problem
Some mutants cannot be killed, and finding them is expensive A mutant that behaves exactly like the original wastes everyone’s time. Deciding which ones those are is undecidable in general.
Example targets
A mid-sized C/Java project with a strong existing test suite.
Read

B3Do coverage and mutation scores predict LLM test-suite quality?

Problem
Does a high coverage score still mean a good test suite? Coverage was always a rough stand-in for finding faults. It may be a worse one when a model wrote the tests in order to maximise it.
Example targets
Defects4J-style real-fault sets; a real project's regression suite.
Read

C · Static analysis: dataflow, pointers, abstract interpretation Topics 3–4 · L17–L19, L21–L24

C1Make a pointer analysis scale

Problem
The analysis is too slow to finish on real code Precise pointer analysis is cubic. On a large program you either give up precision or find a way to spend it only where it pays.
Example targets
LLVM itself, Chromium components, SQLite, Redis.
Read

C2Hunt the siblings of a known CVE with typestate analysis

Problem
A fixed bug tells you what to look for elsewhere A patch shows one wrong way to use an API. Turn it into a rule, then check whether the rest of the codebase breaks the same rule.
Example targets
OpenSSL, the Linux kernel's driver subsystems, FFmpeg — anywhere a CVE class recurs.
Read

C3Why do developers suppress static-analysis warnings?

Problem
Developers switch warnings off, sometimes wrongly Every large codebase is full of suppressions. Some of them hide a warning that was right.
Example targets
Chromium, LLVM, the Linux kernel — large, long-lived, heavily annotated.
Read

C4Neuro-symbolic static analysis

Problem
What should an analysis do when it cannot decide? A sound analysis gives up and reports everything. Use a model at exactly that point — and say plainly which guarantee you gave up.
Example targets
Smart contracts (small, high stakes) or C/C++ with indirect calls.
Read

D · Constraint-based analysis & type systems Topics 5–6 · L25–L30, L32–L33

D1Write the analysis as rules, not as code

Problem
Writing an analysis as rules instead of as code In Datalog you state the rules and the engine works out the answer. Whether it still scales on real code is the open question.
Example targets
A large Java application (Doop-style), a C/C++ project via LLVM, or change-impact analysis across a microservice repository.
Read

D2Types as lightweight specifications: nullability and lifetimes

Problem
Annotations are missing, or they are lying Types like @Nullable are checked on every build. Infer the missing ones, then look hard at any that disagree with the code.
Example targets
A large unannotated Java codebase; Rust crates with hand-written lifetime annotations; a JVM application for the taint-tracking variant.
Read

E · Concurrency & data races Cross-cutting · no lecture

E1Lightweight static data-race detection for C

Problem
A dynamic detector only sees the schedule it happened to run A static detector sees every schedule and reports far too many. Cutting the false alarms is the contribution.
Example targets
Linux kernel subsystems, Redis, PostgreSQL background workers.
Read

E2Concurrency stress testing and litmus tests for a real runtime

Problem
The memory model already tells you which outcomes are legal So the oracle is free: observe an outcome the model forbids and you have found a compiler or runtime bug.
Example targets
JVM/Kotlin, Go's runtime, Rust's atomics, a JS engine's SharedArrayBuffer.
Read

E3Slicing multi-threaded programs so the analysis fits

Problem
Cut the program down until the analysis finishes Whole-program concurrency analysis does not scale. Slice away everything that cannot affect the question you asked.
Example targets
Any large multithreaded C/C++ or Java system.
Read

F · Symbolic execution & test generation Topics 7–8 · L34–L36, L38–L40

F1Symbolic execution for WebAssembly

Problem
WebAssembly is small enough to reason about symbolically Unlike native x86. The question worth asking is what a module can do to the host that runs it.
Example targets
Browser-embedded Wasm, wasmtime, WasmEdge, wasm2c toolchains.
Read

F2Getting past the checks that stop symbolic execution

Problem
Symbolic execution gets stuck at checks it cannot solve Hashes, magic constants, opaque predicates. Let a model guess concrete values; the engine still checks them, so soundness stays put.
Example targets
Obfuscated binaries, malware unpackers, license checks, CTF-style crackmes for the benchmark.
Read

F3Static analysis as a guide for assertion synthesis

Problem
A generated test that only checks for crashes proves little Work out what ought to be true at a program point, then write that down as an assertion.
Example targets
A Python or Java library with a weak existing suite.
Read

G · LLM-assisted program analysis Topic 9 · L41

G1Multi-agent triage of static-analysis alarms

Problem
Scanners report far too much to be usable Filtering helps only if you can show what the filter threw away. One that quietly drops real bugs is worse than no filter.
Example targets
Output of CodeQL, Infer or clang-analyzer on a large C/Java project.
Read

G2An agent with a fuzzer in the loop

Problem
Models guess well but prove nothing Fuzzers are the other way round. Let the model propose and the sanitizer decide — then compare at equal compute.
Example targets
Firmware images, IoT stacks, or a conventional C library with a large API surface.
Read

G3Making an agent explain itself symbolically

Problem
An agent saying “fixed it” is not evidence Make it hand you something you can check yourself: a path condition, an invariant, a failing input.
Example targets
Real issue-fix pairs from a large repository.
Read

G4Hallucinated dependencies as a defensive problem

Problem
Models invent package names that do not exist Anyone can register the invented name. That turns a mistake into an attack, and the defence is yours to build.
Example targets
PyPI, npm, crates.io namespaces.
Read

G5A program knowledge graph for a coding agent

Problem
An agent reads files; it does not understand the program Call graphs, type hierarchies and data flow are exactly what a compiler front end already computes. Build that graph, serve it to the agent as a tool, and measure whether grounded answers beat retrieved text.
Example targets
LLVM or Clang libtooling for C/C++; tree-sitter plus a call-graph pass for Python or Java; any repository large enough that the whole of it does not fit in a context window.
Read

H · Supply-chain security Cross-cutting · no lecture

H1Catching a malicious package before it is installed

Problem
A dependency runs code on your machine before you ever call it An install script is code, and almost nobody reads it. Static and dynamic analysis of package contents is the defence; the hard part is precision, because the registry is mostly benign.
Example targets
npm and PyPI package tarballs; install hooks and post-install scripts; a malicious-package corpus such as Backstabber’s Knife Collection for ground truth.
Read

H2Does a vulnerability deep in the dependency tree actually reach you?

Problem
Most dependency alerts are about code you never call A CVE in a transitive dependency only matters if some path in your program reaches the vulnerable function. That is a reachability question, and reachability is what this course is about.
Example targets
npm or Maven dependency trees; an SBOM for a real application; GitHub advisory data as the vulnerability source.
Read