Bug Summary

File:select/calc.c
Warning:line 96, column 36
Use of memory allocated with size zero

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 calc.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -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 -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-libcss -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D _BSD_SOURCE -D _DEFAULT_SOURCE -I /var/lib/jenkins/workspace/scan-build-libcss/include/ -I /var/lib/jenkins/workspace/scan-build-libcss/src -D _ALIGNED=__attribute__((aligned)) -D STMTEXPR=1 -D DEBUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Og -Wwrite-strings -Wno-error -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-libcss -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-libcss/clangScanBuildReports/2024-05-26-194843-2628385-1 -x c src/select/calc.c
1/*
2 * This file is part of LibCSS.
3 * Licensed under the MIT License,
4 * http://www.opensource.org/licenses/mit-license.php
5 * Copyright 2024 Daniel Silverstone <dsilvers@netsurf-browser.org>
6 */
7
8#include "libcss/hint.h"
9
10#include "select/calc.h"
11#include "select/helpers.h"
12#include "select/unit.h"
13
14#include "utils/utils.h"
15
16/** The default number of entries on a calculator stack */
17#define DEFAULT_STACK_SIZE32 32
18
19#ifndef NDEBUG
20#define CANARY"A css_calculator has leaked" "A css_calculator has leaked"
21#define CANARY_SLEN(sizeof(("A css_calculator has leaked")) - 1) SLEN(CANARY)(sizeof(("A css_calculator has leaked")) - 1)
22#endif
23
24/****************************** Allocation **********************************/
25
26/* Exported function, documented in calc.h */
27css_error css_calculator_create(css_calculator **out)
28{
29 *out = calloc(1, sizeof(css_calculator));
30 if (*out == NULL((void*)0)) {
31 return CSS_NOMEM;
32 }
33
34#ifndef NDEBUG
35 if (lwc_intern_string(CANARY"A css_calculator has leaked", CANARY_SLEN(sizeof(("A css_calculator has leaked")) - 1), &((*out)->canary)) !=
36 lwc_error_ok) {
37 free(*out);
38 *out = NULL((void*)0);
39 return CSS_NOMEM;
40 }
41#endif
42
43 (*out)->stack =
44 calloc(DEFAULT_STACK_SIZE32, sizeof(css_calculator_stack_entry));
45 if ((*out)->stack == NULL((void*)0)) {
46#ifndef NDEBUG
47 lwc_string_unref((*out)->canary){ lwc_string *__lwc_s = ((*out)->canary); ((__lwc_s != ((void
*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "src/select/calc.c"
, 47, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
48#endif
49 free(*out);
50 *out = NULL((void*)0);
51 return CSS_NOMEM;
52 }
53
54 (*out)->refcount = 1;
55 (*out)->stack_alloc = DEFAULT_STACK_SIZE32;
56 (*out)->stack_ptr = 0;
57
58 return CSS_OK;
59}
60
61/* Exported function, documented in calc.h */
62css_calculator *css_calculator_ref(css_calculator *calc)
63{
64 calc->refcount += 1;
65 return calc;
66}
67
68/* Exported function, documented in calc.h */
69void css_calculator_unref(css_calculator *calc)
70{
71 calc->refcount -= 1;
72 if (calc->refcount == 0) {
73#ifndef NDEBUG
74 lwc_string_unref(calc->canary){ lwc_string *__lwc_s = (calc->canary); ((__lwc_s != ((void
*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "src/select/calc.c"
, 74, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
75#endif
76 free(calc->stack);
77 free(calc);
78 }
79}
80
81/****************************** Helpers ************************************/
82
83static css_error css__calculator_push(css_calculator *calc, unit unit,
84 css_fixed value)
85{
86 if (calc->stack_ptr == calc->stack_alloc) {
7
Assuming field 'stack_ptr' is equal to field 'stack_alloc'
8
Taking true branch
87 css_calculator_stack_entry *newstack =
88 realloc(calc->stack, sizeof(css_calculator_stack_entry) *
89 2 * calc->stack_alloc);
90 if (newstack == NULL((void*)0)) {
9
Assuming 'newstack' is not equal to NULL
10
Taking false branch
91 return CSS_NOMEM;
92 }
93 calc->stack = newstack;
94 calc->stack_alloc *= 2;
95 }
96 calc->stack[calc->stack_ptr].unit = unit;
11
Use of memory allocated with size zero
97 calc->stack[calc->stack_ptr].value = value;
98 calc->stack_ptr += 1;
99
100 return CSS_OK;
101}
102
103static css_error css__calculator_pop(css_calculator *calc, unit *unit,
104 css_fixed *value)
105{
106 if (calc->stack_ptr == 0) {
107 return CSS_INVALID;
108 }
109
110 calc->stack_ptr -= 1;
111 *unit = calc->stack[calc->stack_ptr].unit;
112 *value = calc->stack[calc->stack_ptr].value;
113
114 return CSS_OK;
115}
116
117#define CALC_PUSH(unit, value)do { ret = css__calculator_push(calc, unit, value); if (ret !=
CSS_OK) { return ret; } } while (0)
\
118 do { \
119 ret = css__calculator_push(calc, unit, value); \
120 if (ret != CSS_OK) { \
121 return ret; \
122 } \
123 } while (0)
124
125#define CALC_POP(unit, value)do { ret = css__calculator_pop(calc, &unit, &value); if
(ret != CSS_OK) { return ret; } } while (0)
\
126 do { \
127 ret = css__calculator_pop(calc, &unit, &value); \
128 if (ret != CSS_OK) { \
129 return ret; \
130 } \
131 } while (0)
132
133/* Normalise:
134 * - lengths to pixels
135 * - angles to degrees
136 * - time to ms
137 * - freq to hz
138 * - resolution to dpi
139 */
140static css_error css__normalise_unit(const css_unit_ctx *unit_ctx,
141 const css_computed_style *style,
142 int32_t available, unit *u, css_fixed *v)
143{
144 if (*u & UNIT_LENGTH) {
145 css_fixed px = css_unit_len2css_px(style, unit_ctx, *v,
146 css__to_css_unit(*u));
147 *v = px;
148 *u = UNIT_PX;
149 return CSS_OK;
150 } else if (*u & UNIT_ANGLE) {
151 css_fixed deg = css_unit_angle2deg(css__to_css_unit(*u), *v);
152 *v = deg;
153 *u = UNIT_DEG;
154 return CSS_OK;
155 } else if (*u & UNIT_TIME) {
156 if (*u == UNIT_S) {
157 *v = css_multiply_fixed(*v, INTTOFIX(1000)(css_int_to_fixed(1000)));
158 }
159 *u = UNIT_MS;
160 return CSS_OK;
161 } else if (*u & UNIT_FREQ) {
162 if (*u == UNIT_KHZ) {
163 *v = css_multiply_fixed(*v, INTTOFIX(1000)(css_int_to_fixed(1000)));
164 }
165 *u = UNIT_HZ;
166 return CSS_OK;
167 } else if (*u & UNIT_RESOLUTION) {
168 if (*u == UNIT_DPCM) {
169 *v = css_multiply_fixed(*v, FLTTOFIX(2.54)((css_fixed) ((2.54) * (float) (1 << 10))));
170 } else if (*u == UNIT_DPPX) {
171 *v = css_multiply_fixed(*v, INTTOFIX(96)(css_int_to_fixed(96)));
172 }
173 *u = UNIT_DPI;
174 return CSS_OK;
175 } else if (*u == UNIT_PCT) {
176 css_fixed pct100 = css_unit_device2css_px(INTTOFIX(available)(css_int_to_fixed(available)),
177 unit_ctx->device_dpi);
178 if (available < 0) {
179 return CSS_INVALID;
180 }
181 *v = css_multiply_fixed(*v, pct100);
182 *v = css_divide_fixed(*v, INTTOFIX(100)(css_int_to_fixed(100)));
183 *u = UNIT_PX;
184 return CSS_OK;
185 } else if (*u == UNIT_CALC_NUMBER) {
186 /* Nothing to do to normalise numbers */
187 return CSS_OK;
188 }
189 return CSS_INVALID;
190}
191
192/****************************** Compute ************************************/
193
194/* Exported function, documented in calc.h */
195css_error css_calculator_calculate(css_calculator *calc,
196 const css_unit_ctx *unit_ctx,
197 int32_t available, lwc_string *expr,
198 const css_computed_style *style,
199 css_unit *unit_out, css_fixed *value_out)
200{
201 css_error ret = CSS_OK;
202 css_code_t *codeptr = (css_code_t *)lwc_string_data(expr)({((expr != ((void*)0)) ? (void) (0) : __assert_fail ("expr != NULL"
, "src/select/calc.c", 202, __extension__ __PRETTY_FUNCTION__
)); (const char *)((expr)+1);})
;
1
Assuming 'expr' is not equal to null
2
'?' condition is true
203
204 /* Reset the stack before we begin, just in case */
205 calc->stack_ptr = 0;
206
207 /* We are trusting that the bytecode is sane */
208 while (*codeptr != CALC_FINISH) {
3
Assuming the condition is true
4
Loop condition is true. Entering loop body
209 css_code_t op = *codeptr++;
210 switch (op) {
5
Control jumps to 'case CALC_PUSH_NUMBER:' at line 222
211 case CALC_PUSH_VALUE: {
212 css_fixed v = (css_fixed)(*codeptr++);
213 unit u = (unit)(*codeptr++);
214 ret = css__normalise_unit(unit_ctx, style, available,
215 &u, &v);
216 if (ret != CSS_OK) {
217 return ret;
218 }
219 CALC_PUSH(u, v)do { ret = css__calculator_push(calc, u, v); if (ret != CSS_OK
) { return ret; } } while (0)
;
220 break;
221 }
222 case CALC_PUSH_NUMBER: {
223 css_fixed v = (css_fixed)(*codeptr++);
224 CALC_PUSH(UNIT_CALC_NUMBER, v)do { ret = css__calculator_push(calc, UNIT_CALC_NUMBER, v); if
(ret != CSS_OK) { return ret; } } while (0)
;
6
Calling 'css__calculator_push'
225 break;
226 }
227 case CALC_ADD: /* fallthrough */
228 case CALC_SUBTRACT: {
229 unit u_left, u_right;
230 css_fixed v_left, v_right;
231 CALC_POP(u_right, v_right)do { ret = css__calculator_pop(calc, &u_right, &v_right
); if (ret != CSS_OK) { return ret; } } while (0)
;
232 CALC_POP(u_left, v_left)do { ret = css__calculator_pop(calc, &u_left, &v_left
); if (ret != CSS_OK) { return ret; } } while (0)
;
233 if (op == CALC_ADD) {
234 v_left = css_add_fixed(v_left, v_right);
235 } else {
236 v_left = css_subtract_fixed(v_left, v_right);
237 }
238 CALC_PUSH(u_left, v_left)do { ret = css__calculator_push(calc, u_left, v_left); if (ret
!= CSS_OK) { return ret; } } while (0)
;
239 break;
240 }
241 case CALC_MULTIPLY: /* fallthrough */
242 case CALC_DIVIDE: {
243 unit u_left, u_right;
244 css_fixed v_left, v_right;
245 CALC_POP(u_right, v_right)do { ret = css__calculator_pop(calc, &u_right, &v_right
); if (ret != CSS_OK) { return ret; } } while (0)
;
246 CALC_POP(u_left, v_left)do { ret = css__calculator_pop(calc, &u_left, &v_left
); if (ret != CSS_OK) { return ret; } } while (0)
;
247
248 if (op == CALC_MULTIPLY && u_left == UNIT_CALC_NUMBER) {
249 unit u_tmp = u_left;
250 css_fixed v_tmp = v_left;
251 u_left = u_right;
252 v_left = v_right;
253 u_right = u_tmp;
254 v_right = v_tmp;
255 }
256
257 if (u_right != UNIT_CALC_NUMBER) {
258 return CSS_INVALID;
259 }
260
261 if (op == CALC_MULTIPLY) {
262 v_left = css_multiply_fixed(v_left, v_right);
263 } else {
264 v_left = css_divide_fixed(v_left, v_right);
265 }
266
267 CALC_PUSH(u_left, v_left)do { ret = css__calculator_push(calc, u_left, v_left); if (ret
!= CSS_OK) { return ret; } } while (0)
;
268 break;
269 }
270 case CALC_FINISH: /* Should not happen */
271 default:
272 return CSS_INVALID;
273 }
274 }
275
276 if (calc->stack_ptr != 1) {
277 return CSS_INVALID;
278 }
279
280 *unit_out = css__to_css_unit(calc->stack[0].unit);
281 *value_out = calc->stack[0].value;
282
283 return CSS_OK;
284}