Bug Summary

File:root/firefox-clang/gfx/graphite2/src/Segment.cpp
Warning:line 314, column 69
Although the value stored to 'clusterMin' is used in the enclosing expression, the value is never actually read from 'clusterMin'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_gfx_graphite2_src0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/graphite2/src -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/graphite2/src -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D PACKAGE_VERSION="moz" -D PACKAGE_BUGREPORT="http://bugzilla.mozilla.org/" -D GRAPHITE2_STATIC -D GRAPHITE2_CUSTOM_HEADER="MozGrMalloc.h" -D GRAPHITE2_NFILEFACE -D GRAPHITE2_NTRACING -D GRAPHITE2_NSEGCACHE -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/gfx/graphite2/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/graphite2/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-26-231904-1820671-1 -x c++ Unified_cpp_gfx_graphite2_src0.cpp
1/* GRAPHITE2 LICENSING
2
3 Copyright 2010, SIL International
4 All rights reserved.
5
6 This library is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should also have received a copy of the GNU Lesser General Public
17 License along with this library in the file named "LICENSE".
18 If not, write to the Free Software Foundation, 51 Franklin Street,
19 Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
20 internet at http://www.fsf.org/licenses/lgpl.html.
21
22Alternatively, the contents of this file may be used under the terms of the
23Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
24License, as published by the Free Software Foundation, either version 2
25of the License or (at your option) any later version.
26*/
27#include "inc/UtfCodec.h"
28#include <cstring>
29#include <cstdlib>
30
31#include "inc/bits.h"
32#include "inc/Segment.h"
33#include "graphite2/Font.h"
34#include "inc/CharInfo.h"
35#include "inc/debug.h"
36#include "inc/Slot.h"
37#include "inc/Main.h"
38#include "inc/CmapCache.h"
39#include "inc/Collider.h"
40#include "graphite2/Segment.h"
41
42
43using namespace graphite2;
44
45Segment::Segment(size_t numchars, const Face* face, uint32 script, int textDir)
46: m_freeSlots(NULL__null),
47 m_freeJustifies(NULL__null),
48 m_charinfo(new CharInfo[numchars]),
49 m_collisions(NULL__null),
50 m_face(face),
51 m_silf(face->chooseSilf(script)),
52 m_first(NULL__null),
53 m_last(NULL__null),
54 m_bufSize(numchars + 10),
55 m_numGlyphs(numchars),
56 m_numCharinfo(numchars),
57 m_defaultOriginal(0),
58 m_dir(textDir),
59 m_flags(((m_silf->flags() & 0x20) != 0) << 1),
60 m_passBits(m_silf->aPassBits() ? -1 : 0)
61{
62 freeSlot(newSlot());
63 m_bufSize = log_binary(numchars)+1;
64}
65
66Segment::~Segment()
67{
68 for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)
69 free(*i);
70 for (AttributeRope::iterator i = m_userAttrs.begin(); i != m_userAttrs.end(); ++i)
71 free(*i);
72 for (JustifyRope::iterator i = m_justifies.begin(); i != m_justifies.end(); ++i)
73 free(*i);
74 delete[] m_charinfo;
75 free(m_collisions);
76}
77
78void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
79{
80 Slot *aSlot = newSlot();
81
82 if (!aSlot) return;
83 m_charinfo[id].init(cid);
84 m_charinfo[id].feats(iFeats);
85 m_charinfo[id].base(coffset);
86 const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);
87 m_charinfo[id].breakWeight(theGlyph ? theGlyph->attrs()[m_silf->aBreak()] : 0);
88
89 aSlot->child(NULL__null);
90 aSlot->setGlyph(this, gid, theGlyph);
91 aSlot->originate(id);
92 aSlot->before(id);
93 aSlot->after(id);
94 if (m_last) m_last->next(aSlot);
95 aSlot->prev(m_last);
96 m_last = aSlot;
97 if (!m_first) m_first = aSlot;
98 if (theGlyph && m_silf->aPassBits())
99 m_passBits &= theGlyph->attrs()[m_silf->aPassBits()]
100 | (m_silf->numPasses() > 16 ? (theGlyph->attrs()[m_silf->aPassBits() + 1] << 16) : 0);
101}
102
103Slot *Segment::newSlot()
104{
105 if (!m_freeSlots)
106 {
107 // check that the segment doesn't grow indefinintely
108 if (m_numGlyphs > m_numCharinfo * MAX_SEG_GROWTH_FACTOR64)
109 return NULL__null;
110 int numUser = m_silf->numUser();
111#if !defined GRAPHITE2_NTRACING1
112 if (m_face->logger()) ++numUser;
113#endif
114 Slot *newSlots = grzeroalloc<Slot>(m_bufSize);
115 int16 *newAttrs = grzeroalloc<int16>(m_bufSize * numUser);
116 if (!newSlots || !newAttrs)
117 {
118 free(newSlots);
119 free(newAttrs);
120 return NULL__null;
121 }
122 for (size_t i = 0; i < m_bufSize; i++)
123 {
124 ::new (newSlots + i) Slot(newAttrs + i * numUser);
125 newSlots[i].next(newSlots + i + 1);
126 }
127 newSlots[m_bufSize - 1].next(NULL__null);
128 newSlots[0].next(NULL__null);
129 m_slots.push_back(newSlots);
130 m_userAttrs.push_back(newAttrs);
131 m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL__null;
132 return newSlots;
133 }
134 Slot *res = m_freeSlots;
135 m_freeSlots = m_freeSlots->next();
136 res->next(NULL__null);
137 return res;
138}
139
140void Segment::freeSlot(Slot *aSlot)
141{
142 if (aSlot == nullptr) return;
143 if (m_last == aSlot) m_last = aSlot->prev();
144 if (m_first == aSlot) m_first = aSlot->next();
145 if (aSlot->attachedTo())
146 aSlot->attachedTo()->removeChild(aSlot);
147 while (aSlot->firstChild())
148 {
149 if (aSlot->firstChild()->attachedTo() == aSlot)
150 {
151 aSlot->firstChild()->attachTo(nullptr);
152 aSlot->removeChild(aSlot->firstChild());
153 }
154 else
155 aSlot->firstChild(nullptr);
156 }
157 // reset the slot incase it is reused
158 ::new (aSlot) Slot(aSlot->userAttrs());
159 memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
160 // Update generation counter for debug
161#if !defined GRAPHITE2_NTRACING1
162 if (m_face->logger())
163 ++aSlot->userAttrs()[m_silf->numUser()];
164#endif
165 // update next pointer
166 if (!m_freeSlots)
167 aSlot->next(nullptr);
168 else
169 aSlot->next(m_freeSlots);
170 m_freeSlots = aSlot;
171}
172
173SlotJustify *Segment::newJustify()
174{
175 if (!m_freeJustifies)
176 {
177 const size_t justSize = SlotJustify::size_of(m_silf->numJustLevels());
178 byte *justs = grzeroalloc<byte>(justSize * m_bufSize);
179 if (!justs) return NULL__null;
180 for (ptrdiff_t i = m_bufSize - 2; i >= 0; --i)
181 {
182 SlotJustify *p = reinterpret_cast<SlotJustify *>(justs + justSize * i);
183 SlotJustify *next = reinterpret_cast<SlotJustify *>(justs + justSize * (i + 1));
184 p->next = next;
185 }
186 m_freeJustifies = (SlotJustify *)justs;
187 m_justifies.push_back(m_freeJustifies);
188 }
189 SlotJustify *res = m_freeJustifies;
190 m_freeJustifies = m_freeJustifies->next;
191 res->next = NULL__null;
192 return res;
193}
194
195void Segment::freeJustify(SlotJustify *aJustify)
196{
197 int numJust = m_silf->numJustLevels();
198 if (m_silf->numJustLevels() <= 0) numJust = 1;
199 aJustify->next = m_freeJustifies;
200 memset(aJustify->values, 0, numJust*SlotJustify::NUMJUSTPARAMS*sizeof(int16));
201 m_freeJustifies = aJustify;
202}
203
204// reverse the slots but keep diacritics in their same position after their bases
205void Segment::reverseSlots()
206{
207 m_dir = m_dir ^ 64; // invert the reverse flag
208 if (m_first == m_last) return; // skip 0 or 1 glyph runs
209
210 Slot *t = 0;
211 Slot *curr = m_first;
212 Slot *tlast;
213 Slot *tfirst;
214 Slot *out = 0;
215
216 while (curr && getSlotBidiClass(curr) == 16)
217 curr = curr->next();
218 if (!curr) return;
219 tfirst = curr->prev();
220 tlast = curr;
221
222 while (curr)
223 {
224 if (getSlotBidiClass(curr) == 16)
225 {
226 Slot *d = curr->next();
227 while (d && getSlotBidiClass(d) == 16)
228 d = d->next();
229
230 d = d ? d->prev() : m_last;
231 Slot *p = out->next(); // one after the diacritics. out can't be null
232 if (p)
233 p->prev(d);
234 else
235 tlast = d;
236 t = d->next();
237 d->next(p);
238 curr->prev(out);
239 out->next(curr);
240 }
241 else // will always fire first time round the loop
242 {
243 if (out)
244 out->prev(curr);
245 t = curr->next();
246 curr->next(out);
247 out = curr;
248 }
249 curr = t;
250 }
251 out->prev(tfirst);
252 if (tfirst)
253 tfirst->next(out);
254 else
255 m_first = out;
256 m_last = tlast;
257}
258
259void Segment::linkClusters(Slot *s, Slot * end)
260{
261 end = end->next();
262
263 for (; s != end && !s->isBase(); s = s->next());
264 Slot * ls = s;
265
266 if (m_dir & 1)
267 {
268 for (; s != end; s = s->next())
269 {
270 if (!s->isBase()) continue;
271
272 s->sibling(ls);
273 ls = s;
274 }
275 }
276 else
277 {
278 for (; s != end; s = s->next())
279 {
280 if (!s->isBase()) continue;
281
282 ls->sibling(s);
283 ls = s;
284 }
285 }
286}
287
288Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal)
289{
290 Position currpos(0., 0.);
291 float clusterMin = 0.;
292 Rect bbox;
293 bool reorder = (currdir() != isRtl);
294
295 if (reorder)
296 {
297 Slot *temp;
298 reverseSlots();
299 temp = iStart;
300 iStart = iEnd;
301 iEnd = temp;
302 }
303 if (!iStart) iStart = m_first;
304 if (!iEnd) iEnd = m_last;
305
306 if (!iStart || !iEnd) // only true for empty segments
307 return currpos;
308
309 if (isRtl)
310 {
311 for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
312 {
313 if (s->isBase())
314 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
Although the value stored to 'clusterMin' is used in the enclosing expression, the value is never actually read from 'clusterMin'
315 }
316 }
317 else
318 {
319 for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
320 {
321 if (s->isBase())
322 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
323 }
324 }
325 if (reorder)
326 reverseSlots();
327 return currpos;
328}
329
330
331void Segment::associateChars(int offset, size_t numChars)
332{
333 int i = 0, j = 0;
334 CharInfo *c, *cend;
335 for (c = m_charinfo + offset, cend = m_charinfo + offset + numChars; c != cend; ++c)
336 {
337 c->before(-1);
338 c->after(-1);
339 }
340 for (Slot * s = m_first; s; s->index(i++), s = s->next())
341 {
342 j = s->before();
343 if (j < 0) continue;
344
345 for (const int after = s->after(); j <= after; ++j)
346 {
347 c = charinfo(j);
348 if (c->before() == -1 || i < c->before()) c->before(i);
349 if (c->after() < i) c->after(i);
350 }
351 }
352 for (Slot *s = m_first; s; s = s->next())
353 {
354 int a;
355 for (a = s->after() + 1; a < offset + int(numChars) && charinfo(a)->after() < 0; ++a)
356 { charinfo(a)->after(s->index()); }
357 --a;
358 s->after(a);
359
360 for (a = s->before() - 1; a >= offset && charinfo(a)->before() < 0; --a)
361 { charinfo(a)->before(s->index()); }
362 ++a;
363 s->before(a);
364 }
365}
366
367
368template <typename utf_iter>
369inline void process_utf_data(Segment & seg, const Face & face, const int fid, utf_iter c, size_t n_chars)
370{
371 const Cmap & cmap = face.cmap();
372 int slotid = 0;
373
374 const typename utf_iter::codeunit_type * const base = c;
375 for (; n_chars; --n_chars, ++c, ++slotid)
376 {
377 const uint32 usv = *c;
378 uint16 gid = cmap[usv];
379 if (!gid) gid = face.findPseudo(usv);
380 seg.appendSlot(slotid, usv, gid, fid, c - base);
381 }
382}
383
384
385bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars)
386{
387 assert(face)(static_cast <bool> (face) ? void (0) : __assert_fail (
"face", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
388 assert(pFeats)(static_cast <bool> (pFeats) ? void (0) : __assert_fail
("pFeats", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
389 if (!m_charinfo) return false;
390
391 // utf iterator is self recovering so we don't care about the error state of the iterator.
392 switch (enc)
393 {
394 case gr_utf8: process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;
395 case gr_utf16: process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;
396 case gr_utf32: process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;
397 }
398 return true;
399}
400
401void Segment::doMirror(uint16 aMirror)
402{
403 Slot * s;
404 for (s = m_first; s; s = s->next())
405 {
406 unsigned short g = glyphAttr(s->gid(), aMirror);
407 if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1)))
408 s->setGlyph(this, g);
409 }
410}
411
412bool Segment::initCollisions()
413{
414 m_collisions = grzeroalloc<SlotCollision>(slotCount());
415 if (!m_collisions) return false;
416
417 for (Slot *p = m_first; p; p = p->next())
418 if (p->index() < slotCount())
419 ::new (collisionInfo(p)) SlotCollision(this, p);
420 else
421 return false;
422 return true;
423}