Skip to content

Conversation

@Spekular
Copy link
Member

@Spekular Spekular commented Oct 22, 2020

Custom destruction, copy constructors, and copy assignment should usually all be implemented for a class that implements any one of them. These changes are needed for #5524, but I decided to move them to a separate PR to split the review burden, especially since it's important (and tricky, IMO) to get these correct.

Status as of latest commit

Operator SampleBuffer SampleTCO
Copy Constructor Added Added
Copy Assignment Added Deleted

@LmmsBot
Copy link

LmmsBot commented Oct 22, 2020

🤖 Hey, I'm @LmmsBot from github.com/lmms/bot and I made downloads for this pull request, click me to make them magically appear! 🎩

Linux

Windows

macOS

🤖
{"platform_name_to_artifacts": {"Linux": [{"artifact": {"title": {"title": "(AppImage)", "platform_name": "Linux"}, "link": {"link": "https://11836-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.70%2Bgfe4e118-linux-x86_64.AppImage"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/11836?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}], "Windows": [{"artifact": {"title": {"title": "32-bit", "platform_name": "Windows"}, "link": {"link": "https://11835-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.70%2Bgfe4e1188b-mingw-win32.exe"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/11835?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}, {"artifact": {"title": {"title": "64-bit", "platform_name": "Windows"}, "link": {"link": "https://11837-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.70%2Bgfe4e1188b-mingw-win64.exe"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/11837?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}], "macOS": [{"artifact": {"title": {"title": "", "platform_name": "macOS"}, "link": {"link": "https://11839-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.70%2Bgfe4e1188b-mac10.14.dmg"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/11839?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}]}, "commit_sha": "8789faf5632fab25b71199ed7c8fa954cb8918fd"}

@Spekular Spekular added the needs code review A functional code review is currently required for this PR label Oct 23, 2020
@DomClark
Copy link
Member

DomClark commented Nov 1, 2020

The rule of three (or five these days, now we have move constructors and assignment operators) doesn't say that objects have to be copyable or moveable; rather it says that if any of these functions are user-defined, the others should be user-defined too, because the compiler-generated ones are likely to be incorrect. If you write a destructor, you are probably trying to dispose of a resource when the object is destructed. The compiler-generated constructors and assignment operators will copy the resource handle, meaning it will be disposed of twice, and the compiler-generated assignment operators will overwrite the existing handle without disposing of it. If a particular constructor or assigment operator doesn't make sense, or you're not sure what to do at the moment, = delete is a perfectly acceptable definition. The goal is primarily to get rid of the compiler's own version.

SampleBuffer::operator= leaks the original data. You might like to look into the copy-and-swap idiom as a way to implement this.

@Spekular Spekular requested review from DomClark and IanCaio December 1, 2020 23:24
@Spekular
Copy link
Member Author

Spekular commented Dec 1, 2020

Will fix merge conflicts as soon as I know that there aren't bigger issues remaining!

@Spekular Spekular changed the title Fix rule of three for SampleBuffer, partly for SampleTCO Fix rule of three for SampleBuffer, SampleTCO Dec 4, 2020
... by switching from an initializer list to manual assignments.
@Spekular
Copy link
Member Author

Spekular commented Dec 6, 2020

@DomClark @IanCaio any remaining objections?

Comment on lines 153 to 154
memcpy(m_origData, orig.m_origData, m_origFrames * BYTES_PER_FRAME);
memcpy(m_data, orig.m_data, m_frames * BYTES_PER_FRAME);
Copy link
Member

@DomClark DomClark Dec 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

orig.m_origData or orig.m_data can be null, such as for a default-constructed SampleBuffer. Calling memcpy with a null pointer is undefined behaviour, even if the size is zero.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to the comment above, MOST implementations of memcpy does nothing if the length is 0, but it's not guaranteed that ALL implementations do nothing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully fixed in latest commit

Comment on lines 112 to 120
SampleTCO::SampleTCO(const SampleTCO& orig) :
SampleTCO(orig.getTrack())
{
// TODO: This creates a new SampleBuffer for the new TCO, eating up memory
// & eventually causing performance issues. Letting tracks share buffers
// when they're identical would fix this, but isn't possible right now.
m_sampleBuffer = new SampleBuffer(*orig.m_sampleBuffer);
m_isPlaying = orig.m_isPlaying;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructor delegated to here initialises m_sampleBuffer with a newly allocated, default-constructed SampleBuffer. It is then leaked when this constructor overwrites it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully fixed in latest commit

@IanCaio
Copy link
Contributor

IanCaio commented Dec 7, 2020

m_varLock is still not recursive. I'm having second thoughts whether it should though. If we call the copy assignment from a method that has locked the sample buffer we would deadlock, but we should only be locking the sample buffer when accessing it (which means we shouldn't be copy assigning to it until we are done and unlock). So I think we are good having it non-recursive.

I personally think it's more easily understandable to use the tryLock approach on the deadlock prevention: the address approach works just as well, but for a reader it might be confusing at first to know why it's done that way. But it's no big deal and it can be kept that way.

I'll approve it, just want to review it with more time later.

@Spekular
Copy link
Member Author

Spekular commented Dec 7, 2020

m_varLock is still not recursive.

Wow, I totally forgot about that. As you say though, it doesn't seem necessary.

I personally think it's more easily understandable to use the tryLock approach on the deadlock prevention: the address approach works just as well, but for a reader it might be confusing at first to know why it's done that way.

Copying the std::swap() method would require:

  • While both not locked
    • Try to lock first, then second. Release any acquired locks if we fail.
    • Try to lock second, then first. Release any acquired locks if we fail.

With our bracket standards this would be a lot of lines.

But it's no big deal and it can be kept that way.

👍

@Spekular
Copy link
Member Author

@DomClark and @IanCaio, are you happy with the fixes in the recent commits? If so, merge?

Copy link
Contributor

@IanCaio IanCaio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 🚀

@PhysSong PhysSong requested a review from DomClark December 22, 2020 01:46
@IanCaio
Copy link
Contributor

IanCaio commented Dec 28, 2020

Any objections to merging this?

@Veratil
Copy link
Contributor

Veratil commented Dec 28, 2020

Any objections to merging this?

I'm going to ignore style review this time and say no objections. 👍

Copy link
Member

@DomClark DomClark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now. I made one comment, but it can be ignored if you want.

@Spekular
Copy link
Member Author

Master CI fails in the same way as this, so I'll merge now 🎉

@Spekular Spekular merged commit bf7c87d into LMMS:master Dec 29, 2020
@Spekular Spekular deleted the SBROT branch December 29, 2020 22:01
IanCaio pushed a commit to IanCaio/lmms that referenced this pull request Mar 28, 2021
* Automatic formatting changes

* Add copy constructor and assignemnt to SampleBuffer

* Add copy constructor to SampleTCO

* Delete SampleTCO copy assignment, initial work on SampleBuffer swap method

* SampleBuffer: Finish(?) swap and use it for copy assignment, lock for read in copy constructor

* Don't forget to unlock in copy assignment!

* Formatting changes

* Lock ordering in swap

* Fix leak and constness

Co-authored-by: Dominic Clark <[email protected]>

* Fix multiplication style, ensure lock is held when necessary

... by switching from an initializer list to manual assignments.

* Fixes from review

* Avoid more undefined behavior

* Update src/tracks/SampleTrack.cpp

Co-authored-by: Dominic Clark <[email protected]>
devnexen pushed a commit to devnexen/lmms that referenced this pull request Apr 10, 2021
* Automatic formatting changes

* Add copy constructor and assignemnt to SampleBuffer

* Add copy constructor to SampleTCO

* Delete SampleTCO copy assignment, initial work on SampleBuffer swap method

* SampleBuffer: Finish(?) swap and use it for copy assignment, lock for read in copy constructor

* Don't forget to unlock in copy assignment!

* Formatting changes

* Lock ordering in swap

* Fix leak and constness

Co-authored-by: Dominic Clark <[email protected]>

* Fix multiplication style, ensure lock is held when necessary

... by switching from an initializer list to manual assignments.

* Fixes from review

* Avoid more undefined behavior

* Update src/tracks/SampleTrack.cpp

Co-authored-by: Dominic Clark <[email protected]>
sdasda7777 pushed a commit to sdasda7777/lmms that referenced this pull request Jun 28, 2022
* Automatic formatting changes

* Add copy constructor and assignemnt to SampleBuffer

* Add copy constructor to SampleTCO

* Delete SampleTCO copy assignment, initial work on SampleBuffer swap method

* SampleBuffer: Finish(?) swap and use it for copy assignment, lock for read in copy constructor

* Don't forget to unlock in copy assignment!

* Formatting changes

* Lock ordering in swap

* Fix leak and constness

Co-authored-by: Dominic Clark <[email protected]>

* Fix multiplication style, ensure lock is held when necessary

... by switching from an initializer list to manual assignments.

* Fixes from review

* Avoid more undefined behavior

* Update src/tracks/SampleTrack.cpp

Co-authored-by: Dominic Clark <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs code review A functional code review is currently required for this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants