Album segfault {2parts-excerpted}.append( {1part-notexcerpted} );

• Sep 21, 2015 - 10:13
S4 - Minor

I'm trying to diagnose exactly, so bear with my temporary title. The issue is something to do with a particular mismatch number excerpts and number staves...

If make album of:
1. flute-piano w/excerpts
2. flute-piano w/excerpts
3. flute

and create joined score, then there is a segfault with stack trace:
Score::appendScore line 2112
Score::addRest line 162
Score::undoAddCR line 1321
Measure::undoGetSegment line 748
Measure::findSegment line 733
Measure::first line 215
SegmentLine::first line 40

Issue occurs on latest b376184 ...I believe it was introduced with… which allows scores with different excerpt counts to be joined together by first removing excerpts (so just appends base scores, not children scores). The segfault happens when filling in full measure rests, right after finished cloning measures of 3rd score, because the 3rd score has fewer staves.

Attachment Size
flute-piano-one-meas-parts.mscx 14.25 KB
flute-one-meas.mscx 3.54 KB


Hello eric from "yesterday". That was a long night.

Anyway, I'm going to tackle now...

But, I'm a bit perplexed how my commit fccce6c (which was a test case in tst_album) is somehow in musescore/MuseScore.git because I don't believe I have commit access and didn't include it in any PR. Did I somehow unintentionally commit? It doesn't seem to be in "master", but somehow it is here:…

I'm afraid I don't understand git enough to know what is going on. Could someone enlighten me?

regarding that fccce6c magical commit issue, I'm suspecting I had a "Detached Head" such that that commit was never connected to any branch, and therefore somehow managed to find its way inside the official musescore/MuseScore.git repository.

Anyway, I'm returning to this latest git master (a6ec8aa) & followed my replication steps, and I get the segfault (am on win 8.1 x86-64 now) on line 40 of segmentlist.h:

Segment* first() const               { return _first;       }:

and with the debugger evaluator saying _first is "", I believe because the this pointer (of type Ms::SegmentList*) has address 0xc8, which clearly is an invalid address for a pointer because regular pointers shouldn't be so small.

Here's stacktrace:

0	Ms::SegmentList::first	segmentlist.h	40	0xc369a4	
1	Ms::Measure::first	measure.h	215	0xc3d720	
2	Ms::Measure::findSegment	measure.cpp	733	0x79f475	
3	Ms::Measure::undoGetSegment	measure.cpp	748	0x79f530	
4	Ms::Score::undoAddCR	undo.cpp	1321	0x7315ff	
5	Ms::Score::addRest	edit.cpp	162	0x788b6b	
6	Ms::Score::appendScore	score.cpp	2360	0x742b1d	
7	Ms::Album::createScore	album.cpp	187	0x57ab4d	
8	Ms::AlbumManager::createScoreClicked	albummanager.cpp	144	0x57cb37	
9	Ms::AlbumManager::qt_static_metacall	moc_albummanager.cpp	112	0x67b47f	
10	ZN11QMetaObject8activateEP7QObjectiiPPv			0x68a655a2	
11	ZN15QAbstractButton7clickedEb			0x18f0f57c	
12	??			0x23815458	
13	??			0x44c71441	
14	??			0x1024	
15	??			0x44c70000	
16	??			0x1424	
17	??			0x508b0000	
18	ZN7WebCore6JSNode6s_infoE			0x18488b1c	
19	??			0x2b14502b	
20	??			0x448b1048	
21	??			0x44c73024	
22	??			0x424	
23	??			0x4c890000	
24	??			0x54891824	
25	??			0x4c8d1c24	
26	??			0x4891024	

and here is console output:

Debug: Will not join parts. Album item "flute".  Mismatch between number of excerpts with first album item "flute-piano" (C:\Users\Eric\Documents\GitHub\MuseScore\mscore\album.cpp:171, bool Ms::Album::createScore(const QString&))
Debug: tick2measure 122880 (max 59520) not found (C:\Users\Eric\Documents\GitHub\MuseScore\libmscore\utils.cpp:58, Ms::Measure* Ms::Score::tick2measure(int) const)

