Exception safety: not just stopping memory leaks

classic Classic list List threaded Threaded
22 messages Options
12
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Exception safety: not just stopping memory leaks

Paul Licameli
I am trying to ensure exception safety, at least wherever it is possible that read and write operations on block files may fail.

This is harder than just scanning the code for new and delete, and it will be harder to maintain, if other contibutors are not aware of stricter demands and introduce new un-safeties.  And I don't know how to motivate every contributor to have the patience read this email to the end.

It is cleaner to write code that throws on error, with a few appropriate catches that recover from errors; and the many levels of stack in between not needing to be cluttered with testing and propagating of error values.

But those in-between levels cannot completely ignore errors:  they must be appropriately written to "dodge" in between the throw and the catch, by ensuring cleanup of side-effects even when exceptions pass.

The general pseudo-code is:

Do X (with side-effects);
Do big, risky Y;
Undo X.

The "Undo X" step should never be done in-line like that, but instead, should happen within a destructor, and should also be guaranteed not to emit any other exceptions.

Fixing memory leaks is only one special case where "X" is allocating some memory and "undo X" is freeing it, and the tool to do that in a destructor is a smart pointer.

I have lately pushed changes that move other "Undo X" steps into destructors by other means.

One means is valueRestorer, where X is the setting of a variable.

Another is finally, taken from The C++ Programming Language, 4th edition.  Not a built-in construct as in some other languages, but a function definable in C++11, that lets you wrap any code at all in a lambda expression, so that it executes in a destructor of an ad-hoc class.

Another somewhat common thing is locking and unlocking of a mutex, which is best done with wxMutexLocker, or ODLocker.

Sometimes the "Undo X" step is to be cancelled, but only in case if exiting the function along a "success" path; that is, the "Do X" step is conditionally committed.  I do this in some places by calling release() on a generalized std::unique_ptr (one with a second template parameter supplied, the "deleter").

See my recent commits for abundant examples.

I am afraid someone will have to be a nag, examining all contributions, to preserve the levels of safety I attained, and I hope others will learn these not difficult principles well enough, that I don't have to be the only nag.

Does this exhaust what it means to write exception-safe code?  No, one must also be familiar with the notions of weak, strong, and no-fail guarantees, in case of multi-step operations that might complete only some steps and then fail, and I will be referring to these notions too in future code comments.  But this email is long enough now.

PRL



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Gale
Administrator
Paul,

Would it be worth (at least) referring to this on some or all of:

http://wiki.audacityteam.org/wiki/CodingStandards
http://wiki.audacityteam.org/wiki/Quality
http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?

If not a section in the Hackers' Guide, would it justify its own
page in the For Developers category?



Gale


On 22 March 2017 at 01:40, Paul Licameli <[hidden email]> wrote:

> I am trying to ensure exception safety, at least wherever it is possible
> that read and write operations on block files may fail.
>
> This is harder than just scanning the code for new and delete, and it will
> be harder to maintain, if other contibutors are not aware of stricter
> demands and introduce new un-safeties.  And I don't know how to motivate
> every contributor to have the patience read this email to the end.
>
> It is cleaner to write code that throws on error, with a few appropriate
> catches that recover from errors; and the many levels of stack in between
> not needing to be cluttered with testing and propagating of error values.
>
> But those in-between levels cannot completely ignore errors:  they must be
> appropriately written to "dodge" in between the throw and the catch, by
> ensuring cleanup of side-effects even when exceptions pass.
>
> The general pseudo-code is:
>
> Do X (with side-effects);
> Do big, risky Y;
> Undo X.
>
> The "Undo X" step should never be done in-line like that, but instead,
> should happen within a destructor, and should also be guaranteed not to emit
> any other exceptions.
>
> Fixing memory leaks is only one special case where "X" is allocating some
> memory and "undo X" is freeing it, and the tool to do that in a destructor
> is a smart pointer.
>
> I have lately pushed changes that move other "Undo X" steps into destructors
> by other means.
>
> One means is valueRestorer, where X is the setting of a variable.
>
> Another is finally, taken from The C++ Programming Language, 4th edition.
> Not a built-in construct as in some other languages, but a function
> definable in C++11, that lets you wrap any code at all in a lambda
> expression, so that it executes in a destructor of an ad-hoc class.
>
> Another somewhat common thing is locking and unlocking of a mutex, which is
> best done with wxMutexLocker, or ODLocker.
>
> Sometimes the "Undo X" step is to be cancelled, but only in case if exiting
> the function along a "success" path; that is, the "Do X" step is
> conditionally committed.  I do this in some places by calling release() on a
> generalized std::unique_ptr (one with a second template parameter supplied,
> the "deleter").
>
> See my recent commits for abundant examples.
>
> I am afraid someone will have to be a nag, examining all contributions, to
> preserve the levels of safety I attained, and I hope others will learn these
> not difficult principles well enough, that I don't have to be the only nag.
>
> Does this exhaust what it means to write exception-safe code?  No, one must
> also be familiar with the notions of weak, strong, and no-fail guarantees,
> in case of multi-step operations that might complete only some steps and
> then fail, and I will be referring to these notions too in future code
> comments.  But this email is long enough now.
>
> PRL
>
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Darrell Walisser
Maybe worth noting that OpenMP parallel regions cannot throw exceptions. The suggested way to handle that, is to wrap the region in a try, catch *all* exceptions, and save one of them to rethrow when the parallel region exits. Yucky no doubt, but a similar problem would exist for any threaded operation containing resource allocation. By this standard, some of the OpenMP stuff done thus far is certainly not exception safe.

On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews <[hidden email]> wrote:
Paul,

Would it be worth (at least) referring to this on some or all of:

http://wiki.audacityteam.org/wiki/CodingStandards
http://wiki.audacityteam.org/wiki/Quality
http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?

If not a section in the Hackers' Guide, would it justify its own
page in the For Developers category?



Gale


On 22 March 2017 at 01:40, Paul Licameli <[hidden email]> wrote:
> I am trying to ensure exception safety, at least wherever it is possible
> that read and write operations on block files may fail.
>
> This is harder than just scanning the code for new and delete, and it will
> be harder to maintain, if other contibutors are not aware of stricter
> demands and introduce new un-safeties.  And I don't know how to motivate
> every contributor to have the patience read this email to the end.
>
> It is cleaner to write code that throws on error, with a few appropriate
> catches that recover from errors; and the many levels of stack in between
> not needing to be cluttered with testing and propagating of error values.
>
> But those in-between levels cannot completely ignore errors:  they must be
> appropriately written to "dodge" in between the throw and the catch, by
> ensuring cleanup of side-effects even when exceptions pass.
>
> The general pseudo-code is:
>
> Do X (with side-effects);
> Do big, risky Y;
> Undo X.
>
> The "Undo X" step should never be done in-line like that, but instead,
> should happen within a destructor, and should also be guaranteed not to emit
> any other exceptions.
>
> Fixing memory leaks is only one special case where "X" is allocating some
> memory and "undo X" is freeing it, and the tool to do that in a destructor
> is a smart pointer.
>
> I have lately pushed changes that move other "Undo X" steps into destructors
> by other means.
>
> One means is valueRestorer, where X is the setting of a variable.
>
> Another is finally, taken from The C++ Programming Language, 4th edition.
> Not a built-in construct as in some other languages, but a function
> definable in C++11, that lets you wrap any code at all in a lambda
> expression, so that it executes in a destructor of an ad-hoc class.
>
> Another somewhat common thing is locking and unlocking of a mutex, which is
> best done with wxMutexLocker, or ODLocker.
>
> Sometimes the "Undo X" step is to be cancelled, but only in case if exiting
> the function along a "success" path; that is, the "Do X" step is
> conditionally committed.  I do this in some places by calling release() on a
> generalized std::unique_ptr (one with a second template parameter supplied,
> the "deleter").
>
> See my recent commits for abundant examples.
>
> I am afraid someone will have to be a nag, examining all contributions, to
> preserve the levels of safety I attained, and I hope others will learn these
> not difficult principles well enough, that I don't have to be the only nag.
>
> Does this exhaust what it means to write exception-safe code?  No, one must
> also be familiar with the notions of weak, strong, and no-fail guarantees,
> in case of multi-step operations that might complete only some steps and
> then fail, and I will be referring to these notions too in future code
> comments.  But this email is long enough now.
>
> PRL
>
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli


On Wed, Mar 22, 2017 at 12:14 AM, Darrell Walisser <[hidden email]> wrote:
Maybe worth noting that OpenMP parallel regions cannot throw exceptions. The suggested way to handle that, is to wrap the region in a try, catch *all* exceptions, and save one of them to rethrow when the parallel region exits. Yucky no doubt, but a similar problem would exist for any threaded operation containing resource allocation. By this standard, some of the OpenMP stuff done thus far is certainly not exception safe.

Thanks for your work with OpenMP, Darrell.

The uses of OpenMP are few enough to inspect, and I am not worried about them.  I made an exhaustive exploration of the call graph upward from the functions from which I wanted to throw exceptions for errors in block files.  This did not take me into the few OpenMP loops.

True, you can't throw an exception out of a worker thread and into the main thread.  This actually was a concern in my work with exceptions.  Exceptions may be caught in the worker thread that reads and writes the disk during playback and recording.  The thread stops such exceptions from going further.  It uses the function CallAfter, supplied by wxWidgets, to enqueue a piece of work for the main thread to do later at idle time, and that is, to put up an error dialog alerting the user.

PRL


On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews <[hidden email]> wrote:
Paul,

Would it be worth (at least) referring to this on some or all of:

http://wiki.audacityteam.org/wiki/CodingStandards
http://wiki.audacityteam.org/wiki/Quality
http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?

If not a section in the Hackers' Guide, would it justify its own
page in the For Developers category?



Gale


