explicitly signed chars for struct MidiMapping for ARM

• Feb 2, 2016 - 13:15
Type
Functional
Severity
S4 - Minor
Status
closed
Project

The following set of compiler warnings on ARM occur because the MidiMapping struct stores port and channel as chars without any specified sign (see previous discussion in #95951: Enormously Long Stems when Using Beams in GNU/Linux ARM):

/home/e/MuseScore/libmscore/score.cpp: In member function 'void Ms::Score::removeDeletedMidiMapping()':
/home/e/MuseScore/libmscore/score.cpp:991:53: warning: comparison is always false due to limited range of data type [-Wtype-limits]
                       && !(_midiMapping[index].port == -1 && _midiMapping[index].channel == -1));
                                                     ^
/home/e/MuseScore/libmscore/score.cpp:991:90: warning: comparison is always false due to limited range of data type [-Wtype-limits]
                       && !(_midiMapping[index].port == -1 && _midiMapping[index].channel == -1));
                                                                                          ^
/home/e/MuseScore/libmscore/score.cpp: In member function 'int Ms::Score::updateMidiMapping()':
/home/e/MuseScore/libmscore/score.cpp:1023:25: warning: comparison is always false due to limited range of data type [-Wtype-limits]
             if (mm.port == -1 || mm.channel == -1)
                         ^
/home/e/MuseScore/libmscore/score.cpp:1023:45: warning: comparison is always false due to limited range of data type [-Wtype-limits]
             if (mm.port == -1 || mm.channel == -1)
                                             ^
/home/e/MuseScore/libmscore/score.cpp:1045:71: warning: comparison is always false due to limited range of data type [-Wtype-limits]
                               if (_midiMapping[channel->channel].port == -1) {
                                                                       ^
/home/e/MuseScore/libmscore/score.cpp:1049:79: warning: comparison is always false due to limited range of data type [-Wtype-limits]
                               else if (_midiMapping[channel->channel].channel == -1) {
                                                                               ^

It seems -1 is being used to indicate an unused or invalid channel or port. But since a -1 will be interpreted as 255 when read (since they aren't sign extended on ARM by default), therefore none of these equality tests are true, so all these if statements are broken.

I have yet to figure out a sequence of steps that will cause a bug based on these broken if statements, so I haven't labeled this issue as "bug" yet. I have tried creating a score with ~300 instruments hoping that would break something on my ARM, but I haven't been able to produce erroneous behavior yet.

Regardless, if I change the struct MidiMapping to use explicitly "signed" chars for port and channel, then those compiler warnings go away, and musescore seems to run normally. (alternatively I could change all those -1 into 255 and make channel and port explicitly unsigned, which might save an instruction on ARM although might be less readable). But before I submit PR, I'm going to try to create some test script that will cause bogus behavior.

There is also the question of Score::getNextFreeMidiMapping(int p, int ch) where I think for consistency those input ints should be signed chars as well.

I also wanted to note that MIDI data fields are only 0-127, but I'm not sure if port and channel are also limited to that range.


Comments

You could also cast all those -1s to char. Or use a constant for this and compare against that.
Like
define NONE ((char)-1)
or
const char none = (char)-1;
Or even the C++ way
define NONE char(-1)
or
const char none = char(-1);

Not sure about the number of possible ports, but there's a max. of 16 channels

Interesting, I never thought of defining based on char(-1)...then no need to change the data structure.

What define method is the most appropriate way for musescore code base? Where scopewise should I put it (at the top of score.h?)? I was initially going to make a #define, but I didn't see other defines like that.

well unfortunately Score::getNextFreeMidiMapping(int p, int ch) does use -1 in that same manner, so using such a define wouldn't work for that function. I could leave that function alone. Although I'd like to change it to use char as well. But that will cause a make world.

You could use 2 names, noChannel and noPort. I wouldn't use FREE, to easy to relate this to free()
On the other hand what's to lose when changing the chars in that struct to signed chars, that's what it is on other platforms (Windows, Mac(?), non-ARM Linux) anyway.

So I'm for changing the struct to explicitly use signed char for port and channel

while at it, you could probably also change "enum class StaffTypes : char" to a signed char (in libmscore/stafftype.h. line 152) it seems to cause another warning on ARM, in libmscore-stafftype.cpp, line 1300, where it gets (cast to int and then) compared to < 0.

I looked over the code surrounding the rest of those compiler warnings, and none of them seem to have any relation to ARM. I think they're benign, except for the fact that they pollute the build output and hence hide other important warnings by making them hard to spot. There are a few warnings for -Wmaybe-uninitialized which can be dealt with by initializing the variables, one -Wunused-variable for some preferences.cpp text that is never used. There are 23 warnings "-Wformat" for qDebug messages that convert from an enum to int.

The following "-Wstrict-overflow" warning is something that I didn't understand at first:

/home/e/MuseScore/mscore/importmidi/importmidi_voice.cpp: In function 'int Ms::MidiVoice::findMaxOccupiedVoiceInBar(const iterator&, const std::multimap&)':
/home/e/MuseScore/mscore/importmidi/importmidi_voice.cpp:704:5: warning: assuming signed overflow does not occur when assuming that (X + c) < X is always false [-Wstrict-overflow]
 int findMaxOccupiedVoiceInBar( 

After reading http://stackoverflow.com/questions/12984861/dont-understand-assuming-si… it seems to be about the compiler wanting to do certain optimizations that would for the most part be ok unless the values got big enough to overflow. I don't see any chars in that function, so I think this particular warning can be suppressed.

There are 2 benign -Wempty-body warnings:

/home/e/MuseScore/libmscore/element.cpp: In member function 'virtual QPointF Ms::Element::pagePos() const':
/home/e/MuseScore/libmscore/element.cpp:521:34: warning: suggest braces around empty body in an 'else' statement [-Wempty-body]
                   Q_ASSERT(false);
                                  ^
/home/e/MuseScore/libmscore/element.cpp: In member function 'virtual QPointF Ms::Element::canvasPos() const':
/home/e/MuseScore/libmscore/element.cpp:556:34: warning: suggest braces around empty body in an 'else' statement [-Wempty-body]
                   Q_ASSERT(false);

which occur because when Debug mode is disabled, those Q_ASSERTS are removed (I believe by pre-preprocessor), so those else statements are empty.

Anyway, I'm going to keep looking for the slur error, just letting you know it is not one of these compiler warnings.

I'm going to say mscore.h has lots of enums defined as (unspecified) char. I noticed when building in *debug mode* on qtcreator on my ARMv7-A machine, I get another -Wtype-limits error on line 1282 of style.cpp that is fixed by changing enum TextStyleType from char into an explicitly signed char. The error is due to a Q_ASSERT testing that enum >= 0, which I presume someone wrote because might have used -1 to indicate an invalid textstyle, but as we all know now, that Q_ASSERT is broken on ARM. Anyway, I think someone should make another PR going through every enum in mscore.h and decide if is really an unspecified char, because if at anytime someone uses -1 to represent invalid, then that char enum should probably be explicitly signed. Maybe there needs to be a musescore programming rule saying only use unspecified chars if sign doesn't matter for that char.

Quite a lot of these enums had been made a char by me. I tried to use signed char wherever it seemed needed, esp. obvious when in the initialization there were negative values and used plain char where it didn't seem to matter. Seems I missed the odd one here and there :-)

"enum class TextStyleType : char" seems to be one of them...

You know better than I which enums in mscore.h should be explicitly signed...

EDIT: It will take me too long to study all their usages, so I'll let you decide if you want and let you make any changes for what should be explicitly signed in mscore.h. Most of them look like sign doesn't matter, in which plain char is ok, but if any ever deal with any negative values, then should be explicitly signed.

Well, I really don't, as seen just looking at the initialization (and also the number of values, which may trigger the need to make it unsigned), which is what I did, isn't really sufficient in all cases. Here for "enum class TextStyleType : char" a compiler warning tells us about a potential problem, so we'd better fix it. Does changing this to signed char make the warning disappear, on ARM?
If so simply add it to your PR.

yes, changing TextStyleType to signed char fixes the compiler -Wtype-limit warning on my ARM (when building in qtcreator debug mode). I'll add it to my PR now...

ok, that PR passed travis and is ready for merge.

Regarding the slur & pedal issue in reunion: I thought it was an ARM-specific issue, but I've discovered that the issue also happens on x86-64 windows and arch linux nightly. So something must have been recently introduced since 2.0.2 that caused this. Also apparently, the pedal issue is present in 2.0.2 x86-64 windows & linux, so something else caused that issue. I've made a new forum post on it here: https://musescore.org/en/node/96816 so please comment there.

Status (old) patch (ready to commit) fixed

Fixed in branch master, commit e92386e3f7

fix #96626 signed chars for MidiMapping, StaffTypes, TextStyleType

ARM treats chars as unsigned by default, causing problems when comparing to negative values. Explicitly declaring these "chars" as "signed chars" fixes this.

Fixed in branch 2.0.3, commit 9a843466a5

fix #96626 signed chars for MidiMapping, StaffTypes, TextStyleType

ARM treats chars as unsigned by default, causing problems when comparing to negative values. Explicitly declaring these "chars" as "signed chars" fixes this.