So clearly my debug statment "Debug: Will not join parts." at… is warning me that mscore will not attempt to join parts... But it still should be able to continue on and just join the parent scores...

note: Album::createScore() is able to append the 2nd flute-piano movement, but fails when appending the flute-only movement, during the time when filling with rests, specifically when filling the 2nd staff (the 1st piano staff) of measure 1.

Title Album segfault mscx{1staff part, 2staff part}w/excerpts + mscx{1staff part, 2staff part}w/excerpts + mscx{1staff part} Album segfault mscx{2 inst}w/excerpts + mscx{2 inst}w/excerpts + mscx{1 inst}

I've discovered that issue doesn't have anything to do with the number of staves in each part. Since if I do {flute part & recorder part} + {flute part & recorder part} + {flute}, then I get same error, with identical stacktrace.

tick 3840 corresponds to 3rd measure. That would be the 1st measure of the final appeneded score (the plain flute score), since all my test scores are 1 meas each. But when I was looking in the tick2measure, the score only had 1 measure. Maybe it should be looking for tick 0 then, not tick 3840. There are simply no measures for tick 3840 on that flute-only score...

Title Album segfault mscx{2 inst}w/excerpts + mscx{2 inst}w/excerpts + mscx{1 inst} Album segfault mscx{2 inst 1meas}w/excerpts + mscx{1 inst, >1meas}

so in Album::createScore when try to append root score, then in Score::appendScore, when cloning the measures, if the initial score has excerpt while 2nd score has no excerpt, it is somehow not actually cloning enough measures...

I've managed to simplify the test case down to: {2parts w/excertps} + {1 part no excerpts, 2measures}

Title Album segfault mscx{2 inst 1meas}w/excerpts + mscx{1 inst, >1meas} Album segfault {2parts-excerpted}.append( {1part-notexcerpted} );

so what is happening is Score::Append when cloning measures is only appending one stave, so what happens is the resultant score Measure list end up like:

[staff1Meas1]  ->  [appendedScoreMeas1]    ->  [appendedScoreMeas2]
[staff2Meas1]      [NULL]                      [NULL]

but should really have blank measures for the 2nd staff like:

[staff1Meas1]  ->  [appendedScoreMeas1]    ->  [appendedScoreMeas2]
[staff2Meas1]      [blankMeas, needs rest]     [blankMeas, needs rest]

I'm going to take a break now, but I know what needs to be done now...those extra blank measures need to be put in. (The code that puts rests in those staves will work correctly, once they have measures).

I'm going to make an additional test which does nothing more than:

{2parts-excerpted-1meas}.append( {1part-notexcerpted-2meas} );

since that is basically where the fault lies. Once that is fixed, then the album will work...

I'm going to take a break now, but I should be able to fix this fairly quickly.

I've deteremined the issues occurs because one movement has excerpts & one doesn't. Although we are only appending the root scores, however when adding rests into the blank measure, we are adding a ChrordRest element which is still linked with the excerpt staff. So I need to figure out the most appropraite way to only add a rest which is for the single staff, and not it's linked cousin.

I belive the removeExcerpts section:…

Does not properly completely remove the excerpts, since the individual elements of the staff still have all their elements pointing to their linked cousins. I believe I will have to do something similiar to what lasconic did with… but I'm trying to figure out how to properly unlink, and maybe if their is some of lasconic's code I should make a function out of to reuse.

There is also another thing I need to consider now: How should albums behave when a score has a linked staff to another staff in that score that is not a child score? Also I'm thinking I need to put more strict rules on what will are the permitted ways that scores can be joined together into an album. Currently there is just a weak test, which just checks if number of excerpts are equal between scores. But I think that will need to place some more strict rules, that basically say that if want to include linked parts and linked scores in resultant album, that entire organization of each score must be indentical. (And the best way for user to do this is to use the same tempate for each movement). Otherwise, if have different organization of child parts, then child parts are not transfered to resultant joined alubm. And if have different layout of linked staffs, then will simply prohibit joining.