On 22 March 2017 at 01:40, Paul Licameli <[hidden email]> wrote:
> I am trying to ensure exception safety, at least wherever it is possible
> that read and write operations on block files may fail.
>
> This is harder than just scanning the code for new and delete, and it will
> be harder to maintain, if other contibutors are not aware of stricter
> demands and introduce new un-safeties.  And I don't know how to motivate
> every contributor to have the patience read this email to the end.
>
> It is cleaner to write code that throws on error, with a few appropriate
> catches that recover from errors; and the many levels of stack in between
> not needing to be cluttered with testing and propagating of error values.
>
> But those in-between levels cannot completely ignore errors:  they must be
> appropriately written to "dodge" in between the throw and the catch, by
> ensuring cleanup of side-effects even when exceptions pass.
>
> The general pseudo-code is:
>
> Do X (with side-effects);
> Do big, risky Y;
> Undo X.
>
> The "Undo X" step should never be done in-line like that, but instead,
> should happen within a destructor, and should also be guaranteed not to emit
> any other exceptions.
>
> Fixing memory leaks is only one special case where "X" is allocating some
> memory and "undo X" is freeing it, and the tool to do that in a destructor
> is a smart pointer.
>
> I have lately pushed changes that move other "Undo X" steps into destructors
> by other means.
>
> One means is valueRestorer, where X is the setting of a variable.
>
> Another is finally, taken from The C++ Programming Language, 4th edition.
> Not a built-in construct as in some other languages, but a function
> definable in C++11, that lets you wrap any code at all in a lambda
> expression, so that it executes in a destructor of an ad-hoc class.
>
> Another somewhat common thing is locking and unlocking of a mutex, which is
> best done with wxMutexLocker, or ODLocker.
>
> Sometimes the "Undo X" step is to be cancelled, but only in case if exiting
> the function along a "success" path; that is, the "Do X" step is
> conditionally committed.  I do this in some places by calling release() on a
> generalized std::unique_ptr (one with a second template parameter supplied,
> the "deleter").
>
> See my recent commits for abundant examples.
>
> I am afraid someone will have to be a nag, examining all contributions, to
> preserve the levels of safety I attained, and I hope others will learn these
> not difficult principles well enough, that I don't have to be the only nag.
>
> Does this exhaust what it means to write exception-safe code?  No, one must
> also be familiar with the notions of weak, strong, and no-fail guarantees,
> in case of multi-step operations that might complete only some steps and
> then fail, and I will be referring to these notions too in future code
> comments.  But this email is long enough now.
>
> PRL
>
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Stevethefiddle
I'm seeing *a lot* of compiler warnings from your new code Paul. Not a
problem in itself, but it makes it much harder to spot warnings from
my new code when there are vast numbers of warnings from existing
code.



Many of the warnings are trivial, such as:

../../src/blockfile/../xml/../FileException.h: In constructor
‘FileException::FileException(FileException::Cause, const wxFileName&,
const wxString&, const wxFileName&)’:
../../src/blockfile/../xml/../FileException.h:47:15: warning:
‘FileException::fileName’ will be initialized after [-Wreorder]
    wxFileName fileName;
               ^
../../src/blockfile/../xml/../FileException.h:46:10: warning:
‘FileException::Cause FileException::cause’ [-Wreorder]
    Cause cause;
          ^
../../src/blockfile/../xml/../FileException.h:20:13: warning:   when
initialized here [-Wreorder]
    explicit FileException
             ^



Some are difficult to avoid, but I think we can live with these if
there are not too many, such as:

../../include/audacity/Types.h: In constructor
‘sampleCount::sampleCount(long unsigned int)’:
../../include/audacity/Types.h:73:48: warning: narrowing conversion of
‘v’ from ‘long unsigned int’ to ‘sampleCount::type {aka long long
int}’ inside { } [-Wnarrowing]
    sampleCount ( unsigned long v ) : value { v } {}



and then there are some where I find the code incomprehensible, such as:

../../src/xml/../AudacityException.h: In member function
‘AudacityException&
AudacityException::operator=(AudacityException&&)’:
../../src/xml/../AudacityException.h:42:58: warning: no return
statement in function returning non-void [-Wreturn-type]
    AudacityException &operator = (AudacityException &&) {}


Steve

On 22 March 2017 at 05:30, Paul Licameli <[hidden email]> wrote:

>
>
> On Wed, Mar 22, 2017 at 12:14 AM, Darrell Walisser
> <[hidden email]> wrote:
>>
>> Maybe worth noting that OpenMP parallel regions cannot throw exceptions.
>> The suggested way to handle that, is to wrap the region in a try, catch
>> *all* exceptions, and save one of them to rethrow when the parallel region
>> exits. Yucky no doubt, but a similar problem would exist for any threaded
>> operation containing resource allocation. By this standard, some of the
>> OpenMP stuff done thus far is certainly not exception safe.
>
>
> Thanks for your work with OpenMP, Darrell.
>
> The uses of OpenMP are few enough to inspect, and I am not worried about
> them.  I made an exhaustive exploration of the call graph upward from the
> functions from which I wanted to throw exceptions for errors in block files.
> This did not take me into the few OpenMP loops.
>
> True, you can't throw an exception out of a worker thread and into the main
> thread.  This actually was a concern in my work with exceptions.  Exceptions
> may be caught in the worker thread that reads and writes the disk during
> playback and recording.  The thread stops such exceptions from going
> further.  It uses the function CallAfter, supplied by wxWidgets, to enqueue
> a piece of work for the main thread to do later at idle time, and that is,
> to put up an error dialog alerting the user.
>
> PRL
>
>>
>> On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews <[hidden email]>
>> wrote:
>>>
>>> Paul,
>>>
>>> Would it be worth (at least) referring to this on some or all of:
>>>
>>> http://wiki.audacityteam.org/wiki/CodingStandards
>>> http://wiki.audacityteam.org/wiki/Quality
>>> http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?
>>>
>>> If not a section in the Hackers' Guide, would it justify its own
>>> page in the For Developers category?
>>>
>>>
>>>
>>> Gale
>>>
>>>
>>> On 22 March 2017 at 01:40, Paul Licameli <[hidden email]> wrote:
>>> > I am trying to ensure exception safety, at least wherever it is
>>> > possible
>>> > that read and write operations on block files may fail.
>>> >
>>> > This is harder than just scanning the code for new and delete, and it
>>> > will
>>> > be harder to maintain, if other contibutors are not aware of stricter
>>> > demands and introduce new un-safeties.  And I don't know how to
>>> > motivate
>>> > every contributor to have the patience read this email to the end.
>>> >
>>> > It is cleaner to write code that throws on error, with a few
>>> > appropriate
>>> > catches that recover from errors; and the many levels of stack in
>>> > between
>>> > not needing to be cluttered with testing and propagating of error
>>> > values.
>>> >
>>> > But those in-between levels cannot completely ignore errors:  they must
>>> > be
>>> > appropriately written to "dodge" in between the throw and the catch, by
>>> > ensuring cleanup of side-effects even when exceptions pass.
>>> >
>>> > The general pseudo-code is:
>>> >
>>> > Do X (with side-effects);
>>> > Do big, risky Y;
>>> > Undo X.
>>> >
>>> > The "Undo X" step should never be done in-line like that, but instead,
>>> > should happen within a destructor, and should also be guaranteed not to
>>> > emit
>>> > any other exceptions.
>>> >
>>> > Fixing memory leaks is only one special case where "X" is allocating
>>> > some
>>> > memory and "undo X" is freeing it, and the tool to do that in a
>>> > destructor
>>> > is a smart pointer.
>>> >
>>> > I have lately pushed changes that move other "Undo X" steps into
>>> > destructors
>>> > by other means.
>>> >
>>> > One means is valueRestorer, where X is the setting of a variable.
>>> >
>>> > Another is finally, taken from The C++ Programming Language, 4th
>>> > edition.
>>> > Not a built-in construct as in some other languages, but a function
>>> > definable in C++11, that lets you wrap any code at all in a lambda
>>> > expression, so that it executes in a destructor of an ad-hoc class.
>>> >
>>> > Another somewhat common thing is locking and unlocking of a mutex,
>>> > which is
>>> > best done with wxMutexLocker, or ODLocker.
>>> >
>>> > Sometimes the "Undo X" step is to be cancelled, but only in case if
>>> > exiting
>>> > the function along a "success" path; that is, the "Do X" step is
>>> > conditionally committed.  I do this in some places by calling release()
>>> > on a
>>> > generalized std::unique_ptr (one with a second template parameter
>>> > supplied,
>>> > the "deleter").
>>> >
>>> > See my recent commits for abundant examples.
>>> >
>>> > I am afraid someone will have to be a nag, examining all contributions,
>>> > to
>>> > preserve the levels of safety I attained, and I hope others will learn
>>> > these
>>> > not difficult principles well enough, that I don't have to be the only
>>> > nag.
>>> >
>>> > Does this exhaust what it means to write exception-safe code?  No, one
>>> > must
>>> > also be familiar with the notions of weak, strong, and no-fail
>>> > guarantees,
>>> > in case of multi-step operations that might complete only some steps
>>> > and
>>> > then fail, and I will be referring to these notions too in future code
>>> > comments.  But this email is long enough now.
>>> >
>>> > PRL
>>> >
>>> >
>>> >
>>> >
>>> > ------------------------------------------------------------------------------
>>> > Check out the vibrant tech community on one of the world's most
>>> > engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>> > _______________________________________________
>>> > audacity-devel mailing list
>>> > [hidden email]
>>> > https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>> >
>>>
>>>
>>> ------------------------------------------------------------------------------
>>> Check out the vibrant tech community on one of the world's most
>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>> _______________________________________________
>>> audacity-devel mailing list
>>> [hidden email]
>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>
>>
>>
>>
>> ------------------------------------------------------------------------------
>> Check out the vibrant tech community on one of the world's most
>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>> _______________________________________________
>> audacity-devel mailing list
>> [hidden email]
>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

James Crook
In reply to this post by Gale
+1 to what Gale said.  I was going to suggest the same myself, with
preference for new page rather than just adding to the existing ones.

Particularly a new page such as 'Code Guarantees' to explain weak,
strong, and no-fail guarantees

--James.

On 3/22/2017 3:21 AM, Gale Andrews wrote:

> Paul,
>
> Would it be worth (at least) referring to this on some or all of:
>
> http://wiki.audacityteam.org/wiki/CodingStandards
> http://wiki.audacityteam.org/wiki/Quality
> http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?
>
> If not a section in the Hackers' Guide, would it justify its own
> page in the For Developers category?
>
>
>
> Gale
>
>
> On 22 March 2017 at 01:40, Paul Licameli <[hidden email]> wrote:
>> I am trying to ensure exception safety, at least wherever it is possible
>> that read and write operations on block files may fail.
>>
>> This is harder than just scanning the code for new and delete, and it will
>> be harder to maintain, if other contibutors are not aware of stricter
>> demands and introduce new un-safeties.  And I don't know how to motivate
>> every contributor to have the patience read this email to the end.
>>
>> It is cleaner to write code that throws on error, with a few appropriate
>> catches that recover from errors; and the many levels of stack in between
>> not needing to be cluttered with testing and propagating of error values.
>>
>> But those in-between levels cannot completely ignore errors:  they must be
>> appropriately written to "dodge" in between the throw and the catch, by
>> ensuring cleanup of side-effects even when exceptions pass.
>>
>> The general pseudo-code is:
>>
>> Do X (with side-effects);
>> Do big, risky Y;
>> Undo X.
>>
>> The "Undo X" step should never be done in-line like that, but instead,
>> should happen within a destructor, and should also be guaranteed not to emit
>> any other exceptions.
>>
>> Fixing memory leaks is only one special case where "X" is allocating some
>> memory and "undo X" is freeing it, and the tool to do that in a destructor
>> is a smart pointer.
>>
>> I have lately pushed changes that move other "Undo X" steps into destructors
>> by other means.
>>
>> One means is valueRestorer, where X is the setting of a variable.
>>
>> Another is finally, taken from The C++ Programming Language, 4th edition.
>> Not a built-in construct as in some other languages, but a function
>> definable in C++11, that lets you wrap any code at all in a lambda
>> expression, so that it executes in a destructor of an ad-hoc class.
>>
>> Another somewhat common thing is locking and unlocking of a mutex, which is
>> best done with wxMutexLocker, or ODLocker.
>>
>> Sometimes the "Undo X" step is to be cancelled, but only in case if exiting
>> the function along a "success" path; that is, the "Do X" step is
>> conditionally committed.  I do this in some places by calling release() on a
>> generalized std::unique_ptr (one with a second template parameter supplied,
>> the "deleter").
>>
>> See my recent commits for abundant examples.
>>
>> I am afraid someone will have to be a nag, examining all contributions, to
>> preserve the levels of safety I attained, and I hope others will learn these
>> not difficult principles well enough, that I don't have to be the only nag.
>>
>> Does this exhaust what it means to write exception-safe code?  No, one must
>> also be familiar with the notions of weak, strong, and no-fail guarantees,
>> in case of multi-step operations that might complete only some steps and
>> then fail, and I will be referring to these notions too in future code
>> comments.  But this email is long enough now.
>>
>> PRL
>>
>>
>>
>> ------------------------------------------------------------------------------
>> Check out the vibrant tech community on one of the world's most
>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>> _______________________________________________
>> audacity-devel mailing list
>> [hidden email]
>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>
>


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli




On Wed, Mar 22, 2017 at 6:47 AM, James Crook <[hidden email]> wrote:
+1 to what Gale said.  I was going to suggest the same myself, with
preference for new page rather than just adding to the existing ones.

Particularly a new page such as 'Code Guarantees' to explain weak,
strong, and no-fail guarantees

--James.

On 3/22/2017 3:21 AM, Gale Andrews wrote:
> Paul,
>
> Would it be worth (at least) referring to this on some or all of:
>
> http://wiki.audacityteam.org/wiki/CodingStandards
> http://wiki.audacityteam.org/wiki/Quality
> http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?
>
> If not a section in the Hackers' Guide, would it justify its own
> page in the For Developers category?

I have not read these wiki pages before.  Should they become more frequently referred to now?

The first mentiones "CVS etiquette" which sound obsolete.

PRL

 
>
>
>
> Gale
>
>
> On 22 March 2017 at 01:40, Paul Licameli <[hidden email]> wrote:
>> I am trying to ensure exception safety, at least wherever it is possible
>> that read and write operations on block files may fail.
>>
>> This is harder than just scanning the code for new and delete, and it will
>> be harder to maintain, if other contibutors are not aware of stricter
>> demands and introduce new un-safeties.  And I don't know how to motivate
>> every contributor to have the patience read this email to the end.
>>
>> It is cleaner to write code that throws on error, with a few appropriate
>> catches that recover from errors; and the many levels of stack in between
>> not needing to be cluttered with testing and propagating of error values.
>>
>> But those in-between levels cannot completely ignore errors:  they must be
>> appropriately written to "dodge" in between the throw and the catch, by
>> ensuring cleanup of side-effects even when exceptions pass.
>>
>> The general pseudo-code is:
>>
>> Do X (with side-effects);
>> Do big, risky Y;
>> Undo X.
>>
>> The "Undo X" step should never be done in-line like that, but instead,
>> should happen within a destructor, and should also be guaranteed not to emit
>> any other exceptions.
>>
>> Fixing memory leaks is only one special case where "X" is allocating some
>> memory and "undo X" is freeing it, and the tool to do that in a destructor
>> is a smart pointer.
>>
>> I have lately pushed changes that move other "Undo X" steps into destructors
>> by other means.
>>
>> One means is valueRestorer, where X is the setting of a variable.
>>
>> Another is finally, taken from The C++ Programming Language, 4th edition.
>> Not a built-in construct as in some other languages, but a function
>> definable in C++11, that lets you wrap any code at all in a lambda
>> expression, so that it executes in a destructor of an ad-hoc class.
>>
>> Another somewhat common thing is locking and unlocking of a mutex, which is
>> best done with wxMutexLocker, or ODLocker.
>>
>> Sometimes the "Undo X" step is to be cancelled, but only in case if exiting
>> the function along a "success" path; that is, the "Do X" step is
>> conditionally committed.  I do this in some places by calling release() on a
>> generalized std::unique_ptr (one with a second template parameter supplied,
>> the "deleter").
>>
>> See my recent commits for abundant examples.
>>
>> I am afraid someone will have to be a nag, examining all contributions, to
>> preserve the levels of safety I attained, and I hope others will learn these
>> not difficult principles well enough, that I don't have to be the only nag.
>>
>> Does this exhaust what it means to write exception-safe code?  No, one must
>> also be familiar with the notions of weak, strong, and no-fail guarantees,
>> in case of multi-step operations that might complete only some steps and
>> then fail, and I will be referring to these notions too in future code
>> comments.  But this email is long enough now.
>>
>> PRL
>>
>>
>>
>> ------------------------------------------------------------------------------
>> Check out the vibrant tech community on one of the world's most
>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>> _______________________________________________
>> audacity-devel mailing list
>> [hidden email]
>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>
>


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli
In reply to this post by Stevethefiddle
Thank you Steve, I will fix these warnings.

PRL


On Wed, Mar 22, 2017 at 4:58 AM, Steve the Fiddle <[hidden email]> wrote:
I'm seeing *a lot* of compiler warnings from your new code Paul. Not a
problem in itself, but it makes it much harder to spot warnings from
my new code when there are vast numbers of warnings from existing
code.



Many of the warnings are trivial, such as:

../../src/blockfile/../xml/../FileException.h: In constructor
‘FileException::FileException(FileException::Cause, const wxFileName&,
const wxString&, const wxFileName&)’:
../../src/blockfile/../xml/../FileException.h:47:15: warning:
‘FileException::fileName’ will be initialized after [-Wreorder]
    wxFileName fileName;
               ^
../../src/blockfile/../xml/../FileException.h:46:10: warning:
‘FileException::Cause FileException::cause’ [-Wreorder]
    Cause cause;
          ^
../../src/blockfile/../xml/../FileException.h:20:13: warning:   when
initialized here [-Wreorder]
    explicit FileException
             ^



Some are difficult to avoid, but I think we can live with these if
there are not too many, such as:

../../include/audacity/Types.h: In constructor
‘sampleCount::sampleCount(long unsigned int)’:
../../include/audacity/Types.h:73:48: warning: narrowing conversion of
‘v’ from ‘long unsigned int’ to ‘sampleCount::type {aka long long
int}’ inside { } [-Wnarrowing]
    sampleCount ( unsigned long v ) : value { v } {}



and then there are some where I find the code incomprehensible, such as:

../../src/xml/../AudacityException.h: In member function
‘AudacityException&
AudacityException::operator=(AudacityException&&)’:
../../src/xml/../AudacityException.h:42:58: warning: no return
statement in function returning non-void [-Wreturn-type]
    AudacityException &operator = (AudacityException &&) {}


Steve

On 22 March 2017 at 05:30, Paul Licameli <[hidden email]> wrote:
>
>
> On Wed, Mar 22, 2017 at 12:14 AM, Darrell Walisser
> <[hidden email]> wrote:
>>
>> Maybe worth noting that OpenMP parallel regions cannot throw exceptions.
>> The suggested way to handle that, is to wrap the region in a try, catch
>> *all* exceptions, and save one of them to rethrow when the parallel region
>> exits. Yucky no doubt, but a similar problem would exist for any threaded
>> operation containing resource allocation. By this standard, some of the
>> OpenMP stuff done thus far is certainly not exception safe.
>
>
> Thanks for your work with OpenMP, Darrell.
>
> The uses of OpenMP are few enough to inspect, and I am not worried about
> them.  I made an exhaustive exploration of the call graph upward from the
> functions from which I wanted to throw exceptions for errors in block files.
> This did not take me into the few OpenMP loops.
>
> True, you can't throw an exception out of a worker thread and into the main
> thread.  This actually was a concern in my work with exceptions.  Exceptions
> may be caught in the worker thread that reads and writes the disk during
> playback and recording.  The thread stops such exceptions from going
> further.  It uses the function CallAfter, supplied by wxWidgets, to enqueue
> a piece of work for the main thread to do later at idle time, and that is,
> to put up an error dialog alerting the user.
>
> PRL
>
>>
>> On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews <[hidden email]>
>> wrote:
>>>
>>> Paul,
>>>
>>> Would it be worth (at least) referring to this on some or all of:
>>>
>>> http://wiki.audacityteam.org/wiki/CodingStandards
>>> http://wiki.audacityteam.org/wiki/Quality
>>> http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?
>>>
>>> If not a section in the Hackers' Guide, would it justify its own
>>> page in the For Developers category?
>>>
>>>
>>>
>>> Gale
>>>
>>>
>>> On 22 March 2017 at 01:40, Paul Licameli <[hidden email]> wrote:
>>> > I am trying to ensure exception safety, at least wherever it is
>>> > possible
>>> > that read and write operations on block files may fail.
>>> >
>>> > This is harder than just scanning the code for new and delete, and it
>>> > will
>>> > be harder to maintain, if other contibutors are not aware of stricter
>>> > demands and introduce new un-safeties.  And I don't know how to
>>> > motivate
>>> > every contributor to have the patience read this email to the end.
>>> >
>>> > It is cleaner to write code that throws on error, with a few
>>> > appropriate
>>> > catches that recover from errors; and the many levels of stack in
>>> > between
>>> > not needing to be cluttered with testing and propagating of error
>>> > values.
>>> >
>>> > But those in-between levels cannot completely ignore errors:  they must
>>> > be
>>> > appropriately written to "dodge" in between the throw and the catch, by
>>> > ensuring cleanup of side-effects even when exceptions pass.
>>> >
>>> > The general pseudo-code is:
>>> >
>>> > Do X (with side-effects);
>>> > Do big, risky Y;
>>> > Undo X.
>>> >
>>> > The "Undo X" step should never be done in-line like that, but instead,
>>> > should happen within a destructor, and should also be guaranteed not to
>>> > emit
>>> > any other exceptions.
>>> >
>>> > Fixing memory leaks is only one special case where "X" is allocating
>>> > some
>>> > memory and "undo X" is freeing it, and the tool to do that in a
>>> > destructor
>>> > is a smart pointer.
>>> >
>>> > I have lately pushed changes that move other "Undo X" steps into
>>> > destructors
>>> > by other means.
>>> >
>>> > One means is valueRestorer, where X is the setting of a variable.
>>> >
>>> > Another is finally, taken from The C++ Programming Language, 4th
>>> > edition.
>>> > Not a built-in construct as in some other languages, but a function
>>> > definable in C++11, that lets you wrap any code at all in a lambda
>>> > expression, so that it executes in a destructor of an ad-hoc class.
>>> >
>>> > Another somewhat common thing is locking and unlocking of a mutex,
>>> > which is
>>> > best done with wxMutexLocker, or ODLocker.
>>> >
>>> > Sometimes the "Undo X" step is to be cancelled, but only in case if
>>> > exiting
>>> > the function along a "success" path; that is, the "Do X" step is
>>> > conditionally committed.  I do this in some places by calling release()
>>> > on a
>>> > generalized std::unique_ptr (one with a second template parameter
>>> > supplied,
>>> > the "deleter").
>>> >
>>> > See my recent commits for abundant examples.
>>> >
>>> > I am afraid someone will have to be a nag, examining all contributions,
>>> > to
>>> > preserve the levels of safety I attained, and I hope others will learn
>>> > these
>>> > not difficult principles well enough, that I don't have to be the only
>>> > nag.
>>> >
>>> > Does this exhaust what it means to write exception-safe code?  No, one
>>> > must
>>> > also be familiar with the notions of weak, strong, and no-fail
>>> > guarantees,
>>> > in case of multi-step operations that might complete only some steps
>>> > and
>>> > then fail, and I will be referring to these notions too in future code
>>> > comments.  But this email is long enough now.
>>> >
>>> > PRL
>>> >
>>> >
>>> >
>>> >
>>> > ------------------------------------------------------------------------------
>>> > Check out the vibrant tech community on one of the world's most
>>> > engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>> > _______________________________________________
>>> > audacity-devel mailing list
>>> > [hidden email]
>>> > https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>> >
>>>
>>>
>>> ------------------------------------------------------------------------------
>>> Check out the vibrant tech community on one of the world's most
>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>> _______________________________________________
>>> audacity-devel mailing list
>>> [hidden email]
>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>
>>
>>
>>
>> ------------------------------------------------------------------------------
>> Check out the vibrant tech community on one of the world's most
>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>> _______________________________________________
>> audacity-devel mailing list
>> [hidden email]
>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli
In reply to this post by Gale
I have added to

http://wiki.audacityteam.org/wiki/CodingStandards

I could write much more about detailed techniques of safenew, non-default deleters in unique_ptr, shared and weak pointers, and other things.  But tell me, other developers, if this gets the most important points across clearly.

This is only a beginning:  I only talk about resource management, not all the other things I lately said in email about exceptions.  Should there be another new page?

PRL



On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews <[hidden email]> wrote:
Paul,

Would it be worth (at least) referring to this on some or all of:

http://wiki.audacityteam.org/wiki/CodingStandards
http://wiki.audacityteam.org/wiki/Quality
http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?

If not a section in the Hackers' Guide, would it justify its own
page in the For Developers category?



Gale


On 22 March 2017 at 01:40, Paul Licameli <[hidden email]> wrote:
> I am trying to ensure exception safety, at least wherever it is possible
> that read and write operations on block files may fail.
>
> This is harder than just scanning the code for new and delete, and it will
> be harder to maintain, if other contibutors are not aware of stricter
> demands and introduce new un-safeties.  And I don't know how to motivate
> every contributor to have the patience read this email to the end.
>
> It is cleaner to write code that throws on error, with a few appropriate
> catches that recover from errors; and the many levels of stack in between
> not needing to be cluttered with testing and propagating of error values.
>
> But those in-between levels cannot completely ignore errors:  they must be
> appropriately written to "dodge" in between the throw and the catch, by
> ensuring cleanup of side-effects even when exceptions pass.
>
> The general pseudo-code is:
>
> Do X (with side-effects);
> Do big, risky Y;
> Undo X.
>
> The "Undo X" step should never be done in-line like that, but instead,
> should happen within a destructor, and should also be guaranteed not to emit
> any other exceptions.
>
> Fixing memory leaks is only one special case where "X" is allocating some
> memory and "undo X" is freeing it, and the tool to do that in a destructor
> is a smart pointer.
>
> I have lately pushed changes that move other "Undo X" steps into destructors
> by other means.
>
> One means is valueRestorer, where X is the setting of a variable.
>
> Another is finally, taken from The C++ Programming Language, 4th edition.
> Not a built-in construct as in some other languages, but a function
> definable in C++11, that lets you wrap any code at all in a lambda
> expression, so that it executes in a destructor of an ad-hoc class.
>
> Another somewhat common thing is locking and unlocking of a mutex, which is
> best done with wxMutexLocker, or ODLocker.
>
> Sometimes the "Undo X" step is to be cancelled, but only in case if exiting
> the function along a "success" path; that is, the "Do X" step is
> conditionally committed.  I do this in some places by calling release() on a
> generalized std::unique_ptr (one with a second template parameter supplied,
> the "deleter").
>
> See my recent commits for abundant examples.
>
> I am afraid someone will have to be a nag, examining all contributions, to
> preserve the levels of safety I attained, and I hope others will learn these
> not difficult principles well enough, that I don't have to be the only nag.
>
> Does this exhaust what it means to write exception-safe code?  No, one must
> also be familiar with the notions of weak, strong, and no-fail guarantees,
> in case of multi-step operations that might complete only some steps and
> then fail, and I will be referring to these notions too in future code
> comments.  But this email is long enough now.
>
> PRL
>
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

James Crook
Nice.
Worth adding RAII and a link to a definition of it online?
--james.

On 3/22/2017 2:02 PM, Paul Licameli wrote:
I have added to

http://wiki.audacityteam.org/wiki/CodingStandards

I could write much more about detailed techniques of safenew, non-default
deleters in unique_ptr, shared and weak pointers, and other things.  But
tell me, other developers, if this gets the most important points across
clearly.

This is only a beginning:  I only talk about resource management, not all
the other things I lately said in email about exceptions.  Should there be
another new page?

PRL



On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews [hidden email]
wrote:

Paul,

Would it be worth (at least) referring to this on some or all of:

http://wiki.audacityteam.org/wiki/CodingStandards
http://wiki.audacityteam.org/wiki/Quality
http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?

If not a section in the Hackers' Guide, would it justify its own
page in the For Developers category?



Gale


On 22 March 2017 at 01:40, Paul Licameli [hidden email] wrote:
I am trying to ensure exception safety, at least wherever it is possible
that read and write operations on block files may fail.

This is harder than just scanning the code for new and delete, and it
will
be harder to maintain, if other contibutors are not aware of stricter
demands and introduce new un-safeties.  And I don't know how to motivate
every contributor to have the patience read this email to the end.

It is cleaner to write code that throws on error, with a few appropriate
catches that recover from errors; and the many levels of stack in between
not needing to be cluttered with testing and propagating of error values.

