Skip to content

Conversation

@Dimi1010
Copy link
Collaborator

@Dimi1010 Dimi1010 commented Oct 25, 2025

Summary

The PR focuses on streamlining the logic for setting device filters, and removing possibility of errors. It overhauls the IFilterableDevice to utilize a Template Method Pattern, instead of direct pure virtual methods. The cause for the change is the problematic shadowing of methods when a derived class declares a override a virtual method. It fixes one such issue that was left unmitigated in PcapNG type devices hiding setFilter(GeneralFilter).

Override methods and shadowing

The problem

The shadowing issue becomes relevant when a base class declares two or more overloads of a virtual method. If a derived class overrides only one of the overloads, the C++ language spec hides all other overloads from the derived class's scope by default.

For example:

struct Base {
   virtual void foo(int x);
   virtual void foo(std::string x);
}

struct Derived : public Base {
   void foo(int x) override;
}

int main() {
  Derived d;
  static_cast<Base&>(d).foo(std::string{}); // <-This will compile. foo(std::string) is visible for the base class.
  d.foo(std::string{}); // <- This will not compile. foo(std::string) is shadowed.
}

Such issues are hard to spot due to their subtlety.
Such was the case in PcapNGFileReaderDevice and PcapNGFileWriterDevice which only declared setFilter(std::string), making the interface setFilter(GenericFilter const&) unavailable through the types.

Solutions

There are three possible ways to fix this issue:

  1. Ensure all overloads are overridden in a derived class.
  2. Ensure all derived classes that override at least one method have a using Base::foo; declaration.
  3. Keep all overloaded methods as non-virtual and extract uniquely named virtual methods to be overridden for derived classes.

Proposed solution

Previously, most of the devices utilized option 2, but that is brittle as it requires developer knowledge of the issue and scrutinous review as observed due to existing issues with PcapNG-type reader devices.

This PR refactors the code to utilize option 3 as an alternative. This was selected due to the overload setFilter(GeneralFilter) cleanly delegating the majority of the work to setFilter(std::string).

The solution follows a Template Method Pattern by introducing a protected hook method doUpdateFilter(std::string) and keeping the public API non-virtual.

The change allows all calls from setFilter and clearFilter to be delegated to the device hook, while keeping the public API unchanged. The following change has the following benefits:

  • Removes the possibility of shadowing override overloads, as they are no longer virtual. It is still possible to shadow a method by adding another overload in a derived class, but that situation is a lot more rare.
  • Minimized the number of methods that need to be overriden for a specific device.
  • Provides a common place that is fully controlled by the base class for operations that are shared between device implementations. (e.g. possibly a device open check)

Behaviour changes

  • clearFilter now mirrors setFilter and requires the device to be in an open state due to reusing the same filter hook. This differs from the previous implementation where clearFilter could possibly succeed depending on the device's implementation of the method.

This prevents issues such as shadowing overloads when multiple overloads are available and only 1 is overloaded.
For example: `setFilter` previously required `using::setFilter` declaration on every class that included an override it.

The change consolidates all device specific filter update code in `doUpdateFilter` hook.
The methods `setFiltter` (+overloads) / `clearFilter` are no longer virtual and can be overridden. Their implementation is
now forwarded through `doUpdateFilter`.
@Dimi1010 Dimi1010 marked this pull request as ready for review October 25, 2025 10:04
@Dimi1010 Dimi1010 requested a review from seladb as a code owner October 25, 2025 10:04
@codecov
Copy link

codecov bot commented Oct 25, 2025

Codecov Report

❌ Patch coverage is 94.11765% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.45%. Comparing base (0132d27) to head (8e97480).

Files with missing lines Patch % Lines
Pcap++/src/PcapDevice.cpp 80.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #2005      +/-   ##
==========================================
+ Coverage   83.41%   83.45%   +0.04%     
==========================================
  Files         311      311              
  Lines       55019    54550     -469     
  Branches    11816    11467     -349     
==========================================
- Hits        45892    45524     -368     
+ Misses       7852     7813      -39     
+ Partials     1275     1213      -62     
Flag Coverage Δ
alpine320 75.89% <100.00%> (+<0.01%) ⬆️
fedora42 75.46% <90.90%> (-0.38%) ⬇️
macos-14 81.57% <83.33%> (+0.07%) ⬆️
macos-15 81.56% <83.33%> (+0.04%) ⬆️
mingw32 70.01% <90.00%> (-0.53%) ⬇️
mingw64 69.98% <90.00%> (-0.43%) ⬇️
npcap ?
rhel94 75.46% <90.00%> (-0.41%) ⬇️
ubuntu2004 59.46% <81.81%> (-0.67%) ⬇️
ubuntu2004-zstd 59.57% <81.81%> (-0.66%) ⬇️
ubuntu2204 75.41% <90.00%> (-0.39%) ⬇️
ubuntu2204-icpx 57.84% <83.33%> (-2.71%) ⬇️
ubuntu2404 75.51% <100.00%> (-0.38%) ⬇️
ubuntu2404-arm64 75.54% <100.00%> (-0.02%) ⬇️
unittest 83.45% <94.11%> (+0.04%) ⬆️
windows-2022 85.42% <90.90%> (+0.16%) ⬆️
windows-2025 85.45% <90.90%> (+0.11%) ⬆️
winpcap 85.45% <90.90%> (-0.09%) ⬇️
xdp 53.00% <0.00%> (-0.53%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant