Fix out of range access in Label (#18789)

Out of range occurred in some condition
when using `Label` with its `getLetter()` member function.

`Label::recordPlaceholderInfo()` member function is called for
new line (\n) letter in `Label::multilineTextWrap()`,
but the function doesn't set `_lettersInfo[letterIndex].lineIndex`.

But `lineIndex` is used in `Label::updateLabelLetters()`
even if letter is new line.

This change checks `letterInfo.valid` to avoid
accessing `_linesOffsetX[letterInfo.lineIndex]`
for invalid (i.e. `NewLine`) letter.
This commit is contained in:
tyfkda 2018-08-06 15:27:47 +09:00 committed by leda
parent dfa0360d99
commit aacec550c9
3 changed files with 70 additions and 19 deletions

View File

@ -766,30 +766,36 @@ void Label::updateLabelLetters()
else
{
auto& letterInfo = _lettersInfo[letterIndex];
auto& letterDef = _fontAtlas->_letterDefinitions[letterInfo.utf32Char];
uvRect.size.height = letterDef.height;
uvRect.size.width = letterDef.width;
uvRect.origin.x = letterDef.U;
uvRect.origin.y = letterDef.V;
auto batchNode = _batchNodes.at(letterDef.textureID);
letterSprite->setTextureAtlas(batchNode->getTextureAtlas());
letterSprite->setTexture(_fontAtlas->getTexture(letterDef.textureID));
if (letterDef.width <= 0.f || letterDef.height <= 0.f)
if (letterInfo.valid)
{
letterSprite->setTextureAtlas(nullptr);
auto& letterDef = _fontAtlas->_letterDefinitions[letterInfo.utf32Char];
uvRect.size.height = letterDef.height;
uvRect.size.width = letterDef.width;
uvRect.origin.x = letterDef.U;
uvRect.origin.y = letterDef.V;
auto batchNode = _batchNodes.at(letterDef.textureID);
letterSprite->setTextureAtlas(batchNode->getTextureAtlas());
letterSprite->setTexture(_fontAtlas->getTexture(letterDef.textureID));
if (letterDef.width <= 0.f || letterDef.height <= 0.f)
{
letterSprite->setTextureAtlas(nullptr);
}
else
{
letterSprite->setTextureRect(uvRect, false, uvRect.size);
letterSprite->setTextureAtlas(_batchNodes.at(letterDef.textureID)->getTextureAtlas());
letterSprite->setAtlasIndex(_lettersInfo[letterIndex].atlasIndex);
}
auto px = letterInfo.positionX + letterDef.width / 2 + _linesOffsetX[letterInfo.lineIndex];
auto py = letterInfo.positionY - letterDef.height / 2 + _letterOffsetY;
letterSprite->setPosition(px, py);
}
else
{
letterSprite->setTextureRect(uvRect, false, uvRect.size);
letterSprite->setTextureAtlas(_batchNodes.at(letterDef.textureID)->getTextureAtlas());
letterSprite->setAtlasIndex(_lettersInfo[letterIndex].atlasIndex);
letterSprite->setTextureAtlas(nullptr);
}
auto px = letterInfo.positionX + letterDef.width / 2 + _linesOffsetX[letterInfo.lineIndex];
auto py = letterInfo.positionY - letterDef.height / 2 + _letterOffsetY;
letterSprite->setPosition(px, py);
this->updateLetterSpriteScale(letterSprite);
++it;
}

View File

@ -140,6 +140,7 @@ NewLabelTests::NewLabelTests()
ADD_TEST_CASE(LabelIssue16717);
ADD_TEST_CASE(LabelIssueLineGap);
ADD_TEST_CASE(LabelIssue17902);
ADD_TEST_CASE(LabelLetterColorsTest);
};
LabelFNTColorAndOpacity::LabelFNTColorAndOpacity()
@ -3567,4 +3568,35 @@ std::string LabelIssue17902::subtitle() const
return "";
}
//
// LabelLetterColorsTest
//
LabelLetterColorsTest::LabelLetterColorsTest() {
auto center = VisibleRect::center();
auto label = Label::createWithTTF("", "fonts/arial.ttf", 24);
label->setPosition(center.x, center.y);
addChild(label);
label->setString("1\n2\n3");
setLetterColors(label, Color3B::RED);
label->setString("abcd\ne"); // Must not crash at here.
}
std::string LabelLetterColorsTest::title() const {
return "Test for letter colors";
}
std::string LabelLetterColorsTest::subtitle() const {
return "Should not crash!";
}
void LabelLetterColorsTest::setLetterColors(cocos2d::Label* label, const cocos2d::Color3B& color) {
int n = label->getStringLength();
for (int i = 0; i < n; ++i) {
Sprite* letter = label->getLetter(i);
if (letter != nullptr)
letter->setColor(color);
}
}

View File

@ -980,4 +980,17 @@ public:
virtual std::string subtitle() const override;
};
class LabelLetterColorsTest : public AtlasDemoNew {
public:
CREATE_FUNC(LabelLetterColorsTest);
LabelLetterColorsTest();
virtual std::string title() const override;
virtual std::string subtitle() const override;
private:
static void setLetterColors(cocos2d::Label* label, const cocos2d::Color3B& color);
};
#endif