But those in-between levels cannot completely ignore errors:  they must
be
appropriately written to "dodge" in between the throw and the catch, by
ensuring cleanup of side-effects even when exceptions pass.

The general pseudo-code is:

Do X (with side-effects);
Do big, risky Y;
Undo X.

The "Undo X" step should never be done in-line like that, but instead,
should happen within a destructor, and should also be guaranteed not to
emit
any other exceptions.

Fixing memory leaks is only one special case where "X" is allocating some
memory and "undo X" is freeing it, and the tool to do that in a
destructor
is a smart pointer.

I have lately pushed changes that move other "Undo X" steps into
destructors
by other means.

One means is valueRestorer, where X is the setting of a variable.

Another is finally, taken from The C++ Programming Language, 4th edition.
Not a built-in construct as in some other languages, but a function
definable in C++11, that lets you wrap any code at all in a lambda
expression, so that it executes in a destructor of an ad-hoc class.

Another somewhat common thing is locking and unlocking of a mutex, which
is
best done with wxMutexLocker, or ODLocker.

Sometimes the "Undo X" step is to be cancelled, but only in case if
exiting
the function along a "success" path; that is, the "Do X" step is
conditionally committed.  I do this in some places by calling release()
on a
generalized std::unique_ptr (one with a second template parameter
supplied,
the "deleter").

See my recent commits for abundant examples.

I am afraid someone will have to be a nag, examining all contributions,
to
preserve the levels of safety I attained, and I hope others will learn
these
not difficult principles well enough, that I don't have to be the only
nag.
Does this exhaust what it means to write exception-safe code?  No, one
must
also be familiar with the notions of weak, strong, and no-fail
guarantees,
in case of multi-step operations that might complete only some steps and
then fail, and I will be referring to these notions too in future code
comments.  But this email is long enough now.

PRL



------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel

------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


      

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot


_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli


On Wed, Mar 22, 2017 at 11:12 AM, James Crook <[hidden email]> wrote:
Nice.
Worth adding RAII and a link to a definition of it online?
--james.

I have described the idea of RAII without using that term.

I think Stroustrup himself regrets that rather uninformative coinage.  And I think it is less important to say "resource acquisition is initialization" but instead say "resource deallocation is destruction."  That is, it should have been RDID.

Should I start another Wiki page or no?

There is much to say, but if I say too much, I fear the page will not get read.  I never read this coding standard page myself, before today, and I see I have not hewed to everything there.

I get it that Audacity has tolerated laxity about naming and spacing conventions, which might annoy and deter some contributors if we didn't.  But this resource leakage stuff is to me really important -- a matter of correctness and efficiency and clarity and maintanability, not just a fiddly matter of style and taste.

PRL

 


On 3/22/2017 2:02 PM, Paul Licameli wrote:
I have added to

http://wiki.audacityteam.org/wiki/CodingStandards

I could write much more about detailed techniques of safenew, non-default
deleters in unique_ptr, shared and weak pointers, and other things.  But
tell me, other developers, if this gets the most important points across
clearly.

This is only a beginning:  I only talk about resource management, not all
the other things I lately said in email about exceptions.  Should there be
another new page?

PRL



On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews [hidden email]
wrote:

Paul,

Would it be worth (at least) referring to this on some or all of:

http://wiki.audacityteam.org/wiki/CodingStandards
http://wiki.audacityteam.org/wiki/Quality
http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?

If not a section in the Hackers' Guide, would it justify its own
page in the For Developers category?



Gale


On 22 March 2017 at 01:40, Paul Licameli [hidden email] wrote:
I am trying to ensure exception safety, at least wherever it is possible
that read and write operations on block files may fail.

This is harder than just scanning the code for new and delete, and it
will
be harder to maintain, if other contibutors are not aware of stricter
demands and introduce new un-safeties.  And I don't know how to motivate
every contributor to have the patience read this email to the end.

It is cleaner to write code that throws on error, with a few appropriate
catches that recover from errors; and the many levels of stack in between
not needing to be cluttered with testing and propagating of error values.

But those in-between levels cannot completely ignore errors:  they must
be
appropriately written to "dodge" in between the throw and the catch, by
ensuring cleanup of side-effects even when exceptions pass.

The general pseudo-code is:

Do X (with side-effects);
Do big, risky Y;
Undo X.

The "Undo X" step should never be done in-line like that, but instead,
should happen within a destructor, and should also be guaranteed not to
emit
any other exceptions.

Fixing memory leaks is only one special case where "X" is allocating some
memory and "undo X" is freeing it, and the tool to do that in a
destructor
is a smart pointer.

I have lately pushed changes that move other "Undo X" steps into
destructors
by other means.

One means is valueRestorer, where X is the setting of a variable.

Another is finally, taken from The C++ Programming Language, 4th edition.
Not a built-in construct as in some other languages, but a function
definable in C++11, that lets you wrap any code at all in a lambda
expression, so that it executes in a destructor of an ad-hoc class.

Another somewhat common thing is locking and unlocking of a mutex, which
is
best done with wxMutexLocker, or ODLocker.

Sometimes the "Undo X" step is to be cancelled, but only in case if
exiting
the function along a "success" path; that is, the "Do X" step is
conditionally committed.  I do this in some places by calling release()
on a
generalized std::unique_ptr (one with a second template parameter
supplied,
the "deleter").

See my recent commits for abundant examples.

I am afraid someone will have to be a nag, examining all contributions,
to
preserve the levels of safety I attained, and I hope others will learn
these
not difficult principles well enough, that I don't have to be the only
nag.
Does this exhaust what it means to write exception-safe code?  No, one
must
also be familiar with the notions of weak, strong, and no-fail
guarantees,
in case of multi-step operations that might complete only some steps and
then fail, and I will be referring to these notions too in future code
comments.  But this email is long enough now.

PRL



------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel

------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


      

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot


_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Darrell Walisser
In reply to this post by Paul Licameli
On Wed, Mar 22, 2017 at 1:30 AM, Paul Licameli <[hidden email]> wrote:

On Wed, Mar 22, 2017 at 12:14 AM, Darrell Walisser <[hidden email]> wrote:
Maybe worth noting that OpenMP parallel regions cannot throw exceptions. The suggested way to handle that, is to wrap the region in a try, catch *all* exceptions, and save one of them to rethrow when the parallel region exits. Yucky no doubt, but a similar problem would exist for any threaded operation containing resource allocation. By this standard, some of the OpenMP stuff done thus far is certainly not exception safe.

Thanks for your work with OpenMP, Darrell.

The uses of OpenMP are few enough to inspect, and I am not worried about them.  I made an exhaustive exploration of the call graph upward from the functions from which I wanted to throw exceptions for errors in block files.  This did not take me into the few OpenMP loops.

​The threaded code uses WaveTrackCache​ which eventually calls into BlockFile. But there is also new() which can throw, at the least. Do you want to take it to that level at this time (account for exceptions thrown by stl/new), or only our own exception throwing?
 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli


On Wed, Mar 22, 2017 at 11:45 AM, Darrell Walisser <[hidden email]> wrote:
On Wed, Mar 22, 2017 at 1:30 AM, Paul Licameli <[hidden email]> wrote:

On Wed, Mar 22, 2017 at 12:14 AM, Darrell Walisser <[hidden email]> wrote:
Maybe worth noting that OpenMP parallel regions cannot throw exceptions. The suggested way to handle that, is to wrap the region in a try, catch *all* exceptions, and save one of them to rethrow when the parallel region exits. Yucky no doubt, but a similar problem would exist for any threaded operation containing resource allocation. By this standard, some of the OpenMP stuff done thus far is certainly not exception safe.

Thanks for your work with OpenMP, Darrell.

The uses of OpenMP are few enough to inspect, and I am not worried about them.  I made an exhaustive exploration of the call graph upward from the functions from which I wanted to throw exceptions for errors in block files.  This did not take me into the few OpenMP loops.


 
​The threaded code uses WaveTrackCache​ which eventually calls into BlockFile. But there is also new() which can throw, at the least. Do you want to take it to that level at this time (account for exceptions thrown by stl/new), or only our own exception throwing?

You mean the fetch from WaveTrackCache in CalculateOneSpectrum?  See commit 38b8e57e4efa94a3eeb75c13023b83aeb5d894d1.  WaveTrackCache::Get() now has a non-throwing option to return zeroes in case of failure.  I decided to use that in drawing code (also in playback) for reasons unrelated to OpenMP, but that's another good reason.

If operator new throws an exception, I consider that a catastrophic situation from which we won't attempt recovery.  The places where new is invoked are just too numerous to reason about.

What I just said is not inconsistent with other ideas I have entertained for using std::set_new_handler to mitigate low memory situations:  http://en.cppreference.com/w/cpp/memory/new/set_new_handler

Because the new_handler would be called within operator new, before an exception is thrown.

PRL

 
 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Darrell Walisser
In reply to this post by Paul Licameli


On Wed, Mar 22, 2017 at 11:27 AM, Paul Licameli <[hidden email]> wrote:


On Wed, Mar 22, 2017 at 11:12 AM, James Crook <[hidden email]> wrote:
Nice.
Worth adding RAII and a link to a definition of it online?
--james.

I have described the idea of RAII without using that term.

I think Stroustrup himself regrets that rather uninformative coinage.  And I think it is less important to say "resource acquisition is initialization" but instead say "resource deallocation is destruction."  That is, it should have been RDID.

Should I start another Wiki page or no?


​I think it would be a good idea. Based on my own experience it is very difficult to do exception safety correctly. In addition to threads, a common problem we had was throwing across incompatible DLLs (throwing from callbacks or library hooks). Depends on the compiler, compiler flags etc to determine if libraries are "compatible" or not. I my case we were unable to throw across a C library from a C++ library.


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli


On Wed, Mar 22, 2017 at 11:58 AM, Darrell Walisser <[hidden email]> wrote:


