Skip to content

Case 204: Class Gained a Non-Virtual Method

Field Value
Verdict 🟢 COMPATIBLE
Category Addition (Compatible)
Classification Rule
Platforms Linux
Flags
Detected ChangeKinds func_added
Source files catalog/cases/case204_class_gained_non_virtual_method/
Rule family class-gained-non-virtual-method
Subject Safe changes correctly not flagged

Category: Addition | Verdict: ✅ COMPATIBLE

Verdict and consumer impact

Handle gains an is_open() member function that is not virtual. The class stays non-polymorphic, so no vtable pointer is inserted: sizeof(Handle), its alignment and id_'s offset are all unchanged. The release adds one exported symbol and nothing else. Consumers embedding a Handle by value, deriving from it, or allocating one keep working unmodified.

This is the negative control paired with case203_class_gained_vtable_pointer, which makes the nearest breaking version of the same edit by marking the new member virtual. The pair proves two things about these two fixtures: adding the first virtual function is flagged, and adding an ordinary member function is not.

Old/new diff

v1.h v2.h
(no is_open) bool is_open() const;

abicheck command

g++ -shared -fPIC -g v1.cpp -o libv1.so
g++ -shared -fPIC -g v2.cpp -o libv2.so
abicheck compare libv1.so libv2.so --header old=v1.h --header new=v2.h

Expected abicheck finding

Verdict: COMPATIBLE (exit 0)

func_added: New public function: is_open

vptr_introduced, type_size_changed and type_field_offset_changed are expected not to fire. Those absences are the point of the case.

Minimum evidence

min_evidence: L0 — the added member function is a new mangled export visible in the dynamic symbol table alone. abicheck still reads the headers here so the absence of the layout findings is established on the same evidence tier case203's presence is.

Why abicheck catches it

A non-virtual member function is not part of the object's layout, so diff_types.py finds Handle's size, alignment and member offsets unchanged and reports nothing about the record. diff_symbols.py reports the new mangled export as func_added, a COMPATIBLE kind.

Runtime failure demonstration

Severity: none — verified no observable effect.

g++ -shared -fPIC -g v1.cpp -o libv1.so
g++ -g app.cpp -L. -lv1 -Wl,-rpath,. -o app
./app
# → via factory: id() = 7 / local: id() = 7

g++ -shared -fPIC -g v2.cpp -o libv1.so   # swap in v2, no recompile
./app
# → identical output

Safe redesign

None needed — this is the safe pattern. Adding non-virtual member functions to a released class is the standard way to extend it without touching its layout.

Cross-tool comparison

abidiff and ABICC both report only the added function. The case exists so that the vtable-introduction detector has an adjacent fixture it must stay quiet on, not to separate the tools.


Source files

  • CMakeLists.txt
  • app.cpp
  • v1.cpp
  • v1.h
  • v2.cpp
  • v2.h

See also: Compatibility Catalog · All COMPATIBLE cases · Category: Addition (Compatible) · Rule: Class gained a non-virtual method · Subject: Safe changes correctly not flagged.