Merge ~info-martin-konrad/epics-base:make-protected-dtors-non-virtual into ~epics-core/epics-base/+git/epics-base:3.15

Proposed by Martin Konrad
Status: Needs review
Proposed branch: ~info-martin-konrad/epics-base:make-protected-dtors-non-virtual
Merge into: ~epics-core/epics-base/+git/epics-base:3.15
Diff against target: 40 lines (+4/-4)
1 file modified
src/libCom/timer/epicsTimer.h (+4/-4)
Reviewer Review Type Date Requested Status
Jeff Hill Needs Resubmitting
Review via email: mp+382156@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Martin Konrad (info-martin-konrad) wrote :

Hi Jeff,
Please take a look at the following minor merge request for the existing
timer code:

https://code.launchpad.net/~info-martin-konrad/epics-base/+git/epics-base/+merge/382156

Does this make sense?

Martin

Revision history for this message
Jeff Hill (johill-lanl) wrote :

> Please take a look at the following minor merge request for the existing
> timer code:
>
> https://code.launchpad.net/~info-martin-konrad/epics-base/+git/epics-
> base/+merge/382156
>
> Does this make sense?

This interface was actually one of my first forays into C++ library interface design. Today I would design the destroying part of the interface differently.

Yes I agree that their logical conclusions at this link are correct. The pure virtual destruct cant be called by users so the small overhead for its existence isn't required. It isn't harmful, but it does impose a small memory penalty, and therefore should not have been included in the original interface.

The pure virtual base destruct interface actually does protect the library implementation itself from inadvertently destroying through the base, but this is admittedly a much more tolerable risk.

The only downside to this proposal is that it is an interface change, requiring recompilation of _all_ user codes which are linked with shareable libraries. If this recompilation doesnt occur I suspect that there is real risk for run time failure depending on the compiler implementation. This is because the layout of the vtbl will certainly change. So this change is arguably appropriate for appearing in a new major release, but not into a point release.

So I agree in principal with the change, but remembering to introduce it into base at the appropriate time is the primary difficulty.

So the crux question is what version of base does this go into?

I will add these changes to my version of the timer queue assuming that we might need to remember to back them out if someone decides to back patch the heap algorithm changes into a point release.

Another consideration is that certain C++ compilers will throw warnings for _any_ class with virtual functions that does not have a pure virtual base.

review: Needs Information
Revision history for this message
Jeff Hill (johill-lanl) wrote :

I just now experimented with introducing one of the above changes and I immediately see warning from gcc.

base/timerQueueFix/src/libCom/timer/timer.cpp: In member function ‘virtual void Timer::destroy()’:
base/timerQueueFix/src/libCom/timer/timer.cpp:42:12: warning: deleting object of polymorphic class type ‘Timer’ which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]
     delete this;

> gcc --version
gcc (SUSE Linux) 4.8.5

So I am not well convinced that this is a good idea. Our only cost for the pure virtual DTOR is a small increase in the VTBL size which is probably insignificant.

review: Needs Fixing
Revision history for this message
Jeff Hill (johill-lanl) wrote :

I will not, at this time, introduce these changes into my version. Pending obtaining compelling positives for doing this.

Our only cost for the library implementation safety of a pure virtual DTOR is the small increase in the VTBL size which is probably insignificant.

review: Needs Resubmitting
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

I think this change is benign, though only because of the unsafe legacy design where virtual epicsTimer::destroy() take the place of destructor.

Unmerged commits

e6aaf3d... by Martin Konrad

Make the protected dtors in epicsTimer.h non-virtual

These dtors seem to be marked protected to prevent destructing
a derived object via a base-class pointer. If this dtor cannot
be called there is no need to mark it virtual. Remove "virtual"
to avoid confusion. Refer to
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-dtor-virtual
for details.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/libCom/timer/epicsTimer.h b/src/libCom/timer/epicsTimer.h
index 72270f2..0839ea8 100644
--- a/src/libCom/timer/epicsTimer.h
+++ b/src/libCom/timer/epicsTimer.h
@@ -67,7 +67,7 @@ public:
67 double getExpireDelay ();67 double getExpireDelay ();
68 virtual void show ( unsigned int level ) const = 0;68 virtual void show ( unsigned int level ) const = 0;
69protected:69protected:
70 virtual ~epicsTimer () = 0; /* protected => delete() must not be called */70 ~epicsTimer (); /* protected => delete() must not be called */
71};71};
7272
73class epicsTimerQueue {73class epicsTimerQueue {
@@ -75,7 +75,7 @@ public:
75 virtual epicsTimer & createTimer () = 0;75 virtual epicsTimer & createTimer () = 0;
76 virtual void show ( unsigned int level ) const = 0;76 virtual void show ( unsigned int level ) const = 0;
77protected:77protected:
78 epicsShareFunc virtual ~epicsTimerQueue () = 0;78 epicsShareFunc ~epicsTimerQueue ();
79};79};
8080
81class epicsTimerQueueActive81class epicsTimerQueueActive
@@ -85,7 +85,7 @@ public:
85 bool okToShare, unsigned threadPriority = epicsThreadPriorityMin + 10 );85 bool okToShare, unsigned threadPriority = epicsThreadPriorityMin + 10 );
86 virtual void release () = 0; 86 virtual void release () = 0;
87protected:87protected:
88 epicsShareFunc virtual ~epicsTimerQueueActive () = 0;88 epicsShareFunc ~epicsTimerQueueActive ();
89};89};
9090
91class epicsTimerQueueNotify {91class epicsTimerQueueNotify {
@@ -97,7 +97,7 @@ public:
97 /* return this quantum in seconds. If unknown then return zero. */97 /* return this quantum in seconds. If unknown then return zero. */
98 virtual double quantum () = 0;98 virtual double quantum () = 0;
99protected:99protected:
100 epicsShareFunc virtual ~epicsTimerQueueNotify () = 0;100 epicsShareFunc ~epicsTimerQueueNotify ();
101};101};
102102
103class epicsTimerQueuePassive103class epicsTimerQueuePassive

Subscribers

People subscribed via source and target branches