On Wed, Mar 22, 2017 at 11:27 AM, Paul Licameli <[hidden email]> wrote:


On Wed, Mar 22, 2017 at 11:12 AM, James Crook <[hidden email]> wrote:
Nice.
Worth adding RAII and a link to a definition of it online?
--james.

I have described the idea of RAII without using that term.

I think Stroustrup himself regrets that rather uninformative coinage.  And I think it is less important to say "resource acquisition is initialization" but instead say "resource deallocation is destruction."  That is, it should have been RDID.

Should I start another Wiki page or no?


​I think it would be a good idea. Based on my own experience it is very difficult to do exception safety correctly. In addition to threads, a common problem we had was throwing across incompatible DLLs (throwing from callbacks or library hooks). Depends on the compiler, compiler flags etc to determine if libraries are "compatible" or not. I my case we were unable to throw across a C library from a C++ library.

I hear you!  See what I did at commit 6525bb18cf06

But that is a question about inserting catches at comparatively few places to stop exception propagation.

I'm conveying something different:  that when you write new C++, even in the core of Audacity and not dealing with C libraries, you should be aware of exception propagation through your functions as a pervasive possibility, and make defensive coding habits pervasive too.

You may be as old as I am, having grown up with old procedural languages like C which didn't have destructors or this exception handling stuff in them, but it's not hard to adjust your habits now.  (The freshman programming course still taught Pascal when I was at university.  But I never took any programming courses anyway.)

PRL



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

David Bailes-3
In reply to this post by James Crook
On Wed, Mar 22, 2017 at 3:12 PM, James Crook <[hidden email]> wrote:
Nice.
Worth adding RAII and a link to a definition of it online?

for example:

Couldn't we just follow these c++ core guidelines, and document which if its rules we are not going to follow. It would save reinventing the wheel.

David.
 

--james.


On 3/22/2017 2:02 PM, Paul Licameli wrote:
I have added to

http://wiki.audacityteam.org/wiki/CodingStandards

I could write much more about detailed techniques of safenew, non-default
deleters in unique_ptr, shared and weak pointers, and other things.  But
tell me, other developers, if this gets the most important points across
clearly.

This is only a beginning:  I only talk about resource management, not all
the other things I lately said in email about exceptions.  Should there be
another new page?

PRL



On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews [hidden email]
wrote:

Paul,

Would it be worth (at least) referring to this on some or all of:

http://wiki.audacityteam.org/wiki/CodingStandards
http://wiki.audacityteam.org/wiki/Quality
http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?

If not a section in the Hackers' Guide, would it justify its own
page in the For Developers category?



Gale


On 22 March 2017 at 01:40, Paul Licameli [hidden email] wrote:
I am trying to ensure exception safety, at least wherever it is possible
that read and write operations on block files may fail.

This is harder than just scanning the code for new and delete, and it
will
be harder to maintain, if other contibutors are not aware of stricter
demands and introduce new un-safeties.  And I don't know how to motivate
every contributor to have the patience read this email to the end.

It is cleaner to write code that throws on error, with a few appropriate
catches that recover from errors; and the many levels of stack in between
not needing to be cluttered with testing and propagating of error values.

But those in-between levels cannot completely ignore errors:  they must
be
appropriately written to "dodge" in between the throw and the catch, by
ensuring cleanup of side-effects even when exceptions pass.

The general pseudo-code is:

Do X (with side-effects);
Do big, risky Y;
Undo X.

The "Undo X" step should never be done in-line like that, but instead,
should happen within a destructor, and should also be guaranteed not to
emit
any other exceptions.

Fixing memory leaks is only one special case where "X" is allocating some
memory and "undo X" is freeing it, and the tool to do that in a
destructor
is a smart pointer.

I have lately pushed changes that move other "Undo X" steps into
destructors
by other means.

One means is valueRestorer, where X is the setting of a variable.

Another is finally, taken from The C++ Programming Language, 4th edition.
Not a built-in construct as in some other languages, but a function
definable in C++11, that lets you wrap any code at all in a lambda
expression, so that it executes in a destructor of an ad-hoc class.

Another somewhat common thing is locking and unlocking of a mutex, which
is
best done with wxMutexLocker, or ODLocker.

Sometimes the "Undo X" step is to be cancelled, but only in case if
exiting
the function along a "success" path; that is, the "Do X" step is
conditionally committed.  I do this in some places by calling release()
on a
generalized std::unique_ptr (one with a second template parameter
supplied,
the "deleter").

See my recent commits for abundant examples.

I am afraid someone will have to be a nag, examining all contributions,
to
preserve the levels of safety I attained, and I hope others will learn
these
not difficult principles well enough, that I don't have to be the only
nag.
Does this exhaust what it means to write exception-safe code?  No, one
must
also be familiar with the notions of weak, strong, and no-fail
guarantees,
in case of multi-step operations that might complete only some steps and
then fail, and I will be referring to these notions too in future code
comments.  But this email is long enough now.

PRL



------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel

------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


      

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot


_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli


On Thu, Mar 23, 2017 at 6:13 AM, David Bailes <[hidden email]> wrote:
On Wed, Mar 22, 2017 at 3:12 PM, James Crook <[hidden email]> wrote:
Nice.
Worth adding RAII and a link to a definition of it online?

for example:

Couldn't we just follow these c++ core guidelines, and document which if its rules we are not going to follow. It would save reinventing the wheel.


I have not myself read that interesting document through, but surely, coming from Stroustrup and Sutter, the advice must be excellent.

That may be useful to refer to, but I think it is also worth having one short guide to what is most important, explaining some peculiarities of our own code.

Such as:  once explaining what the strong exception safety guarantee is, then explaining how that is achieved in Audacity's editing operations.

PRL
 
David.
 

--james.


On 3/22/2017 2:02 PM, Paul Licameli wrote:
I have added to

http://wiki.audacityteam.org/wiki/CodingStandards

I could write much more about detailed techniques of safenew, non-default
deleters in unique_ptr, shared and weak pointers, and other things.  But
tell me, other developers, if this gets the most important points across
clearly.

This is only a beginning:  I only talk about resource management, not all
the other things I lately said in email about exceptions.  Should there be
another new page?

PRL



On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews [hidden email]
wrote:

Paul,

Would it be worth (at least) referring to this on some or all of:

http://wiki.audacityteam.org/wiki/CodingStandards
http://wiki.audacityteam.org/wiki/Quality
http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?

If not a section in the Hackers' Guide, would it justify its own
page in the For Developers category?



Gale


On 22 March 2017 at 01:40, Paul Licameli [hidden email] wrote:
I am trying to ensure exception safety, at least wherever it is possible
that read and write operations on block files may fail.

This is harder than just scanning the code for new and delete, and it
will
be harder to maintain, if other contibutors are not aware of stricter
demands and introduce new un-safeties.  And I don't know how to motivate
every contributor to have the patience read this email to the end.

It is cleaner to write code that throws on error, with a few appropriate
catches that recover from errors; and the many levels of stack in between
not needing to be cluttered with testing and propagating of error values.

But those in-between levels cannot completely ignore errors:  they must
be
appropriately written to "dodge" in between the throw and the catch, by
ensuring cleanup of side-effects even when exceptions pass.

The general pseudo-code is:

Do X (with side-effects);
Do big, risky Y;
Undo X.

The "Undo X" step should never be done in-line like that, but instead,
should happen within a destructor, and should also be guaranteed not to
emit
any other exceptions.

Fixing memory leaks is only one special case where "X" is allocating some
memory and "undo X" is freeing it, and the tool to do that in a
destructor
is a smart pointer.

I have lately pushed changes that move other "Undo X" steps into
destructors
by other means.

One means is valueRestorer, where X is the setting of a variable.

Another is finally, taken from The C++ Programming Language, 4th edition.
Not a built-in construct as in some other languages, but a function
definable in C++11, that lets you wrap any code at all in a lambda
expression, so that it executes in a destructor of an ad-hoc class.

Another somewhat common thing is locking and unlocking of a mutex, which
is
best done with wxMutexLocker, or ODLocker.

Sometimes the "Undo X" step is to be cancelled, but only in case if
exiting
the function along a "success" path; that is, the "Do X" step is
conditionally committed.  I do this in some places by calling release()
on a
generalized std::unique_ptr (one with a second template parameter
supplied,
the "deleter").

See my recent commits for abundant examples.

I am afraid someone will have to be a nag, examining all contributions,
to
preserve the levels of safety I attained, and I hope others will learn
these
not difficult principles well enough, that I don't have to be the only
nag.
Does this exhaust what it means to write exception-safe code?  No, one
must
also be familiar with the notions of weak, strong, and no-fail
guarantees,
in case of multi-step operations that might complete only some steps and
then fail, and I will be referring to these notions too in future code
comments.  But this email is long enough now.

PRL



------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel

------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


      

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot


_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli
I have updated this page, explaining safety guarantees and how I mean to implement them.

Not sure where the boundary between "coding standards" and "hacker's guide" should go, whether I go too deep into the weeds, but some part of this should be well known to developers.  Specifically, where I mention what must be done in intermediate levels of call stack in editing operations.  This requires everyone's awareness and cooperation to maintain it.

http://wiki.audacityteam.org/wiki/CodingStandards


On Thu, Mar 23, 2017 at 8:06 AM, Paul Licameli <[hidden email]> wrote:


On Thu, Mar 23, 2017 at 6:13 AM, David Bailes <[hidden email]> wrote:
On Wed, Mar 22, 2017 at 3:12 PM, James Crook <[hidden email]> wrote:
Nice.
Worth adding RAII and a link to a definition of it online?

for example:

Couldn't we just follow these c++ core guidelines, and document which if its rules we are not going to follow. It would save reinventing the wheel.


I have not myself read that interesting document through, but surely, coming from Stroustrup and Sutter, the advice must be excellent.

