Bug Summary

File:weather-iwin.c
Warning:line 385, column 18
Value stored to 'session' during its initialization is never read

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 weather-iwin.c -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 -fhalf-no-semantic-interposition -mframe-pointer=all -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=/rootdir/libcafeweather -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I .. -I . -I /usr/include/libxml2 -I /usr/include/libsoup-3.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="CafeWeather" -D CAFELOCALEDIR="/usr/share/locale" -D CAFEWEATHER_XML_LOCATION_DIR="/usr/share/libcafeweather" -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/libcafeweather -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-11-015129-15479-1 -x c weather-iwin.c
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2/* weather-iwin.c - US National Weather Service IWIN forecast source
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H1
20#include <config.h>
21#endif
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include <libxml/parser.h>
28
29#define CAFEWEATHER_I_KNOW_THIS_IS_UNSTABLE
30#include "weather.h"
31#include "weather-priv.h"
32
33/**
34 * Humans don't deal well with .MONDAY...SUNNY AND BLAH BLAH.TUESDAY...THEN THIS AND THAT.WEDNESDAY...RAINY BLAH BLAH.
35 * This function makes it easier to read.
36 */
37static gchar *
38formatWeatherMsg (gchar *forecast)
39{
40 gchar *ptr = forecast;
41 gchar *startLine = NULL((void*)0);
42
43 while (0 != *ptr) {
44 if (ptr[0] == '\n' && ptr[1] == '.') {
45 /* This removes the preamble by shifting the relevant data
46 * down to the start of the buffer. */
47 if (NULL((void*)0) == startLine) {
48 memmove (forecast, ptr, strlen (ptr) + 1);
49 ptr = forecast;
50 ptr[0] = ' ';
51 }
52 ptr[1] = '\n';
53 ptr += 2;
54 startLine = ptr;
55 } else if (ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '.' && NULL((void*)0) != startLine) {
56 memmove (startLine + 2, startLine, (ptr - startLine) * sizeof (gchar));
57 startLine[0] = ' ';
58 startLine[1] = '\n';
59 ptr[2] = '\n';
60
61 ptr += 3;
62
63 } else if (ptr[0] == '$' && ptr[1] == '$') {
64 ptr[0] = ptr[1] = ' ';
65
66 } else {
67 ptr++;
68 }
69 }
70
71 return forecast;
72}
73
74static gboolean
75hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
76{
77 xmlChar *attr;
78 gboolean res = FALSE(0);
79
80 if (!node)
81 return res;
82
83 attr = xmlGetProp (node, (const xmlChar *) attr_name);
84
85 if (!attr)
86 return res;
87
88 res = g_str_equal ((const char *)attr, attr_value)(strcmp ((const char *) ((const char *)attr), (const char *) (
attr_value)) == 0)
;
89
90 xmlFree (attr);
91
92 return res;
93}
94
95static GSList *
96parseForecastXml (const char *buff, WeatherInfo *master_info)
97{
98 GSList *res = NULL((void*)0);
99 xmlDocPtr doc;
100 xmlNode *root, *node;
101
102 g_return_val_if_fail (master_info != NULL, NULL)do { if ((master_info != ((void*)0))) { } else { g_return_if_fail_warning
("CafeWeather", ((const char*) (__func__)), "master_info != NULL"
); return (((void*)0)); } } while (0)
;
103
104 if (!buff || !*buff)
105 return NULL((void*)0);
106
107 #define XC (const xmlChar *)
108 #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)(strcmp ((const char *) ((const char *)_node->name), (const
char *) (_name)) == 0)
109
110 doc = xmlParseMemory (buff, strlen (buff));
111 if (!doc)
112 return NULL((void*)0);
113
114 /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
115 root = xmlDocGetRootElement (doc);
116 for (node = root->xmlChildrenNodechildren; node; node = node->next) {
117 if (node->name == NULL((void*)0) || node->type != XML_ELEMENT_NODE)
118 continue;
119
120 if (isElem (node, "data")) {
121 xmlNode *n;
122 char *time_layout = NULL((void*)0);
123 time_t update_times[7] = {0};
124
125 for (n = node->children; n; n = n->next) {
126 if (!n->name)
127 continue;
128
129 if (isElem (n, "time-layout")) {
130 if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
131 xmlNode *c;
132 int count = 0;
133
134 for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
135 if (c->name && !time_layout && isElem (c, "layout-key")) {
136 xmlChar *val = xmlNodeGetContent (c);
137
138 if (val) {
139 time_layout = g_strdup ((const char *)val)g_strdup_inline ((const char *)val);
140 xmlFree (val);
141 }
142 } else if (c->name && isElem (c, "start-valid-time")) {
143 xmlChar *val = xmlNodeGetContent (c);
144
145 if (val) {
146 GTimeVal tv;
147
148 if (g_time_val_from_iso8601 ((const char *)val, &tv)) {
149 update_times[count] = tv.tv_sec;
150 } else {
151 update_times[count] = 0;
152 }
153
154 count++;
155
156 xmlFree (val);
157 }
158 }
159 }
160
161 if (count != 7) {
162 /* There can be more than one time-layout element, the other
163 with only few children, which is not the one to use. */
164 g_free (time_layout);
165 time_layout = NULL((void*)0);
166 }
167 }
168 } else if (isElem (n, "parameters")) {
169 xmlNode *p;
170
171 /* time-layout should be always before parameters */
172 if (!time_layout)
173 break;
174
175 if (!res) {
176 int i;
177
178 for (i = 0; i < 7; i++) {
179 WeatherInfo *nfo = weather_info_clone (master_info);
180
181 if (nfo) {
182 nfo->valid = FALSE(0);
183 nfo->forecast_type = FORECAST_ZONE;
184 nfo->update = update_times [i];
185 nfo->sky = -1;
186 nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
187 nfo->temp = -1000.0;
188 nfo->temp_min = -1000.0;
189 nfo->temp_max = -1000.0;
190 nfo->tempMinMaxValid = FALSE(0);
191 nfo->cond.significant = FALSE(0);
192 nfo->cond.phenomenon = PHENOMENON_NONE;
193 nfo->cond.qualifier = QUALIFIER_NONE;
194 nfo->dew = -1000.0;
195 nfo->wind = -1;
196 nfo->windspeed = -1;
197 nfo->pressure = -1.0;
198 nfo->visibility = -1.0;
199 nfo->sunriseValid = FALSE(0);
200 nfo->sunsetValid = FALSE(0);
201 nfo->sunrise = 0;
202 nfo->sunset = 0;
203 g_free (nfo->forecast);
204 nfo->forecast = NULL((void*)0);
205 nfo->session = NULL((void*)0);
206 nfo->requests_pending = 0;
207 nfo->finish_cb = NULL((void*)0);
208 nfo->cb_data = NULL((void*)0);
209 res = g_slist_append (res, nfo);
210 }
211 }
212 }
213
214 for (p = n->children; p; p = p->next) {
215 if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
216 xmlNode *c;
217 GSList *at = res;
218 gboolean is_max = hasAttr (p, "type", "maximum");
219
220 if (!is_max && !hasAttr (p, "type", "minimum"))
221 break;
222
223 for (c = p->children; c && at; c = c->next) {
224 if (isElem (c, "value")) {
225 WeatherInfo *nfo = (WeatherInfo *)at->data;
226 xmlChar *val = xmlNodeGetContent (c);
227
228 /* can pass some values as <value xsi:nil="true"/> */
229 if (!val || !*val) {
230 if (is_max)
231 nfo->temp_max = nfo->temp_min;
232 else
233 nfo->temp_min = nfo->temp_max;
234 } else {
235 if (is_max)
236 nfo->temp_max = atof ((const char *)val);
237 else
238 nfo->temp_min = atof ((const char *)val);
239 }
240
241 if (val)
242 xmlFree (val);
243
244 nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
245 nfo->valid = nfo->tempMinMaxValid;
246
247 at = at->next;
248 }
249 }
250 } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
251 xmlNode *c;
252 GSList *at = res;
253
254 for (c = p->children; c && at; c = c->next) {
255 if (c->name && isElem (c, "weather-conditions")) {
256 WeatherInfo *nfo = at->data;
257 xmlChar *val = xmlGetProp (c, XC "weather-summary");
258
259 if (val && nfo) {
260 /* Checking from top to bottom, if 'value' contains 'name', then that win,
261 thus put longer (more precise) values to the top. */
262 int i;
263 struct _ph_list {
264 const char *name;
265 WeatherConditionPhenomenon ph;
266 } ph_list[] = {
267 { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
268 { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
269 { "Blowing Sand", PHENOMENON_SANDSTORM } ,
270 { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
271 { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
272 { "Drizzle", PHENOMENON_DRIZZLE } ,
273 { "Rain", PHENOMENON_RAIN } ,
274 { "Snow", PHENOMENON_SNOW } ,
275 { "Fog", PHENOMENON_FOG } ,
276 { "Smoke", PHENOMENON_SMOKE } ,
277 { "Sand", PHENOMENON_SAND } ,
278 { "Haze", PHENOMENON_HAZE } ,
279 { "Dust", PHENOMENON_DUST } /*,
280 { "", PHENOMENON_SNOW_GRAINS } ,
281 { "", PHENOMENON_ICE_PELLETS } ,
282 { "", PHENOMENON_HAIL } ,
283 { "", PHENOMENON_SMALL_HAIL } ,
284 { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
285 { "", PHENOMENON_MIST } ,
286 { "", PHENOMENON_SPRAY } ,
287 { "", PHENOMENON_SQUALL } ,
288 { "", PHENOMENON_TORNADO } ,
289 { "", PHENOMENON_DUST_WHIRLS } */
290 };
291 struct _sky_list {
292 const char *name;
293 WeatherSky sky;
294 } sky_list[] = {
295 { "Mostly Sunny", SKY_BROKEN } ,
296 { "Mostly Clear", SKY_BROKEN } ,
297 { "Partly Cloudy", SKY_SCATTERED } ,
298 { "Mostly Cloudy", SKY_FEW } ,
299 { "Sunny", SKY_CLEAR } ,
300 { "Clear", SKY_CLEAR } ,
301 { "Cloudy", SKY_OVERCAST } ,
302 { "Clouds", SKY_SCATTERED } ,
303 { "Rain", SKY_SCATTERED } ,
304 { "Snow", SKY_SCATTERED }
305 };
306
307 nfo->valid = TRUE(!(0));
308 g_free (nfo->forecast);
309 nfo->forecast = g_strdup ((const char *)val)g_strdup_inline ((const char *)val);
310
311 for (i = 0; i < G_N_ELEMENTS (ph_list)(sizeof (ph_list) / sizeof ((ph_list)[0])); i++) {
312 if (strstr ((const char *)val, ph_list [i].name)) {
313 nfo->cond.phenomenon = ph_list [i].ph;
314 break;
315 }
316 }
317
318 for (i = 0; i < G_N_ELEMENTS (sky_list)(sizeof (sky_list) / sizeof ((sky_list)[0])); i++) {
319 if (strstr ((const char *)val, sky_list [i].name)) {
320 nfo->sky = sky_list [i].sky;
321 break;
322 }
323 }
324 }
325
326 if (val)
327 xmlFree (val);
328
329 at = at->next;
330 }
331 }
332 }
333 }
334
335 if (res) {
336 gboolean have_any = FALSE(0);
337 GSList *r;
338
339 /* Remove invalid forecast data from the list.
340 They should be all valid or all invalid. */
341 for (r = res; r; r = r->next) {
342 WeatherInfo *nfo = r->data;
343
344 if (!nfo || !nfo->valid) {
345 if (r->data)
346 weather_info_free (r->data);
347
348 r->data = NULL((void*)0);
349 } else {
350 have_any = TRUE(!(0));
351
352 if (nfo->tempMinMaxValid)
353 nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
354 }
355 }
356
357 if (!have_any) {
358 /* data members are freed already */
359 g_slist_free (res);
360 res = NULL((void*)0);
361 }
362 }
363
364 break;
365 }
366 }
367
368 g_free (time_layout);
369
370 /* stop seeking XML */
371 break;
372 }
373 }
374 xmlFreeDoc (doc);
375
376 #undef XC
377 #undef isElem
378
379 return res;
380}
381
382static void
383iwin_finish (GObject *object, GAsyncResult *result, gpointer data)
384{
385 SoupSession *session = SOUP_SESSION (object);
Value stored to 'session' during its initialization is never read
386 SoupMessage *msg = soup_session_get_async_result_message (SOUP_SESSION (object), result);
387 WeatherInfo *info = (WeatherInfo *)data;
388 GBytes *response_body = NULL((void*)0);
389 const gchar *msgdata = NULL((void*)0);
390
391 g_return_if_fail (info != NULL)do { if ((info != ((void*)0))) { } else { g_return_if_fail_warning
("CafeWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
392
393response_body = soup_session_send_and_read_finish(SOUP_SESSION(object),
394 result, NULL((void*)0)/*&error*/);
395
396 if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg))((soup_message_get_status (msg)) >= 200 && (soup_message_get_status
(msg)) < 300)
) {
397 /* forecast data is not really interesting anyway ;) */
398 g_warning ("Failed to get IWIN forecast data: %d %s\n",
399 soup_message_get_status (msg), soup_message_get_reason_phrase (msg));
400 request_done (info, FALSE(0));
401 return;
402 }
403
404msgdata = g_bytes_get_data(response_body, NULL((void*)0)/*&length*/);
405
406 if (info->forecast_type == FORECAST_LIST)
407 info->forecast_list = parseForecastXml (msgdata, info);
408 else
409 info->forecast = formatWeatherMsg (g_strdup (msgdata)g_strdup_inline (msgdata));
410
411 request_done (info, TRUE(!(0)));
412}
413
414/* Get forecast into newly alloc'ed string */
415void
416iwin_start_open (WeatherInfo *info)
417{
418 gchar *url, *state, *zone;
419 WeatherLocation *loc;
420 SoupMessage *msg;
421
422 g_return_if_fail (info != NULL)do { if ((info != ((void*)0))) { } else { g_return_if_fail_warning
("CafeWeather", ((const char*) (__func__)), "info != NULL");
return; } } while (0)
;
423 loc = info->location;
424 g_return_if_fail (loc != NULL)do { if ((loc != ((void*)0))) { } else { g_return_if_fail_warning
("CafeWeather", ((const char*) (__func__)), "loc != NULL"); return
; } } while (0)
;
425
426 if (loc->zone[0] == '-' && (info->forecast_type != FORECAST_LIST || !loc->latlon_valid))
427 return;
428
429 if (info->forecast) {
430 g_free (info->forecast);
431 info->forecast = NULL((void*)0);
432 }
433
434 free_forecast_list (info);
435
436 if (info->forecast_type == FORECAST_LIST) {
437 /* see the description here: http://www.weather.gov/forecasts/xml/ */
438 if (loc->latlon_valid) {
439 struct tm tm;
440 time_t now = time (NULL((void*)0));
441
442 localtime_r (&now, &tm);
443
444 url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7",
445 RADIANS_TO_DEGREES (loc->latitude)((loc->latitude) * 180. / 3.14159265358979323846), RADIANS_TO_DEGREES (loc->longitude)((loc->longitude) * 180. / 3.14159265358979323846), 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday);
446
447 msg = soup_message_new ("GET", url);
448 g_free (url);
449 soup_session_send_and_read_async (info->session, msg, G_PRIORITY_DEFAULT0, NULL((void*)0), iwin_finish, info);
450
451 info->requests_pending++;
452 }
453
454 return;
455 }
456
457 if (loc->zone[0] == ':') {
458 /* Met Office Region Names */
459 metoffice_start_open (info);
460 return;
461 } else if (loc->zone[0] == '@') {
462 /* Australian BOM forecasts */
463 bom_start_open (info);
464 return;
465 }
466
467 /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
468 ** file (the PA stands for the state pennsylvania). The url used wants the state
469 ** as pa, and the zone as lower case paz021.
470 */
471 zone = g_ascii_strdown (loc->zone, -1);
472 state = g_strndup (zone, 2);
473
474 url = g_strdup_printf ("http://tgftp.nws.noaa.gov/data/forecasts/zone/%s/%s.txt", state, zone);
475
476 g_free (zone);
477 g_free (state);
478
479 msg = soup_message_new ("GET", url);
480 g_free (url);
481 soup_session_send_and_read_async (info->session, msg, G_PRIORITY_DEFAULT0, NULL((void*)0), iwin_finish, info);
482
483 info->requests_pending++;
484}