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-12-27-083052-3296037-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, F_1000x00019000);
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 /* Alignment note: lwc string data is always very well aligned */
203 css_code_t *codeptr = (css_code_t *)(void *)lwc_string_data(expr)({((expr != ((void*)0)) ? (void) (0) : __assert_fail ("expr != NULL"
, "src/select/calc.c", 203, __extension__ __PRETTY_FUNCTION__
)); (const char *)((expr)+1);})
;
1
Assuming 'expr' is not equal to null
2
'?' condition is true
204
205 /* Reset the stack before we begin, just in case */
206 calc->stack_ptr = 0;
207
208 /* We are trusting that the bytecode is sane */
209 while (*codeptr != CALC_FINISH) {
3
Assuming the condition is true
4
Loop condition is true. Entering loop body
210 css_code_t op = *codeptr++;
211 switch (op) {
5
Control jumps to 'case CALC_PUSH_NUMBER:' at line 223
212 case CALC_PUSH_VALUE: {
213 css_fixed v = (css_fixed)(*codeptr++);
214 unit u = (unit)(*codeptr++);
215 ret = css__normalise_unit(unit_ctx, style, available,
216 &u, &v);
217 if (ret != CSS_OK) {
218 return ret;
219 }
220 CALC_PUSH(u, v)do { ret = css__calculator_push(calc, u, v); if (ret != CSS_OK
) { return ret; } } while (0)
;
221 break;
222 }
223 case CALC_PUSH_NUMBER: {
224 css_fixed v = (css_fixed)(*codeptr++);
225 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'
226 break;
227 }
228 case CALC_ADD: /* fallthrough */
229 case CALC_SUBTRACT: {
230 unit u_left, u_right;
231 css_fixed v_left, v_right;
232 CALC_POP(u_right, v_right)do { ret = css__calculator_pop(calc, &u_right, &v_right
); if (ret != CSS_OK) { return ret; } } while (0)
;
233 CALC_POP(u_left, v_left)do { ret = css__calculator_pop(calc, &u_left, &v_left
); if (ret != CSS_OK) { return ret; } } while (0)
;
234 if (op == CALC_ADD) {
235 v_left = css_add_fixed(v_left, v_right);
236 } else {
237 v_left = css_subtract_fixed(v_left, v_right);
238 }
239 CALC_PUSH(u_left, v_left)do { ret = css__calculator_push(calc, u_left, v_left); if (ret
!= CSS_OK) { return ret; } } while (0)
;
240 break;
241 }
242 case CALC_MULTIPLY: /* fallthrough */
243 case CALC_DIVIDE: {
244 unit u_left, u_right;
245 css_fixed v_left, v_right;
246 CALC_POP(u_right, v_right)do { ret = css__calculator_pop(calc, &u_right, &v_right
); if (ret != CSS_OK) { return ret; } } while (0)
;
247 CALC_POP(u_left, v_left)do { ret = css__calculator_pop(calc, &u_left, &v_left
); if (ret != CSS_OK) { return ret; } } while (0)
;
248
249 if (op == CALC_MULTIPLY && u_left == UNIT_CALC_NUMBER) {
250 unit u_tmp = u_left;
251 css_fixed v_tmp = v_left;
252 u_left = u_right;
253 v_left = v_right;
254 u_right = u_tmp;
255 v_right = v_tmp;
256 }
257
258 if (u_right != UNIT_CALC_NUMBER) {
259 return CSS_INVALID;
260 }
261
262 if (op == CALC_MULTIPLY) {
263 v_left = css_multiply_fixed(v_left, v_right);
264 } else {
265 v_left = css_divide_fixed(v_left, v_right);
266 }
267
268 CALC_PUSH(u_left, v_left)do { ret = css__calculator_push(calc, u_left, v_left); if (ret
!= CSS_OK) { return ret; } } while (0)
;
269 break;
270 }
271 case CALC_FINISH: /* Should not happen */
272 default:
273 return CSS_INVALID;
274 }
275 }
276
277 if (calc->stack_ptr != 1) {
278 return CSS_INVALID;
279 }
280
281 *unit_out = css__to_css_unit(calc->stack[0].unit);
282 *value_out = calc->stack[0].value;
283
284 return CSS_OK;
285}