That may be useful to refer to, but I think it is also worth having one short guide to what is most important, explaining some peculiarities of our own code.

Such as:  once explaining what the strong exception safety guarantee is, then explaining how that is achieved in Audacity's editing operations.

PRL
 
David.
 

--james.


On 3/22/2017 2:02 PM, Paul Licameli wrote:
I have added to

http://wiki.audacityteam.org/wiki/CodingStandards

I could write much more about detailed techniques of safenew, non-default
deleters in unique_ptr, shared and weak pointers, and other things.  But
tell me, other developers, if this gets the most important points across
clearly.

This is only a beginning:  I only talk about resource management, not all
the other things I lately said in email about exceptions.  Should there be
another new page?

PRL



On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews [hidden email]
wrote:

Paul,

Would it be worth (at least) referring to this on some or all of:

http://wiki.audacityteam.org/wiki/CodingStandards
http://wiki.audacityteam.org/wiki/Quality
http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?

If not a section in the Hackers' Guide, would it justify its own
page in the For Developers category?



Gale


On 22 March 2017 at 01:40, Paul Licameli [hidden email] wrote:
I am trying to ensure exception safety, at least wherever it is possible
that read and write operations on block files may fail.

This is harder than just scanning the code for new and delete, and it
will
be harder to maintain, if other contibutors are not aware of stricter
demands and introduce new un-safeties.  And I don't know how to motivate
every contributor to have the patience read this email to the end.

It is cleaner to write code that throws on error, with a few appropriate
catches that recover from errors; and the many levels of stack in between
not needing to be cluttered with testing and propagating of error values.

But those in-between levels cannot completely ignore errors:  they must
be
appropriately written to "dodge" in between the throw and the catch, by
ensuring cleanup of side-effects even when exceptions pass.

The general pseudo-code is:

Do X (with side-effects);
Do big, risky Y;
Undo X.

The "Undo X" step should never be done in-line like that, but instead,
should happen within a destructor, and should also be guaranteed not to
emit
any other exceptions.

Fixing memory leaks is only one special case where "X" is allocating some
memory and "undo X" is freeing it, and the tool to do that in a
destructor
is a smart pointer.

I have lately pushed changes that move other "Undo X" steps into
destructors
by other means.

One means is valueRestorer, where X is the setting of a variable.

Another is finally, taken from The C++ Programming Language, 4th edition.
Not a built-in construct as in some other languages, but a function
definable in C++11, that lets you wrap any code at all in a lambda
expression, so that it executes in a destructor of an ad-hoc class.

Another somewhat common thing is locking and unlocking of a mutex, which
is
best done with wxMutexLocker, or ODLocker.

Sometimes the "Undo X" step is to be cancelled, but only in case if
exiting
the function along a "success" path; that is, the "Do X" step is
conditionally committed.  I do this in some places by calling release()
on a
generalized std::unique_ptr (one with a second template parameter
supplied,
the "deleter").

See my recent commits for abundant examples.

I am afraid someone will have to be a nag, examining all contributions,
to
preserve the levels of safety I attained, and I hope others will learn
these
not difficult principles well enough, that I don't have to be the only
nag.
Does this exhaust what it means to write exception-safe code?  No, one
must
also be familiar with the notions of weak, strong, and no-fail
guarantees,
in case of multi-step operations that might complete only some steps and
then fail, and I will be referring to these notions too in future code
comments.  But this email is long enough now.

PRL



------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel

------------------------------------------------------------
------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


      

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot


_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel




------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Stevethefiddle
Good to see some documentation about this.
I presume that the exclamation marks don't mean anything?

Steve

On 23 March 2017 at 13:56, Paul Licameli <[hidden email]> wrote:

> I have updated this page, explaining safety guarantees and how I mean to
> implement them.
>
> Not sure where the boundary between "coding standards" and "hacker's guide"
> should go, whether I go too deep into the weeds, but some part of this
> should be well known to developers.  Specifically, where I mention what must
> be done in intermediate levels of call stack in editing operations.  This
> requires everyone's awareness and cooperation to maintain it.
>
> http://wiki.audacityteam.org/wiki/CodingStandards
>
>
> On Thu, Mar 23, 2017 at 8:06 AM, Paul Licameli <[hidden email]>
> wrote:
>>
>>
>>
>> On Thu, Mar 23, 2017 at 6:13 AM, David Bailes <[hidden email]> wrote:
>>>
>>> On Wed, Mar 22, 2017 at 3:12 PM, James Crook <[hidden email]> wrote:
>>>>
>>>> Nice.
>>>> Worth adding RAII and a link to a definition of it online?
>>>
>>>
>>> for example:
>>> http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-resource
>>>
>>> Couldn't we just follow these c++ core guidelines, and document which if
>>> its rules we are not going to follow. It would save reinventing the wheel.
>>>
>>
>> I have not myself read that interesting document through, but surely,
>> coming from Stroustrup and Sutter, the advice must be excellent.
>>
>> That may be useful to refer to, but I think it is also worth having one
>> short guide to what is most important, explaining some peculiarities of our
>> own code.
>>
>> Such as:  once explaining what the strong exception safety guarantee is,
>> then explaining how that is achieved in Audacity's editing operations.
>>
>> PRL
>>
>>>
>>> David.
>>>
>>>>
>>>>
>>>> --james.
>>>>
>>>>
>>>> On 3/22/2017 2:02 PM, Paul Licameli wrote:
>>>>
>>>> I have added to
>>>>
>>>> http://wiki.audacityteam.org/wiki/CodingStandards
>>>>
>>>> I could write much more about detailed techniques of safenew,
>>>> non-default
>>>> deleters in unique_ptr, shared and weak pointers, and other things.  But
>>>> tell me, other developers, if this gets the most important points across
>>>> clearly.
>>>>
>>>> This is only a beginning:  I only talk about resource management, not
>>>> all
>>>> the other things I lately said in email about exceptions.  Should there
>>>> be
>>>> another new page?
>>>>
>>>> PRL
>>>>
>>>>
>>>>
>>>> On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews <[hidden email]>
>>>> wrote:
>>>>
>>>> Paul,
>>>>
>>>> Would it be worth (at least) referring to this on some or all of:
>>>>
>>>> http://wiki.audacityteam.org/wiki/CodingStandards
>>>> http://wiki.audacityteam.org/wiki/Quality
>>>> http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?
>>>>
>>>> If not a section in the Hackers' Guide, would it justify its own
>>>> page in the For Developers category?
>>>>
>>>>
>>>>
>>>> Gale
>>>>
>>>>
>>>> On 22 March 2017 at 01:40, Paul Licameli <[hidden email]>
>>>> wrote:
>>>>
>>>> I am trying to ensure exception safety, at least wherever it is possible
>>>> that read and write operations on block files may fail.
>>>>
>>>> This is harder than just scanning the code for new and delete, and it
>>>>
>>>> will
>>>>
>>>> be harder to maintain, if other contibutors are not aware of stricter
>>>> demands and introduce new un-safeties.  And I don't know how to motivate
>>>> every contributor to have the patience read this email to the end.
>>>>
>>>> It is cleaner to write code that throws on error, with a few appropriate
>>>> catches that recover from errors; and the many levels of stack in
>>>> between
>>>> not needing to be cluttered with testing and propagating of error
>>>> values.
>>>>
>>>> But those in-between levels cannot completely ignore errors:  they must
>>>>
>>>> be
>>>>
>>>> appropriately written to "dodge" in between the throw and the catch, by
>>>> ensuring cleanup of side-effects even when exceptions pass.
>>>>
>>>> The general pseudo-code is:
>>>>
>>>> Do X (with side-effects);
>>>> Do big, risky Y;
>>>> Undo X.
>>>>
>>>> The "Undo X" step should never be done in-line like that, but instead,
>>>> should happen within a destructor, and should also be guaranteed not to
>>>>
>>>> emit
>>>>
>>>> any other exceptions.
>>>>
>>>> Fixing memory leaks is only one special case where "X" is allocating
>>>> some
>>>> memory and "undo X" is freeing it, and the tool to do that in a
>>>>
>>>> destructor
>>>>
>>>> is a smart pointer.
>>>>
>>>> I have lately pushed changes that move other "Undo X" steps into
>>>>
>>>> destructors
>>>>
>>>> by other means.
>>>>
>>>> One means is valueRestorer, where X is the setting of a variable.
>>>>
>>>> Another is finally, taken from The C++ Programming Language, 4th
>>>> edition.
>>>> Not a built-in construct as in some other languages, but a function
>>>> definable in C++11, that lets you wrap any code at all in a lambda
>>>> expression, so that it executes in a destructor of an ad-hoc class.
>>>>
>>>> Another somewhat common thing is locking and unlocking of a mutex, which
>>>>
>>>> is
>>>>
>>>> best done with wxMutexLocker, or ODLocker.
>>>>
>>>> Sometimes the "Undo X" step is to be cancelled, but only in case if
>>>>
>>>> exiting
>>>>
>>>> the function along a "success" path; that is, the "Do X" step is
>>>> conditionally committed.  I do this in some places by calling release()
>>>>
>>>> on a
>>>>
>>>> generalized std::unique_ptr (one with a second template parameter
>>>>
>>>> supplied,
>>>>
>>>> the "deleter").
>>>>
>>>> See my recent commits for abundant examples.
>>>>
>>>> I am afraid someone will have to be a nag, examining all contributions,
>>>>
>>>> to
>>>>
>>>> preserve the levels of safety I attained, and I hope others will learn
>>>>
>>>> these
>>>>
>>>> not difficult principles well enough, that I don't have to be the only
>>>>
>>>> nag.
>>>>
>>>> Does this exhaust what it means to write exception-safe code?  No, one
>>>>
>>>> must
>>>>
>>>> also be familiar with the notions of weak, strong, and no-fail
>>>>
>>>> guarantees,
>>>>
>>>> in case of multi-step operations that might complete only some steps and
>>>> then fail, and I will be referring to these notions too in future code
>>>> comments.  But this email is long enough now.
>>>>
>>>> PRL
>>>>
>>>>
>>>>
>>>> ------------------------------------------------------------
>>>>
>>>> ------------------
>>>>
>>>> Check out the vibrant tech community on one of the world's most
>>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>>> _______________________________________________
>>>> audacity-devel mailing list
>>>> [hidden email]
>>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>>
>>>> ------------------------------------------------------------
>>>> ------------------
>>>> Check out the vibrant tech community on one of the world's most
>>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>>> _______________________________________________
>>>> audacity-devel mailing list
>>>> [hidden email]
>>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>>
>>>>
>>>>
>>>>
>>>> ------------------------------------------------------------------------------
>>>> Check out the vibrant tech community on one of the world's most
>>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> audacity-devel mailing list
>>>> [hidden email]
>>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>>
>>>>
>>>>
>>>>
>>>> ------------------------------------------------------------------------------
>>>> Check out the vibrant tech community on one of the world's most
>>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>>> _______________________________________________
>>>> audacity-devel mailing list
>>>> [hidden email]
>>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>>
>>>
>>>
>>>
>>> ------------------------------------------------------------------------------
>>> Check out the vibrant tech community on one of the world's most
>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>> _______________________________________________
>>> audacity-devel mailing list
>>> [hidden email]
>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>
>>
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exception safety: not just stopping memory leaks

