1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "zbxalgo.h"
22 #include "zbxvariant.h"
23 #include "log.h"
24 
25 /******************************************************************************
26  *                                                                            *
27  *                     Module for evaluating expressions                      *
28  *                  ---------------------------------------                   *
29  *                                                                            *
30  * Global variables are used for efficiency reasons so that arguments do not  *
31  * have to be passed to each of evaluate_termX() functions. For this reason,  *
32  * too, this module is isolated into a separate file.                         *
33  *                                                                            *
34  * The priority of supported operators is as follows:                         *
35  *                                                                            *
36  *   - (unary)   evaluate_term8()                                             *
37  *   not         evaluate_term7()                                             *
38  *   * /         evaluate_term6()                                             *
39  *   + -         evaluate_term5()                                             *
40  *   < <= >= >   evaluate_term4()                                             *
41  *   = <>        evaluate_term3()                                             *
42  *   and         evaluate_term2()                                             *
43  *   or          evaluate_term1()                                             *
44  *                                                                            *
45  * Function evaluate_term9() is used for parsing tokens on the lowest level:  *
46  * those can be suffixed numbers like "12.345K" or parenthesized expressions. *
47  *                                                                            *
48  ******************************************************************************/
49 
50 static const char	*ptr;		/* character being looked at */
51 static int		level;		/* expression nesting level  */
52 
53 static char		*buffer;	/* error message buffer      */
54 static size_t		max_buffer_len;	/* error message buffer size */
55 
56 /******************************************************************************
57  *                                                                            *
58  * Purpose: check whether the character delimits a numeric token              *
59  *                                                                            *
60  ******************************************************************************/
is_number_delimiter(char c)61 static int	is_number_delimiter(char c)
62 {
63 	return 0 == isdigit(c) && '.' != c && 0 == isalpha(c) ? SUCCEED : FAIL;
64 }
65 
66 /******************************************************************************
67  *                                                                            *
68  * Purpose: check whether the character delimits a symbolic operator token    *
69  *                                                                            *
70  ******************************************************************************/
is_operator_delimiter(char c)71 static int	is_operator_delimiter(char c)
72 {
73 	return ' ' == c || '(' == c || '\r' == c || '\n' == c || '\t' == c || ')' == c || '\0' == c ? SUCCEED : FAIL;
74 }
75 
76 /******************************************************************************
77  *                                                                            *
78  * Purpose: evaluate a quoted string like "/etc/passwd"                       *
79  * Characters '\' and '"' are expected to be escaped or parsing fails         *
80  *                                                                            *
81  ******************************************************************************/
evaluate_string(zbx_variant_t * res)82 static void	evaluate_string(zbx_variant_t *res)
83 {
84 	const char	*start;
85 	char		*res_temp = NULL, *dst;
86 	int		str_len = 0;
87 
88 	for (start = ptr; '"' != *ptr; ptr++)
89 	{
90 		if ('\\' == *ptr)
91 		{
92 			ptr++;
93 
94 			if ('\\' != *ptr && '\"' != *ptr && '\0' != *ptr)
95 			{
96 				zbx_snprintf(buffer, max_buffer_len, "Cannot evaluate expression:"
97 						" invalid escape sequence at \"%s\".", ptr - 1);
98 				zbx_variant_set_dbl(res, ZBX_INFINITY);
99 				return;
100 			}
101 
102 		}
103 
104 		if ('\0' == *ptr)
105 		{
106 			zbx_variant_set_dbl(res, ZBX_INFINITY);
107 			zbx_snprintf(buffer, max_buffer_len, "Cannot evaluate expression:"
108 					" unterminated string at \"%s\".", start);
109 			return;
110 		}
111 	}
112 
113 	str_len = ptr - start;
114 	res_temp = zbx_malloc(NULL, str_len + 1);
115 
116 	for (dst = res_temp; start != ptr; start++)
117 	{
118 		switch (*start)
119 		{
120 			case '\\':
121 				start++;
122 				break;
123 			case '\r':
124 				continue;
125 		}
126 		*dst++ = *start;
127 	}
128 	*dst = '\0';
129 	zbx_variant_set_str(res, res_temp);
130 }
131 
132 /******************************************************************************
133  *                                                                            *
134  * Purpose: evaluate a suffixed number like 12.345K                           *
135  *                                                                            *
136  ******************************************************************************/
evaluate_number(int * unknown_idx)137 static double	evaluate_number(int *unknown_idx)
138 {
139 	double		result;
140 	int		len;
141 
142 	/* Is it a special token of unknown value (e.g. ZBX_UNKNOWN0, ZBX_UNKNOWN1) ? */
143 	if (0 == strncmp(ZBX_UNKNOWN_STR, ptr, ZBX_UNKNOWN_STR_LEN))
144 	{
145 		const char	*p0, *p1;
146 
147 		p0 = ptr + ZBX_UNKNOWN_STR_LEN;
148 		p1 = p0;
149 
150 		/* extract the message number which follows after 'ZBX_UNKNOWN' */
151 		while (0 != isdigit((unsigned char)*p1))
152 			p1++;
153 
154 		if (p0 < p1 && SUCCEED == is_number_delimiter(*p1))
155 		{
156 			ptr = p1;
157 
158 			/* return 'unknown' and corresponding message number about its origin */
159 			*unknown_idx = atoi(p0);
160 			return ZBX_UNKNOWN;
161 		}
162 
163 		ptr = p0;
164 
165 		return ZBX_INFINITY;
166 	}
167 
168 	if (SUCCEED == zbx_suffixed_number_parse(ptr, &len) && SUCCEED == is_number_delimiter(*(ptr + len)))
169 	{
170 		result = atof(ptr) * suffix2factor(*(ptr + len - 1));
171 		ptr += len;
172 	}
173 	else
174 		result = ZBX_INFINITY;
175 
176 	return result;
177 }
178 
179 /******************************************************************************
180  *                                                                            *
181  * Function: variant_convert_to_double                                        *
182  *                                                                            *
183  * Purpose: cast string variant to a double variant                           *
184  *                                                                            *
185  * Parameters: var - [IN/OUT] the variant to cast                             *
186  *                                                                            *
187  ******************************************************************************/
variant_convert_to_double(zbx_variant_t * var)188 static void	variant_convert_to_double(zbx_variant_t *var)
189 {
190 	if (ZBX_VARIANT_STR == var->type)
191 	{
192 		double	var_double_value = evaluate_string_to_double(var->data.str);
193 		if (ZBX_INFINITY == var_double_value)
194 		{
195 			zbx_snprintf(buffer, max_buffer_len, "Cannot evaluate expression:"
196 					" value \"%s\" is not a numeric operand.", var->data.str);
197 		}
198 		zbx_variant_clear(var);
199 		zbx_variant_set_dbl(var, var_double_value);
200 	}
201 }
202 
203 /******************************************************************************
204  *                                                                            *
205  * Function: variant_get_double                                               *
206  *                                                                            *
207  * Purpose: get variant value in double (float64) format                      *
208  *                                                                            *
209  * Parameters: var - [IN] the input variant                                   *
210  *                                                                            *
211  * Return value: Depending on variant type:                                   *
212  *    DBL - the variant value                                                 *
213  *    STR - if variant value contains valid float64 string (with supported    *
214  *          Zabbix suffixes) the converted value is returned. Otherwise       *
215  *          ZBX_INFINITY is returned.                                         *
216  *    other types - ZBX_INFINITY
217  *                                                                            *
218  ******************************************************************************/
variant_get_double(const zbx_variant_t * var)219 static double	variant_get_double(const zbx_variant_t *var)
220 {
221 	switch (var->type)
222 	{
223 		case ZBX_VARIANT_DBL:
224 			return var->data.dbl;
225 		case ZBX_VARIANT_STR:
226 			return evaluate_string_to_double(var->data.str);
227 		default:
228 			THIS_SHOULD_NEVER_HAPPEN;
229 			return ZBX_INFINITY;
230 	}
231 }
232 
233 static zbx_variant_t	evaluate_term1(int *unknown_idx);
234 
235 /******************************************************************************
236  *                                                                            *
237  * Purpose: evaluate a suffixed number or a parenthesized expression          *
238  *                                                                            *
239  ******************************************************************************/
evaluate_term9(int * unknown_idx)240 static zbx_variant_t	evaluate_term9(int *unknown_idx)
241 {
242 	zbx_variant_t	res;
243 
244 	while (' ' == *ptr || '\r' == *ptr || '\n' == *ptr || '\t' == *ptr)
245 		ptr++;
246 
247 	if ('\0' == *ptr)
248 	{
249 		zbx_strlcpy(buffer, "Cannot evaluate expression: unexpected end of expression.", max_buffer_len);
250 		zbx_variant_set_dbl(&res, ZBX_INFINITY);
251 		return res;
252 	}
253 
254 	if ('(' == *ptr)
255 	{
256 		ptr++;
257 
258 		res = evaluate_term1(unknown_idx);
259 
260 		if (ZBX_VARIANT_DBL == res.type && ZBX_INFINITY == res.data.dbl)
261 			return res;
262 
263 		/* if evaluate_term1() returns ZBX_UNKNOWN then continue as with regular number */
264 
265 		if (')' != *ptr)
266 		{
267 			zbx_snprintf(buffer, max_buffer_len, "Cannot evaluate expression:"
268 					" expected closing parenthesis at \"%s\".", ptr);
269 
270 			zbx_variant_clear(&res);
271 			zbx_variant_set_dbl(&res, ZBX_INFINITY);
272 
273 			return res;
274 		}
275 
276 		ptr++;
277 	}
278 	else
279 	{
280 		if ('"' == *ptr)
281 		{
282 			ptr++;
283 			evaluate_string(&res);
284 
285 			if (ZBX_VARIANT_DBL == res.type && ZBX_INFINITY == res.data.dbl)
286 				return res;
287 
288 			ptr++;
289 
290 			/* We do not really need to do this check. */
291 			/* The only reason we do it is to keep it consistent with */
292 			/* numeric tokens, where operators are not allowed after them: 123and. */
293 			/* Check below ensures that '"123"and' expression will fail as well. */
294 			if (FAIL == is_operator_delimiter(*ptr) && FAIL == is_number_delimiter(*ptr))
295 			{
296 				zbx_variant_clear(&res);
297 				zbx_variant_set_dbl(&res, ZBX_INFINITY);
298 				zbx_snprintf(buffer, max_buffer_len, "Cannot evaluate expression:"
299 						" unexpected token at \"%s\".", ptr);
300 			}
301 
302 		}
303 		else
304 		{
305 			zbx_variant_set_dbl(&res, evaluate_number(unknown_idx));
306 
307 			if (ZBX_INFINITY == res.data.dbl)
308 			{
309 				zbx_snprintf(buffer, max_buffer_len, "Cannot evaluate expression:"
310 						" expected numeric token at \"%s\".", ptr);
311 				return res;
312 			}
313 		}
314 	}
315 
316 	while ('\0' != *ptr && (' ' == *ptr || '\r' == *ptr || '\n' == *ptr || '\t' == *ptr))
317 		ptr++;
318 
319 	return res;
320 }
321 
322 /******************************************************************************
323  *                                                                            *
324  * Purpose: evaluate "-" (unary)                                              *
325  *                                                                            *
326  * -0.0     -> -0.0                                                           *
327  * -1.2     -> -1.2                                                           *
328  * -Unknown ->  Unknown                                                       *
329  *                                                                            *
330  ******************************************************************************/
evaluate_term8(int * unknown_idx)331 static zbx_variant_t	evaluate_term8(int *unknown_idx)
332 {
333 	while (' ' == *ptr || '\r' == *ptr || '\n' == *ptr || '\t' == *ptr)
334 		ptr++;
335 
336 	if ('-' == *ptr)
337 	{
338 		zbx_variant_t	res;
339 		ptr++;
340 		res = evaluate_term9(unknown_idx);
341 		variant_convert_to_double(&res);
342 
343 		if (ZBX_UNKNOWN == res.data.dbl || ZBX_INFINITY == res.data.dbl)
344 			return res;
345 
346 		res.data.dbl = -res.data.dbl;
347 		return res;
348 	}
349 	else
350 		return evaluate_term9(unknown_idx);
351 }
352 
353 /******************************************************************************
354  *                                                                            *
355  * Purpose: evaluate "not"                                                    *
356  *                                                                            *
357  * not 0.0     ->  1.0                                                        *
358  * not 1.2     ->  0.0                                                        *
359  * not Unknown ->  Unknown                                                    *
360  *                                                                            *
361  ******************************************************************************/
evaluate_term7(int * unknown_idx)362 static zbx_variant_t	evaluate_term7(int *unknown_idx)
363 {
364 	while (' ' == *ptr || '\r' == *ptr || '\n' == *ptr || '\t' == *ptr)
365 		ptr++;
366 
367 	if ('n' == ptr[0] && 'o' == ptr[1] && 't' == ptr[2] && SUCCEED == is_operator_delimiter(ptr[3]))
368 	{
369 		zbx_variant_t	res;
370 		ptr += 3;
371 		res = evaluate_term8(unknown_idx);
372 		variant_convert_to_double(&res);
373 
374 		if (ZBX_UNKNOWN == res.data.dbl || ZBX_INFINITY == res.data.dbl)
375 			return res;
376 
377 		res.data.dbl = (SUCCEED == zbx_double_compare(res.data.dbl, 0.0) ? 1.0 : 0.0);
378 		return res;
379 	}
380 	else
381 		return evaluate_term8(unknown_idx);
382 }
383 
384 /******************************************************************************
385  *                                                                            *
386  * Purpose: evaluate "*" and "/"                                              *
387  *                                                                            *
388  *     0.0 * Unknown  ->  Unknown (yes, not 0 as we don't want to lose        *
389  *                        Unknown in arithmetic operations)                   *
390  *     1.2 * Unknown  ->  Unknown                                             *
391  *     0.0 / 1.2      ->  0.0                                                 *
392  *     1.2 / 0.0      ->  error (ZBX_INFINITY)                                *
393  * Unknown / 0.0      ->  error (ZBX_INFINITY)                                *
394  * Unknown / 1.2      ->  Unknown                                             *
395  * Unknown / Unknown  ->  Unknown                                             *
396  *     0.0 / Unknown  ->  Unknown                                             *
397  *     1.2 / Unknown  ->  Unknown                                             *
398  *                                                                            *
399  ******************************************************************************/
evaluate_term6(int * unknown_idx)400 static zbx_variant_t	evaluate_term6(int *unknown_idx)
401 {
402 	char		op;
403 	int		res_idx = -1, oper_idx = -2;	/* set invalid values to catch errors */
404 	zbx_variant_t	res;
405 
406 	res = evaluate_term7(&res_idx);
407 
408 	if (ZBX_VARIANT_DBL == res.type)
409 	{
410 		if (ZBX_INFINITY == res.data.dbl)
411 			return res;
412 
413 		if (ZBX_UNKNOWN == res.data.dbl)
414 			*unknown_idx = res_idx;
415 	}
416 
417 	/* if evaluate_term7() returns ZBX_UNKNOWN then continue as with regular number */
418 
419 	while ('*' == *ptr || '/' == *ptr)
420 	{
421 		zbx_variant_t	operand;
422 
423 		variant_convert_to_double(&res);
424 
425 		if (ZBX_INFINITY == res.data.dbl)
426 			return res;
427 
428 		op = *ptr++;
429 
430 		/* 'ZBX_UNKNOWN' in multiplication and division produces 'ZBX_UNKNOWN'. */
431 		/* Even if 1st operand is Unknown we evaluate 2nd operand too to catch fatal errors in it. */
432 
433 		operand = evaluate_term7(&oper_idx);
434 		variant_convert_to_double(&operand);
435 
436 		if (ZBX_INFINITY == operand.data.dbl)
437 		{
438 			zbx_variant_clear(&res);
439 			zbx_variant_set_dbl(&res, ZBX_INFINITY);
440 			zbx_variant_clear(&operand);
441 			return res;
442 		}
443 
444 		if ('*' == op)
445 		{
446 			if (ZBX_UNKNOWN == operand.data.dbl)		/* (anything) * Unknown */
447 			{
448 				*unknown_idx = oper_idx;
449 				res_idx = oper_idx;
450 				res.data.dbl = ZBX_UNKNOWN;
451 			}
452 			else if (ZBX_UNKNOWN == res.data.dbl)		/* Unknown * known */
453 				*unknown_idx = res_idx;
454 			else
455 				res.data.dbl *= operand.data.dbl;
456 		}
457 		else
458 		{
459 			/* catch division by 0 even if 1st operand is Unknown */
460 
461 			if (ZBX_UNKNOWN != operand.data.dbl && SUCCEED == zbx_double_compare(operand.data.dbl, 0.0))
462 			{
463 				zbx_strlcpy(buffer, "Cannot evaluate expression: division by zero.", max_buffer_len);
464 				zbx_variant_clear(&res);
465 				zbx_variant_set_dbl(&res, ZBX_INFINITY);
466 				zbx_variant_clear(&operand);
467 				return res;
468 			}
469 
470 			if (ZBX_UNKNOWN == operand.data.dbl)		/* (anything) / Unknown */
471 			{
472 				*unknown_idx = oper_idx;
473 				res_idx = oper_idx;
474 				res.data.dbl = ZBX_UNKNOWN;
475 			}
476 			else if (ZBX_UNKNOWN == res.data.dbl)		/* Unknown / known */
477 			{
478 				*unknown_idx = res_idx;
479 			}
480 			else
481 				res.data.dbl /= operand.data.dbl;
482 		}
483 
484 		zbx_variant_clear(&operand);
485 	}
486 	return res;
487 }
488 
489 /******************************************************************************
490  *                                                                            *
491  * Purpose: evaluate "+" and "-"                                              *
492  *                                                                            *
493  *     0.0 +/- Unknown  ->  Unknown                                           *
494  *     1.2 +/- Unknown  ->  Unknown                                           *
495  * Unknown +/- Unknown  ->  Unknown                                           *
496  *                                                                            *
497  ******************************************************************************/
evaluate_term5(int * unknown_idx)498 static zbx_variant_t	evaluate_term5(int *unknown_idx)
499 {
500 	char		op;
501 	zbx_variant_t	res, operand;
502 	int		res_idx = -3, oper_idx = -4;	/* set invalid values to catch errors */
503 
504 	res = evaluate_term6(&res_idx);
505 
506 	if (ZBX_VARIANT_DBL == res.type)
507 	{
508 		if (ZBX_INFINITY == res.data.dbl)
509 			return res;
510 
511 		if (ZBX_UNKNOWN == res.data.dbl)
512 			*unknown_idx = res_idx;
513 	}
514 
515 	/* if evaluate_term6() returns ZBX_UNKNOWN then continue as with regular number */
516 
517 	while ('+' == *ptr || '-' == *ptr)
518 	{
519 		variant_convert_to_double(&res);
520 
521 		if (ZBX_INFINITY == res.data.dbl)
522 			return res;
523 
524 		op = *ptr++;
525 
526 		/* even if 1st operand is Unknown we evaluate 2nd operand to catch fatal error if any occurs */
527 
528 		operand = evaluate_term6(&oper_idx);
529 		variant_convert_to_double(&operand);
530 
531 		if (ZBX_INFINITY == operand.data.dbl)
532 		{
533 			zbx_variant_clear(&res);
534 			zbx_variant_set_dbl(&res, ZBX_INFINITY);
535 			zbx_variant_clear(&operand);
536 			return res;
537 		}
538 
539 		if (ZBX_UNKNOWN == operand.data.dbl)		/* (anything) +/- Unknown */
540 		{
541 			*unknown_idx = oper_idx;
542 			res_idx = oper_idx;
543 			res.data.dbl = ZBX_UNKNOWN;
544 		}
545 		else if (ZBX_UNKNOWN == res.data.dbl)		/* Unknown +/- known */
546 		{
547 			*unknown_idx = res_idx;
548 		}
549 		else
550 		{
551 			if ('+' == op)
552 				res.data.dbl += operand.data.dbl;
553 			else
554 				res.data.dbl -= operand.data.dbl;
555 		}
556 
557 		zbx_variant_clear(&operand);
558 	}
559 
560 	return res;
561 }
562 
563 /******************************************************************************
564  *                                                                            *
565  * Purpose: evaluate "<", "<=", ">=", ">"                                     *
566  *                                                                            *
567  *     0.0 < Unknown  ->  Unknown                                             *
568  *     1.2 < Unknown  ->  Unknown                                             *
569  * Unknown < Unknown  ->  Unknown                                             *
570  *                                                                            *
571  ******************************************************************************/
evaluate_term4(int * unknown_idx)572 static zbx_variant_t	evaluate_term4(int *unknown_idx)
573 {
574 	char		op;
575 	zbx_variant_t	res, operand;
576 	int		res_idx = -5, oper_idx = -6;	/* set invalid values to catch errors */
577 
578 	res = evaluate_term5(&res_idx);
579 
580 	if (ZBX_VARIANT_DBL == res.type)
581 	{
582 		if (ZBX_INFINITY == res.data.dbl)
583 			return res;
584 
585 		if (ZBX_UNKNOWN == res.data.dbl)
586 			*unknown_idx = res_idx;
587 	}
588 
589 	/* if evaluate_term5() returns ZBX_UNKNOWN then continue as with regular number */
590 
591 	while (1)
592 	{
593 		if ('<' == ptr[0] && '=' == ptr[1])
594 		{
595 			op = 'l';
596 			ptr += 2;
597 		}
598 		else if ('>' == ptr[0] && '=' == ptr[1])
599 		{
600 			op = 'g';
601 			ptr += 2;
602 		}
603 		else if (('<' == ptr[0] && '>' != ptr[1]) || '>' == ptr[0])
604 		{
605 			op = *ptr++;
606 		}
607 		else
608 			break;
609 
610 		variant_convert_to_double(&res);
611 
612 		if (ZBX_INFINITY == res.data.dbl)
613 			return res;
614 
615 		/* even if 1st operand is Unknown we evaluate 2nd operand to catch fatal error if any occurs */
616 
617 		operand = evaluate_term5(&oper_idx);
618 
619 		variant_convert_to_double(&operand);
620 
621 		if (ZBX_INFINITY == operand.data.dbl)
622 		{
623 			zbx_variant_clear(&res);
624 			zbx_variant_set_dbl(&res, ZBX_INFINITY);
625 			zbx_variant_clear(&operand);
626 			return res;
627 		}
628 
629 		if (ZBX_UNKNOWN == operand.data.dbl)		/* (anything) < Unknown */
630 		{
631 			*unknown_idx = oper_idx;
632 			res_idx = oper_idx;
633 			res.data.dbl = ZBX_UNKNOWN;
634 		}
635 		else if (ZBX_UNKNOWN == res.data.dbl)		/* Unknown < known */
636 		{
637 			*unknown_idx = res_idx;
638 		}
639 		else
640 		{
641 			if ('<' == op)
642 				res.data.dbl = (res.data.dbl < operand.data.dbl - ZBX_DOUBLE_EPSILON);
643 			else if ('l' == op)
644 				res.data.dbl = (res.data.dbl <= operand.data.dbl + ZBX_DOUBLE_EPSILON);
645 			else if ('g' == op)
646 				res.data.dbl = (res.data.dbl >= operand.data.dbl - ZBX_DOUBLE_EPSILON);
647 			else
648 				res.data.dbl = (res.data.dbl > operand.data.dbl + ZBX_DOUBLE_EPSILON);
649 		}
650 
651 		zbx_variant_clear(&operand);
652 	}
653 
654 	return res;
655 }
656 
657 /******************************************************************************
658  *                                                                            *
659  * Purpose: evaluate "=" and "<>"                                             *
660  *                                                                            *
661  *      0.0 = Unknown  ->  Unknown                                            *
662  *      1.2 = Unknown  ->  Unknown                                            *
663  *  Unknown = Unknown  ->  Unknown                                            *
664  *     0.0 <> Unknown  ->  Unknown                                            *
665  *     1.2 <> Unknown  ->  Unknown                                            *
666  * Unknown <> Unknown  ->  Unknown                                            *
667  *                                                                            *
668  ******************************************************************************/
evaluate_term3(int * unknown_idx)669 static zbx_variant_t	evaluate_term3(int *unknown_idx)
670 {
671 	char		op;
672 	int		res_idx = -7, oper_idx = -8;	/* set invalid values to catch errors */
673 	zbx_variant_t	res, operand;
674 	double		left, right, value;
675 
676 	res = evaluate_term4(&res_idx);
677 
678 	if (ZBX_VARIANT_DBL == res.type)
679 	{
680 		if (ZBX_INFINITY == res.data.dbl)
681 			return res;
682 
683 		if (ZBX_UNKNOWN == res.data.dbl)
684 			*unknown_idx = res_idx;
685 	}
686 
687 	/* if evaluate_term4() returns ZBX_UNKNOWN then continue as with regular number */
688 
689 	while (1)
690 	{
691 		if ('=' == *ptr)
692 		{
693 			op = *ptr++;
694 		}
695 		else if ('<' == ptr[0] && '>' == ptr[1])
696 		{
697 			op = '#';
698 			ptr += 2;
699 		}
700 		else
701 			break;
702 
703 		/* even if 1st operand is Unknown we evaluate 2nd operand to catch fatal error if any occurs */
704 
705 		operand = evaluate_term4(&oper_idx);
706 
707 		if (ZBX_VARIANT_DBL == operand.type && ZBX_INFINITY == operand.data.dbl)
708 		{
709 			zbx_variant_clear(&res);
710 			return operand;
711 		}
712 
713 		if (ZBX_VARIANT_DBL == res.type && ZBX_UNKNOWN == res.data.dbl)
714 		{
715 			zbx_variant_clear(&operand);
716 			continue;
717 		}
718 
719 		if (ZBX_VARIANT_DBL == operand.type && ZBX_UNKNOWN == operand.data.dbl)
720 		{
721 			zbx_variant_clear(&res);
722 			res = operand;
723 			*unknown_idx = oper_idx;
724 			continue;
725 		}
726 
727 		left = variant_get_double(&res);
728 		right = variant_get_double(&operand);
729 
730 		if (ZBX_INFINITY != left && ZBX_INFINITY != right)
731 		{
732 			/* both operands either are of double type or could be cast to it - */
733 			/* compare them as double values                                    */
734 			value = (SUCCEED == zbx_double_compare(left, right) ? 1 : 0);
735 		}
736 		else if (ZBX_VARIANT_DBL == res.type || ZBX_VARIANT_DBL == operand.type)
737 		{
738 			/* if one of operands has double type and the other */
739 			/* cannot be cast to double - they cannot be equal  */
740 			value = 0;
741 		}
742 		else
743 		{
744 			/* at this point both operands should be strings and should be */
745 			/* compared as such but check for their types just in case     */
746 			if (ZBX_VARIANT_STR != res.type || ZBX_VARIANT_STR != operand.type)
747 			{
748 				zbx_strlcpy(buffer, "Cannot evaluate expression: unsupported value type found.",
749 						max_buffer_len);
750 				value = ZBX_INFINITY;
751 				THIS_SHOULD_NEVER_HAPPEN;
752 			}
753 			else
754 				value = !strcmp(res.data.str, operand.data.str);
755 		}
756 
757 		if ('#' == op)
758 			value = (SUCCEED == zbx_double_compare(value, 0.0) ? 1.0 : 0.0);
759 
760 		zbx_variant_clear(&res);
761 		zbx_variant_clear(&operand);
762 		zbx_variant_set_dbl(&res, value);
763 	}
764 
765 	return res;
766 }
767 
768 /******************************************************************************
769  *                                                                            *
770  * Purpose: evaluate "and"                                                    *
771  *                                                                            *
772  *      0.0 and Unknown  -> 0.0                                               *
773  *  Unknown and 0.0      -> 0.0                                               *
774  *      1.0 and Unknown  -> Unknown                                           *
775  *  Unknown and 1.0      -> Unknown                                           *
776  *  Unknown and Unknown  -> Unknown                                           *
777  *                                                                            *
778  ******************************************************************************/
evaluate_term2(int * unknown_idx)779 static zbx_variant_t	evaluate_term2(int *unknown_idx)
780 {
781 	zbx_variant_t	res, operand;
782 	int		res_idx = -9, oper_idx = -10;	/* set invalid values to catch errors */
783 
784 	res = evaluate_term3(&res_idx);
785 
786 	if (ZBX_VARIANT_DBL == res.type)
787 	{
788 		if (ZBX_INFINITY == res.data.dbl)
789 			return res;
790 
791 		if (ZBX_UNKNOWN == res.data.dbl)
792 			*unknown_idx = res_idx;
793 	}
794 
795 	/* if evaluate_term3() returns ZBX_UNKNOWN then continue as with regular number */
796 
797 	while ('a' == ptr[0] && 'n' == ptr[1] && 'd' == ptr[2] && SUCCEED == is_operator_delimiter(ptr[3]))
798 	{
799 		ptr += 3;
800 		variant_convert_to_double(&res);
801 
802 		if (ZBX_INFINITY == res.data.dbl)
803 			return res;
804 
805 		operand = evaluate_term3(&oper_idx);
806 		variant_convert_to_double(&operand);
807 
808 		if (ZBX_INFINITY == operand.data.dbl)
809 		{
810 			zbx_variant_clear(&res);
811 			zbx_variant_set_dbl(&res, ZBX_INFINITY);
812 			zbx_variant_clear(&operand);
813 			return res;
814 		}
815 
816 		if (ZBX_UNKNOWN == res.data.dbl)
817 		{
818 			if (ZBX_UNKNOWN == operand.data.dbl)				/* Unknown and Unknown */
819 			{
820 				*unknown_idx = oper_idx;
821 				res_idx = oper_idx;
822 				res.data.dbl = ZBX_UNKNOWN;
823 			}
824 			else if (SUCCEED == zbx_double_compare(operand.data.dbl, 0.0))	/* Unknown and 0 */
825 			{
826 				res.data.dbl = 0.0;
827 			}
828 			else							/* Unknown and 1 */
829 				*unknown_idx = res_idx;
830 		}
831 		else if (ZBX_UNKNOWN == operand.data.dbl)
832 		{
833 			if (SUCCEED == zbx_double_compare(res.data.dbl, 0.0))		/* 0 and Unknown */
834 			{
835 				res.data.dbl = 0.0;
836 			}
837 			else							/* 1 and Unknown */
838 			{
839 				*unknown_idx = oper_idx;
840 				res_idx = oper_idx;
841 				res.data.dbl = ZBX_UNKNOWN;
842 			}
843 		}
844 		else
845 		{
846 			res.data.dbl = (SUCCEED != zbx_double_compare(res.data.dbl, 0.0) &&
847 					SUCCEED != zbx_double_compare(operand.data.dbl, 0.0));
848 		}
849 
850 		zbx_variant_clear(&operand);
851 	}
852 
853 	return res;
854 }
855 
856 /******************************************************************************
857  *                                                                            *
858  * Purpose: evaluate "or"                                                     *
859  *                                                                            *
860  *      1.0 or Unknown  -> 1.0                                                *
861  *  Unknown or 1.0      -> 1.0                                                *
862  *      0.0 or Unknown  -> Unknown                                            *
863  *  Unknown or 0.0      -> Unknown                                            *
864  *  Unknown or Unknown  -> Unknown                                            *
865  *                                                                            *
866  ******************************************************************************/
evaluate_term1(int * unknown_idx)867 static zbx_variant_t	evaluate_term1(int *unknown_idx)
868 {
869 	int		res_idx = -11, oper_idx = -12;	/* set invalid values to catch errors */
870 	zbx_variant_t	res, operand;
871 
872 	level++;
873 
874 	if (32 < level)
875 	{
876 		zbx_strlcpy(buffer, "Cannot evaluate expression: nesting level is too deep.", max_buffer_len);
877 		zbx_variant_set_dbl(&res, ZBX_INFINITY);
878 		return res;
879 	}
880 
881 	res = evaluate_term2(&res_idx);
882 
883 	if (ZBX_VARIANT_DBL == res.type)
884 	{
885 		if (ZBX_INFINITY == res.data.dbl)
886 			return res;
887 
888 		if (ZBX_UNKNOWN == res.data.dbl)
889 			*unknown_idx = res_idx;
890 	}
891 
892 	/* if evaluate_term2() returns ZBX_UNKNOWN then continue as with regular number */
893 
894 	while ('o' == ptr[0] && 'r' == ptr[1] && SUCCEED == is_operator_delimiter(ptr[2]))
895 	{
896 		ptr += 2;
897 		variant_convert_to_double(&res);
898 
899 		if (ZBX_INFINITY == res.data.dbl)
900 			return res;
901 
902 		operand = evaluate_term2(&oper_idx);
903 
904 		variant_convert_to_double(&operand);
905 
906 		if (ZBX_INFINITY == operand.data.dbl)
907 		{
908 			zbx_variant_clear(&res);
909 			zbx_variant_set_dbl(&res, ZBX_INFINITY);
910 			zbx_variant_clear(&operand);
911 			return res;
912 		}
913 
914 		if (ZBX_UNKNOWN == res.data.dbl)
915 		{
916 			if (ZBX_UNKNOWN == operand.data.dbl)				/* Unknown or Unknown */
917 			{
918 				*unknown_idx = oper_idx;
919 				res_idx = oper_idx;
920 				res.data.dbl = ZBX_UNKNOWN;
921 			}
922 			else if (SUCCEED != zbx_double_compare(operand.data.dbl, 0.0))	/* Unknown or 1 */
923 			{
924 				res.data.dbl = 1;
925 			}
926 			else							/* Unknown or 0 */
927 				*unknown_idx = res_idx;
928 		}
929 		else if (ZBX_UNKNOWN == operand.data.dbl)
930 		{
931 			if (SUCCEED != zbx_double_compare(res.data.dbl, 0.0))		/* 1 or Unknown */
932 			{
933 				res.data.dbl = 1;
934 			}
935 			else							/* 0 or Unknown */
936 			{
937 				*unknown_idx = oper_idx;
938 				res_idx = oper_idx;
939 				res.data.dbl = ZBX_UNKNOWN;
940 			}
941 		}
942 		else
943 		{
944 			res.data.dbl = (SUCCEED != zbx_double_compare(res.data.dbl, 0.0) ||
945 					SUCCEED != zbx_double_compare(operand.data.dbl, 0.0));
946 		}
947 		zbx_variant_clear(&operand);
948 	}
949 
950 	level--;
951 
952 	return res;
953 }
954 
955 /******************************************************************************
956  *                                                                            *
957  * Purpose: evaluate an expression like "(26.416>10) or (0=1)"                *
958  *                                                                            *
959  ******************************************************************************/
evaluate(double * value,const char * expression,char * error,size_t max_error_len,zbx_vector_ptr_t * unknown_msgs)960 int	evaluate(double *value, const char *expression, char *error, size_t max_error_len,
961 		zbx_vector_ptr_t *unknown_msgs)
962 {
963 	int		unknown_idx = -13;	/* index of message in 'unknown_msgs' vector, set to invalid value */
964 						/* to catch errors */
965 	zbx_variant_t	res;
966 
967 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __func__, expression);
968 
969 	ptr = expression;
970 	level = 0;
971 	buffer = error;
972 	max_buffer_len = max_error_len;
973 	res = evaluate_term1(&unknown_idx);
974 
975 	if (ZBX_VARIANT_STR == res.type)
976 	{
977 		if (0 == strlen(res.data.str))
978 		{
979 			zbx_strlcpy(buffer, "Cannot evaluate expression: unexpected end of expression.",
980 					max_buffer_len);
981 			zbx_variant_clear(&res);
982 			zbx_variant_set_dbl(&res, ZBX_INFINITY);
983 		}
984 		else
985 		{
986 			variant_convert_to_double(&res);
987 		}
988 	}
989 
990 	*value = res.data.dbl;
991 	zbx_variant_clear(&res);
992 
993 	if ('\0' != *ptr && ZBX_INFINITY != *value)
994 	{
995 		zbx_snprintf(error, max_error_len, "Cannot evaluate expression: unexpected token at \"%s\".", ptr);
996 		*value = ZBX_INFINITY;
997 	}
998 
999 	if (ZBX_UNKNOWN == *value)
1000 	{
1001 		/* Map Unknown result to error. Callers currently do not operate with ZBX_UNKNOWN. */
1002 		if (NULL != unknown_msgs)
1003 		{
1004 			if (0 > unknown_idx)
1005 			{
1006 				THIS_SHOULD_NEVER_HAPPEN;
1007 				zabbix_log(LOG_LEVEL_WARNING, "%s() internal error: " ZBX_UNKNOWN_STR " index:%d"
1008 						" expression:'%s'", __func__, unknown_idx, expression);
1009 				zbx_snprintf(error, max_error_len, "Internal error: " ZBX_UNKNOWN_STR " index %d."
1010 						" Please report this to Zabbix developers.", unknown_idx);
1011 			}
1012 			else if (unknown_msgs->values_num > unknown_idx)
1013 			{
1014 				zbx_snprintf(error, max_error_len, "Cannot evaluate expression: \"%s\".",
1015 						(char *)(unknown_msgs->values[unknown_idx]));
1016 			}
1017 			else
1018 			{
1019 				zbx_snprintf(error, max_error_len, "Cannot evaluate expression: unsupported "
1020 						ZBX_UNKNOWN_STR "%d value.", unknown_idx);
1021 			}
1022 		}
1023 		else
1024 		{
1025 			THIS_SHOULD_NEVER_HAPPEN;
1026 			/* do not leave garbage in error buffer, write something helpful */
1027 			zbx_snprintf(error, max_error_len, "%s(): internal error: no message for unknown result",
1028 					__func__);
1029 		}
1030 
1031 		*value = ZBX_INFINITY;
1032 	}
1033 
1034 	if (ZBX_INFINITY == *value)
1035 	{
1036 		zabbix_log(LOG_LEVEL_DEBUG, "End of %s() error:'%s'", __func__, error);
1037 		return FAIL;
1038 	}
1039 
1040 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:" ZBX_FS_DBL, __func__, *value);
1041 
1042 	return SUCCEED;
1043 }
1044 
1045 /******************************************************************************
1046  *                                                                            *
1047  * Function: evaluate_unknown                                                 *
1048  *                                                                            *
1049  * Purpose: evaluate an expression like "(26.416>10) and not(0=ZBX_UNKNOWN0)" *
1050  *                                                                            *
1051  * Parameters: expression    - [IN]  expression to evaluate                   *
1052  *             value         - [OUT] expression evaluation result             *
1053  *             error         - [OUT] error message buffer                     *
1054  *             max_error_len - [IN]  error buffer size                        *
1055  *                                                                            *
1056  * Return value: SUCCEED - expression evaluated successfully,                 *
1057  *                         or evaluation result is undefined (ZBX_UNKNOWN)    *
1058  *               FAIL    - expression evaluation failed                       *
1059  *                                                                            *
1060  ******************************************************************************/
evaluate_unknown(const char * expression,double * value,char * error,size_t max_error_len)1061 int	evaluate_unknown(const char *expression, double *value, char *error, size_t max_error_len)
1062 {
1063 	const char	*__function_name = "evaluate_with_unknown";
1064 	zbx_variant_t	res;
1065 	int		unknown_idx = -13;	/* index of message in 'unknown_msgs' vector, set to invalid value */
1066 						/* to catch errors */
1067 
1068 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, expression);
1069 
1070 	ptr = expression;
1071 	level = 0;
1072 
1073 	buffer = error;
1074 	max_buffer_len = max_error_len;
1075 	res = evaluate_term1(&unknown_idx);
1076 	variant_convert_to_double(&res);
1077 	*value = res.data.dbl;
1078 	zbx_variant_clear(&res);
1079 
1080 	if ('\0' != *ptr && ZBX_INFINITY != *value)
1081 	{
1082 		zbx_snprintf(error, max_error_len, "Cannot evaluate expression: unexpected token at \"%s\".", ptr);
1083 		*value = ZBX_INFINITY;
1084 	}
1085 
1086 	if (ZBX_INFINITY == *value)
1087 	{
1088 		zabbix_log(LOG_LEVEL_DEBUG, "End of %s() error:'%s'", __function_name, error);
1089 		return FAIL;
1090 	}
1091 
1092 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:" ZBX_FS_DBL, __function_name, *value);
1093 
1094 	return SUCCEED;
1095 }
1096 
1097 /******************************************************************************
1098  *                                                                            *
1099  * Function: evaluate_string_to_double                                        *
1100  *                                                                            *
1101  * Purpose: cast string to a double, expand suffixes and parse negative sign  *
1102  *                                                                            *
1103  * Parameters: in - [IN] the input string                                     *
1104  * Return value:  -  the resulting double                                     *
1105  *                                                                            *
1106  ******************************************************************************/
evaluate_string_to_double(const char * in)1107 double	evaluate_string_to_double(const char *in)
1108 {
1109 	int		len;
1110 	double		result_double_value;
1111 	const char	*tmp_ptr = in;
1112 
1113 	if (1 < strlen(in) && '-' == in[0])
1114 		tmp_ptr++;
1115 
1116 	if (SUCCEED == zbx_suffixed_number_parse(tmp_ptr, &len) && '\0' == *(tmp_ptr + len))
1117 	{
1118 		result_double_value = atof(tmp_ptr) * suffix2factor(*(tmp_ptr + len - 1));
1119 
1120 		/* negative sign detected */
1121 		if (tmp_ptr != in)
1122 			result_double_value = -(result_double_value);
1123 	}
1124 	else
1125 	{
1126 		result_double_value = ZBX_INFINITY;
1127 	}
1128 
1129 	return result_double_value;
1130 }
1131