Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmExprParserHelper.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmExprParserHelper.h"
4
5
#include <iostream>
6
#include <stdexcept>
7
#include <utility>
8
9
#include "cmExprLexer.h"
10
#include "cmStringAlgorithms.h"
11
12
int cmExpr_yyparse(yyscan_t yyscanner);
13
//
14
cmExprParserHelper::cmExprParserHelper()
15
1.85k
{
16
1.85k
  this->FileLine = -1;
17
1.85k
  this->FileName = nullptr;
18
1.85k
  this->Result = 0;
19
1.85k
}
20
21
1.85k
cmExprParserHelper::~cmExprParserHelper() = default;
22
23
int cmExprParserHelper::ParseString(char const* str, int verb)
24
1.85k
{
25
1.85k
  if (!str) {
26
0
    return 0;
27
0
  }
28
  // printf("Do some parsing: %s\n", str);
29
30
1.85k
  this->Verbose = verb;
31
1.85k
  this->InputBuffer = str;
32
1.85k
  this->InputBufferPos = 0;
33
1.85k
  this->CurrentLine = 0;
34
35
1.85k
  this->Result = 0;
36
37
1.85k
  yyscan_t yyscanner;
38
1.85k
  cmExpr_yylex_init(&yyscanner);
39
1.85k
  cmExpr_yyset_extra(this, yyscanner);
40
41
1.85k
  try {
42
1.85k
    int res = cmExpr_yyparse(yyscanner);
43
1.85k
    if (res != 0) {
44
244
      std::string e =
45
244
        cmStrCat("cannot parse the expression: \"", this->InputBuffer,
46
244
                 "\": ", this->ErrorString, '.');
47
244
      this->SetError(std::move(e));
48
244
    }
49
1.85k
  } catch (std::runtime_error const& fail) {
50
9
    std::string e = cmStrCat("cannot evaluate the expression: \"",
51
9
                             this->InputBuffer, "\": ", fail.what(), '.');
52
9
    this->SetError(std::move(e));
53
75
  } catch (std::out_of_range const&) {
54
75
    std::string e =
55
75
      cmStrCat("cannot evaluate the expression: \"", this->InputBuffer,
56
75
               "\": a numeric value is out of range.");
57
75
    this->SetError(std::move(e));
58
75
  } catch (...) {
59
0
    std::string e =
60
0
      cmStrCat("cannot parse the expression: \"", this->InputBuffer, "\".");
61
0
    this->SetError(std::move(e));
62
0
  }
63
1.85k
  cmExpr_yylex_destroy(yyscanner);
64
1.85k
  if (!this->ErrorString.empty()) {
65
328
    return 0;
66
328
  }
67
68
1.53k
  if (this->Verbose) {
69
0
    std::cerr << "Expanding [" << str << "] produced: [" << this->Result << "]"
70
0
              << std::endl;
71
0
  }
72
1.53k
  return 1;
73
1.85k
}
74
75
int cmExprParserHelper::LexInput(char* buf, int maxlen)
76
177k
{
77
  // std::cout << "JPLexInput ";
78
  // std::cout.write(buf, maxlen);
79
  // std::cout << std::endl;
80
177k
  if (maxlen < 1) {
81
0
    return 0;
82
0
  }
83
177k
  if (this->InputBufferPos < this->InputBuffer.size()) {
84
175k
    buf[0] = this->InputBuffer[this->InputBufferPos++];
85
175k
    if (buf[0] == '\n') {
86
321
      this->CurrentLine++;
87
321
    }
88
175k
    return (1);
89
175k
  }
90
1.74k
  buf[0] = '\n';
91
1.74k
  return (0);
92
177k
}
93
94
void cmExprParserHelper::Error(char const* str)
95
244
{
96
244
  unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
97
244
  this->ErrorString = cmStrCat(str, " (", pos, ')');
98
244
}
99
100
void cmExprParserHelper::Warning(std::string str)
101
8.57k
{
102
8.57k
  this->WarningString = cmStrCat(this->WarningString, std::move(str), '\n');
103
8.57k
}
104
105
void cmExprParserHelper::UnexpectedChar(char c)
106
25.8k
{
107
25.8k
  unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
108
25.8k
  this->WarningString = cmStrCat(
109
25.8k
    this->WarningString, "Unexpected character in expression at position ",
110
25.8k
    pos, ": ", c, '\n');
111
25.8k
}
112
113
void cmExprParserHelper::SetResult(std::int64_t value)
114
1.56k
{
115
1.56k
  this->Result = value;
116
1.56k
}
117
118
void cmExprParserHelper::SetError(std::string errorString)
119
328
{
120
328
  this->ErrorString = std::move(errorString);
121
328
}
122
123
std::int64_t cmExprParserHelper::ShL(std::int64_t l, std::int64_t r)
124
4.68k
{
125
4.68k
  if (l < 0) {
126
1.20k
    this->Warning(
127
1.20k
      cmStrCat("left shift of negative value in:\n  ", l, " << ", r));
128
1.20k
  }
129
4.68k
  if (r < 0) {
130
1.90k
    this->Warning(
131
1.90k
      cmStrCat("shift exponent is negative in:\n  ", l, " << ", r));
132
1.90k
    r &= 0x3F;
133
1.90k
  }
134
4.68k
  if (r >= 64) {
135
1.02k
    this->Warning(
136
1.02k
      cmStrCat("shift exponent is too large in:\n  ", l, " << ", r));
137
1.02k
    r &= 0x3F;
138
1.02k
  }
139
4.68k
  return static_cast<std::int64_t>(static_cast<std::uint64_t>(l) << r);
140
4.68k
}
141
142
std::int64_t cmExprParserHelper::ShR(std::int64_t l, std::int64_t r)
143
1.63k
{
144
1.63k
  if (r < 0) {
145
561
    this->Warning(
146
561
      cmStrCat("shift exponent is negative in:\n  ", l, " >> ", r));
147
561
    r &= 0x3F;
148
561
  }
149
1.63k
  if (r >= 64) {
150
711
    this->Warning(
151
711
      cmStrCat("shift exponent is too large in:\n  ", l, " >> ", r));
152
711
    r &= 0x3F;
153
711
  }
154
1.63k
  return l >> r;
155
1.63k
}
156
157
std::int64_t cmExprParserHelper::Add(std::int64_t l, std::int64_t r)
158
919
{
159
919
  std::int64_t sum;
160
919
  if (this->AddOverflow(l, r, &sum)) {
161
379
    this->Warning(cmStrCat("signed integer overflow in:\n  ", l, " + ", r));
162
379
  }
163
919
  return sum;
164
919
}
165
166
std::int64_t cmExprParserHelper::Sub(std::int64_t l, std::int64_t r)
167
2.58k
{
168
2.58k
  std::int64_t diff;
169
2.58k
  if (this->SubOverflow(l, r, &diff)) {
170
489
    this->Warning(cmStrCat("signed integer overflow in:\n  ", l, " - ", r));
171
489
  }
172
2.58k
  return diff;
173
2.58k
}
174
175
std::int64_t cmExprParserHelper::Mul(std::int64_t l, std::int64_t r)
176
952
{
177
952
  std::int64_t prod;
178
952
  if (this->MulOverflow(l, r, &prod)) {
179
453
    this->Warning(cmStrCat("signed integer overflow in:\n  ", l, " * ", r));
180
453
  }
181
952
  return prod;
182
952
}
183
184
std::int64_t cmExprParserHelper::Div(std::int64_t l, std::int64_t r)
185
1.44k
{
186
1.44k
  if (r == 0) {
187
2
    throw std::overflow_error("divide by zero");
188
2
  }
189
1.44k
  if (l == INT64_MIN && r == -1) {
190
1
    throw std::overflow_error("signed integer overflow in division");
191
1
  }
192
1.44k
  return l / r;
193
1.44k
}
194
195
std::int64_t cmExprParserHelper::Mod(std::int64_t l, std::int64_t r)
196
1.42k
{
197
1.42k
  if (r == 0) {
198
4
    throw std::overflow_error("modulo by zero");
199
4
  }
200
1.41k
  if (l == INT64_MIN && r == -1) {
201
2
    throw std::overflow_error("signed integer overflow in modulo");
202
2
  }
203
1.41k
  return l % r;
204
1.41k
}
205
206
std::int64_t cmExprParserHelper::Neg(std::int64_t x)
207
6.78k
{
208
6.78k
  if (static_cast<std::uint64_t>(x) == 0x8000000000000000) {
209
1.83k
    this->Warning(cmStrCat("signed integer cannot negate:\n  ", x));
210
1.83k
    return x;
211
1.83k
  }
212
4.94k
  return -x;
213
6.78k
}
214
215
// The __has_builtin preprocessor check was added in Clang 2.6 and GCC 10.
216
// The __builtin_X_overflow intrinsics were added in Clang 3.4 and GCC 5.
217
#ifndef __has_builtin
218
#  if defined(__GNUC__) && __GNUC__ >= 5
219
#    define __has_builtin(x) 1
220
#  else
221
#    define __has_builtin(x) 0
222
#  endif
223
#endif
224
225
bool cmExprParserHelper::AddOverflow(long l, long r, long* p)
226
919
{
227
919
#if __has_builtin(__builtin_saddl_overflow)
228
919
  return __builtin_saddl_overflow(l, r, p);
229
#else
230
  *p = l + r;
231
  return false;
232
#endif
233
919
}
234
235
bool cmExprParserHelper::AddOverflow(long long l, long long r, long long* p)
236
0
{
237
0
#if __has_builtin(__builtin_saddll_overflow)
238
0
  return __builtin_saddll_overflow(l, r, p);
239
#else
240
  *p = l + r;
241
  return false;
242
#endif
243
0
}
244
245
bool cmExprParserHelper::SubOverflow(long l, long r, long* p)
246
2.58k
{
247
2.58k
#if __has_builtin(__builtin_ssubl_overflow)
248
2.58k
  return __builtin_ssubl_overflow(l, r, p);
249
#else
250
  *p = l - r;
251
  return false;
252
#endif
253
2.58k
}
254
255
bool cmExprParserHelper::SubOverflow(long long l, long long r, long long* p)
256
0
{
257
0
#if __has_builtin(__builtin_ssubll_overflow)
258
0
  return __builtin_ssubll_overflow(l, r, p);
259
#else
260
  *p = l - r;
261
  return false;
262
#endif
263
0
}
264
265
bool cmExprParserHelper::MulOverflow(long l, long r, long* p)
266
952
{
267
952
#if __has_builtin(__builtin_smull_overflow)
268
952
  return __builtin_smull_overflow(l, r, p);
269
#else
270
  *p = l * r;
271
  return false;
272
#endif
273
952
}
274
275
bool cmExprParserHelper::MulOverflow(long long l, long long r, long long* p)
276
0
{
277
0
#if __has_builtin(__builtin_smulll_overflow)
278
0
  return __builtin_smulll_overflow(l, r, p);
279
#else
280
  *p = l * r;
281
  return false;
282
#endif
283
0
}