Paul Licameli


On Thu, Mar 23, 2017 at 11:59 AM, Steve the Fiddle <[hidden email]> wrote:
Good to see some documentation about this.
I presume that the exclamation marks don't mean anything?

They are certainly not factorials.
 
"No naked new!" is a nice alliterative slogan easily remembered.

PRL



Steve

On 23 March 2017 at 13:56, Paul Licameli <[hidden email]> wrote:
> I have updated this page, explaining safety guarantees and how I mean to
> implement them.
>
> Not sure where the boundary between "coding standards" and "hacker's guide"
> should go, whether I go too deep into the weeds, but some part of this
> should be well known to developers.  Specifically, where I mention what must
> be done in intermediate levels of call stack in editing operations.  This
> requires everyone's awareness and cooperation to maintain it.
>
> http://wiki.audacityteam.org/wiki/CodingStandards
>
>
> On Thu, Mar 23, 2017 at 8:06 AM, Paul Licameli <[hidden email]>
> wrote:
>>
>>
>>
>> On Thu, Mar 23, 2017 at 6:13 AM, David Bailes <[hidden email]> wrote:
>>>
>>> On Wed, Mar 22, 2017 at 3:12 PM, James Crook <[hidden email]> wrote:
>>>>
>>>> Nice.
>>>> Worth adding RAII and a link to a definition of it online?
>>>
>>>
>>> for example:
>>> http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-resource
>>>
>>> Couldn't we just follow these c++ core guidelines, and document which if
>>> its rules we are not going to follow. It would save reinventing the wheel.
>>>
>>
>> I have not myself read that interesting document through, but surely,
>> coming from Stroustrup and Sutter, the advice must be excellent.
>>
>> That may be useful to refer to, but I think it is also worth having one
>> short guide to what is most important, explaining some peculiarities of our
>> own code.
>>
>> Such as:  once explaining what the strong exception safety guarantee is,
>> then explaining how that is achieved in Audacity's editing operations.
>>
>> PRL
>>
>>>
>>> David.
>>>
>>>>
>>>>
>>>> --james.
>>>>
>>>>
>>>> On 3/22/2017 2:02 PM, Paul Licameli wrote:
>>>>
>>>> I have added to
>>>>
>>>> http://wiki.audacityteam.org/wiki/CodingStandards
>>>>
>>>> I could write much more about detailed techniques of safenew,
>>>> non-default
>>>> deleters in unique_ptr, shared and weak pointers, and other things.  But
>>>> tell me, other developers, if this gets the most important points across
>>>> clearly.
>>>>
>>>> This is only a beginning:  I only talk about resource management, not
>>>> all
>>>> the other things I lately said in email about exceptions.  Should there
>>>> be
>>>> another new page?
>>>>
>>>> PRL
>>>>
>>>>
>>>>
>>>> On Tue, Mar 21, 2017 at 11:21 PM, Gale Andrews <[hidden email]>
>>>> wrote:
>>>>
>>>> Paul,
>>>>
>>>> Would it be worth (at least) referring to this on some or all of:
>>>>
>>>> http://wiki.audacityteam.org/wiki/CodingStandards
>>>> http://wiki.audacityteam.org/wiki/Quality
>>>> http://wiki.audacityteam.org/wiki/Guide_for_Hackers ?
>>>>
>>>> If not a section in the Hackers' Guide, would it justify its own
>>>> page in the For Developers category?
>>>>
>>>>
>>>>
>>>> Gale
>>>>
>>>>
>>>> On 22 March 2017 at 01:40, Paul Licameli <[hidden email]>
>>>> wrote:
>>>>
>>>> I am trying to ensure exception safety, at least wherever it is possible
>>>> that read and write operations on block files may fail.
>>>>
>>>> This is harder than just scanning the code for new and delete, and it
>>>>
>>>> will
>>>>
>>>> be harder to maintain, if other contibutors are not aware of stricter
>>>> demands and introduce new un-safeties.  And I don't know how to motivate
>>>> every contributor to have the patience read this email to the end.
>>>>
>>>> It is cleaner to write code that throws on error, with a few appropriate
>>>> catches that recover from errors; and the many levels of stack in
>>>> between
>>>> not needing to be cluttered with testing and propagating of error
>>>> values.
>>>>
>>>> But those in-between levels cannot completely ignore errors:  they must
>>>>
>>>> be
>>>>
>>>> appropriately written to "dodge" in between the throw and the catch, by
>>>> ensuring cleanup of side-effects even when exceptions pass.
>>>>
>>>> The general pseudo-code is:
>>>>
>>>> Do X (with side-effects);
>>>> Do big, risky Y;
>>>> Undo X.
>>>>
>>>> The "Undo X" step should never be done in-line like that, but instead,
>>>> should happen within a destructor, and should also be guaranteed not to
>>>>
>>>> emit
>>>>
>>>> any other exceptions.
>>>>
>>>> Fixing memory leaks is only one special case where "X" is allocating
>>>> some
>>>> memory and "undo X" is freeing it, and the tool to do that in a
>>>>
>>>> destructor
>>>>
>>>> is a smart pointer.
>>>>
>>>> I have lately pushed changes that move other "Undo X" steps into
>>>>
>>>> destructors
>>>>
>>>> by other means.
>>>>
>>>> One means is valueRestorer, where X is the setting of a variable.
>>>>
>>>> Another is finally, taken from The C++ Programming Language, 4th
>>>> edition.
>>>> Not a built-in construct as in some other languages, but a function
>>>> definable in C++11, that lets you wrap any code at all in a lambda
>>>> expression, so that it executes in a destructor of an ad-hoc class.
>>>>
>>>> Another somewhat common thing is locking and unlocking of a mutex, which
>>>>
>>>> is
>>>>
>>>> best done with wxMutexLocker, or ODLocker.
>>>>
>>>> Sometimes the "Undo X" step is to be cancelled, but only in case if
>>>>
>>>> exiting
>>>>
>>>> the function along a "success" path; that is, the "Do X" step is
>>>> conditionally committed.  I do this in some places by calling release()
>>>>
>>>> on a
>>>>
>>>> generalized std::unique_ptr (one with a second template parameter
>>>>
>>>> supplied,
>>>>
>>>> the "deleter").
>>>>
>>>> See my recent commits for abundant examples.
>>>>
>>>> I am afraid someone will have to be a nag, examining all contributions,
>>>>
>>>> to
>>>>
>>>> preserve the levels of safety I attained, and I hope others will learn
>>>>
>>>> these
>>>>
>>>> not difficult principles well enough, that I don't have to be the only
>>>>
>>>> nag.
>>>>
>>>> Does this exhaust what it means to write exception-safe code?  No, one
>>>>
>>>> must
>>>>
>>>> also be familiar with the notions of weak, strong, and no-fail
>>>>
>>>> guarantees,
>>>>
>>>> in case of multi-step operations that might complete only some steps and
>>>> then fail, and I will be referring to these notions too in future code
>>>> comments.  But this email is long enough now.
>>>>
>>>> PRL
>>>>
>>>>
>>>>
>>>> ------------------------------------------------------------
>>>>
>>>> ------------------
>>>>
>>>> Check out the vibrant tech community on one of the world's most
>>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>>> _______________________________________________
>>>> audacity-devel mailing list
>>>> [hidden email]
>>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>>
>>>> ------------------------------------------------------------
>>>> ------------------
>>>> Check out the vibrant tech community on one of the world's most
>>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>>> _______________________________________________
>>>> audacity-devel mailing list
>>>> [hidden email]
>>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>>
>>>>
>>>>
>>>>
>>>> ------------------------------------------------------------------------------
>>>> Check out the vibrant tech community on one of the world's most
>>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> audacity-devel mailing list
>>>> [hidden email]
>>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>>
>>>>
>>>>
>>>>
>>>> ------------------------------------------------------------------------------
>>>> Check out the vibrant tech community on one of the world's most
>>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>>> _______________________________________________
>>>> audacity-devel mailing list
>>>> [hidden email]
>>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>>
>>>
>>>
>>>
>>> ------------------------------------------------------------------------------
>>> Check out the vibrant tech community on one of the world's most
>>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>>> _______________________________________________
>>> audacity-devel mailing list
>>> [hidden email]
>>> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>>>
>>
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> audacity-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/audacity-devel
>

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
audacity-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-devel
12
Loading...