### Bug Summary

File: | wiretap/procmon.c
Warning: | line 720, column 32 Use of memory after it is freed

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
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 procmon.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 -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /usr/include/libxml2 -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D wiretap_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -I /builds/wireshark/wireshark/build/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-12-18-100403-3573-1 -x c /builds/wireshark/wireshark/wiretap/procmon.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /** procmon.c
2 | *
3 | * Implements reading of MS Procmon files
4 | * Used a lot of information from https://github.com/eronnen/procmon-parser
5 | *
6 | * Wiretap Library
7 | * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8 | *
9 | * SPDX-License-Identifier: GPL-2.0-or-later
10 | */
11 |
12 | #include "config.h"
13 | #define WS_LOG_DOMAIN"Wiretap" LOG_DOMAIN_WIRETAP"Wiretap"
14 |
15 | #include "procmon.h"
16 | #include "file_wrappers.h"
17 | #include "wtap_module.h"
18 | #include "pcapng_module.h"
19 |
20 | #include <wsutil/buffer.h>
21 |
22 | // To do:
23 | // - Figure out module timestamps
24 | // - Read the hosts array and pass the entries to wtap_dump_set_addrinfo_list,
25 | // similar to the pcapng parser. The diffculty here is that host entries store
26 | // their address in a 16-byte blob with no indication as to whether or not it's
27 | // an IPv4 or an IPv6 address; v4 address are just stored in the first 4 bytes.
28 | // - Read the ports array? Is there any advantage to doing that vs our built in
29 | // port number resolution?
30 |
31 | #pragma pack(push,1)
32 | typedef struct procmon_header_s {
33 | uint32_t signature; // Magic Signature - 'PML_'
34 | uint32_t version; // Version of the PML file. 9 in the current version.
35 | uint32_t system_bitness; // System bitness: 1 if the system is 64 bit, 0 otherwise.
36 | uint16_t computer_name[16]; // Name of the computer (that did the capture).
37 | uint16_t system_root_path[260]; // System root path (e.g. "C:\Windows").
38 | uint32_t num_events; // Total number of events in the log file.
39 | uint64_t unused; // ? (seems to be unused)
40 | uint64_t start_events_offset; // File offset to the start of the events array.
41 | uint64_t event_offsets_array_offset;// File offset to an array of offsets to all the events.
42 | uint64_t process_array_offset; // File offset to the array of processes.
43 | uint64_t string_array_offset; // File offset to the array of strings.
44 | uint64_t icon_array_offset; // File offset to the icons array.
45 | uint64_t maximum_user_address; // SYSTEM_INFO.lpMaximumApplicationAddress: Maximum User Address
46 | uint32_t os_version_info_size; // OSVERSIONINFOEXW.dwOSVersionInfoSize: sizeof(OSVERSIONINFOEXW)
47 | uint32_t major_version; // OSVERSIONINFOEXW.dwMajorVersion: Major version number of the operating system.
48 | uint32_t minor_version; // OSVERSIONINFOEXW.dwMinorVersion: Minor version number of the operating system.
49 | uint32_t build_number; // OSVERSIONINFOEXW.dwBuildNumber: Build number of the operating system.
50 | uint32_t platform_id; // OSVERSIONINFOEXW.dwPlatformId: Operating system platform.
51 | uint16_t csd_version[128]; // OSVERSIONINFOEXW.szCSDVersion: Indicates the latest Service Pack installed.
52 | uint16_t service_pack_major; // OSVERSIONINFOEXW.wServicePackMajor: Major version number of the latest Service Pack.
53 | uint16_t service_pack_minor; // OSVERSIONINFOEXW.wServicePackMinor: Minor version number of the latest Service Pack.
54 | uint16_t suite_mask; // OSVERSIONINFOEXW.wSuiteMask: Bit mask that identifies the product suites available.
55 | uint8_t product_type; // OSVERSIONINFOEXW.wProductType: Additional information about the system.
56 | uint8_t version_reserved; // OSVERSIONINFOEXW.wReserved: Reserved for future use.
57 | uint32_t num_processors; // SYSTEM_INFO.dwNumberOfProcessors: Number of logical processors.
58 | uint64_t total_physical_memory; // MEMORYSTATUSEX.ullTotalPhys: Total physical memory (in bytes).
59 | uint64_t start_events_offset_dup; // File offset to the start of the events array (again).
60 | uint64_t host_port_array_offset; // File offset to hosts and ports arrays.
61 | } procmon_header_t;
62 |
63 | typedef enum {
64 | PROCMON_EVENT_TYPE_UNKNOWN = 0,
65 | PROCMON_EVENT_TYPE_PROCESS = 1,
66 | PROCMON_EVENT_TYPE_REGISTRY = 2,
67 | PROCMON_EVENT_TYPE_FILE_SYSTEM = 3,
68 | PROCMON_EVENT_TYPE_PROFILING = 4,
69 | PROCMON_EVENT_TYPE_NETWORK = 5,
70 | } procmon_event_class_type_t;
71 |
72 | typedef struct procmon_event_header_s {
73 | uint32_t process_index; // The index to the process of the event.
74 | uint32_t thread_id; // Thread Id.
75 | uint32_t event_class; // Event class (of type procmon_event_class_type_t)
76 | uint16_t operation_type; // Operation type (dependent on the event class)
77 | uint8_t unknown[6]; // Unknown
78 | uint64_t duration; // Duration of the operation in 100 nanoseconds interval.
79 | uint64_t timestamp; // The time when the event was captured (in FILETIME format)
80 | uint32_t event_result; // The value of the event result.
81 | uint16_t stack_trace_depth; // The depth of the captured stack trace.
82 | uint16_t unknown3; // Unknown
83 | uint32_t details_size; // The size of the specific detail structure (contains path and other details)
84 | uint32_t extra_details_offset; // The offset from the start of the event to extra detail structure (not necessarily continuous with this structure).
85 |
86 | } procmon_event_header_t;
87 | #pragma pack(pop)
88 |
89 | typedef struct {
90 | uint32_t process_index;
91 | uint32_t process_id;
92 | uint32_t parent_process_id;
93 | uint32_t parent_process_index;
94 | uint64_t authentication_id;
95 | uint32_t session_number;
96 | uint32_t unknown1;
97 | uint64_t start_time; // FILETIME
98 | uint64_t end_time; // FILETIME
99 | uint32_t is_virtualized;
100 | uint32_t is_64_bit;
101 | uint32_t integrity_si;
102 | uint32_t user_name_si;
103 | uint32_t process_name_si;
104 | uint32_t image_path_si;
105 | uint32_t command_line_si;
106 | uint32_t company_si;
107 | uint32_t version_si;
108 | uint32_t description_si;
109 | uint32_t icon_index_big;
110 | uint32_t icon_index_small;
111 | } procmon_raw_process_t;
112 |
113 | typedef struct {
114 | uint32_t unknown1;
115 | uint32_t base_address;
116 | uint32_t size;
117 | uint32_t image_path_si;
118 | uint32_t version_si;
119 | uint32_t company_si;
120 | uint32_t description_si;
121 | uint32_t timestamp;
122 | uint64_t unknown2[3];
123 | } procmon_raw_module_32_t;
124 |
125 | typedef struct {
126 | uint64_t unknown1;
127 | uint64_t base_address;
128 | uint32_t size;
129 | uint32_t image_path_si;
130 | uint32_t version_si;
131 | uint32_t company_si;
132 | uint32_t description_si;
133 | uint32_t timestamp;
134 | uint64_t unknown2[3];
135 | } procmon_raw_module_64_t;
136 |
137 | typedef struct {
138 | procmon_header_t header;
139 | uint32_t *event_offsets;
140 | uint32_t cur_event;
141 | const char **string_array;
142 | size_t string_array_size;
143 | uint32_t *process_index_map; /* Map of process index to process array index */
144 | size_t process_index_map_size;/* Size of the process index map */
145 | struct procmon_process_t *process_array; /* Array of processes */
146 | size_t process_array_size; /* Size of the process array */
147 | } procmon_file_info_t;
148 |
149 | #define COMMON_EVENT_STRUCT_SIZE52 52
150 | // Most of these are arbitrary
151 | #define MAX_PROCMON_EVENTS(500 * 1000 * 1000) (500 * 1000 * 1000)
152 | #define MAX_PROCMON_STRINGS(1000 * 1000) (1000 * 1000)
153 | #define MAX_PROCMON_STRING_LENGTH8192 8192
154 | #define MAX_PROCMON_PROCESSES(500 * 1000) (500 * 1000)
155 | #define MAX_PROCMON_MODULES1000 1000
156 |
157 | static int procmon_file_type_subtype = -1;
158 |
159 | void register_procmon(void);
160 |
161 | static void file_info_cleanup(procmon_file_info_t* file_info)
162 | {
163 | g_free(file_info->event_offsets);
164 | g_free(file_info->string_array);
165 | g_free(file_info->process_index_map);
166 | if (file_info->process_array
81.1 | Field 'process_array' is non-null
) {
82 | ← | Taking true branch | →
167 | for (size_t idx = 0; idx < file_info->process_array_size; idx++) {
83 | ← | Loop condition is true. Entering loop body | →
84 | ← | Loop condition is false. Execution continues on line 170 | →
168 | g_free(file_info->process_array[idx].modules);
169 | }
170 | g_free(file_info->process_array);
85 | ← | Memory is released | →
171 | }
172 | g_free(file_info);
173 | }
174 |
175 | static const char *procmon_string(procmon_file_info_t* file_info, uint32_t str_index)
176 | {
177 | if (str_index >= file_info->string_array_size) {
178 | return "<unknown>";
179 | }
180 | return file_info->string_array[str_index];
181 | }
182 |
183 | static bool_Bool procmon_read_event(FILE_T fh, wtap_rec* rec, procmon_file_info_t* file_info, int* err, char** err_info)
184 | {
185 | wtapng_block_t wblock;
186 | procmon_event_header_t event_header;
187 |
188 | wblock.rec = rec;
189 |
190 | wblock.block = wtap_block_create(WTAP_BLOCK_FT_SPECIFIC_EVENT);
191 |
192 | wblock.rec->presence_flags = WTAP_HAS_CAP_LEN0x00000002;
193 | wblock.rec->tsprec = WTAP_TSPREC_NSEC9;
194 |
195 | /* Read the event header */
196 | if (!wtap_read_bytes(fh, &event_header, sizeof event_header, err, err_info)) {
197 | ws_debug("Failed to read procmon process index")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 197, __func__, "Failed to read procmon process index"); } } while (0);
198 | return false0;
199 | }
200 |
201 | /* Append the raw data of the event header */
202 | ws_buffer_append(&wblock.rec->data, (const uint8_t*)&event_header, sizeof event_header);
203 |
204 | wblock.rec->presence_flags |= WTAP_HAS_TS0x00000001;
205 | filetime_to_nstime(&wblock.rec->ts, GUINT64_FROM_LE(event_header.timestamp)(((guint64) (event_header.timestamp))));
206 |
207 | /* Read stack trace data */
208 | uint32_t sizeof_stacktrace = event_header.stack_trace_depth * (file_info->header.system_bitness ? 8 : 4);
209 |
210 | /* Append the size of the stack trace data so the dissector doesn't need to know about system bitness */
211 | ws_buffer_append(&wblock.rec->data, (const uint8_t*)&sizeof_stacktrace, sizeof sizeof_stacktrace);
212 |
213 | if (!wtap_read_bytes_buffer(fh, &wblock.rec->data, sizeof_stacktrace, err, err_info)) {
214 | ws_debug("Failed to read procmon stack trace data")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 214, __func__, "Failed to read procmon stack trace data"); } } while (0);
215 | return false0;
216 | }
217 |
218 | /* Read detail data */
219 | if (!wtap_read_bytes_buffer(fh, &wblock.rec->data, event_header.details_size, err, err_info)) {
220 | ws_debug("Failed to read procmon detail data")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 220, __func__, "Failed to read procmon detail data"); } } while (0);
221 | return false0;
222 | }
223 |
224 | if (event_header.extra_details_offset > 0)
225 | {
226 | int64_t current_offset = file_tell(fh);
227 |
228 | /* The extra details structure surprisingly can be separated from the event structure */
229 | int64_t real_details_offset = event_header.extra_details_offset - (COMMON_EVENT_STRUCT_SIZE52 + event_header.details_size + sizeof_stacktrace);
230 | if (file_seek(fh, real_details_offset, SEEK_CUR1, err) == -1) {
231 | ws_debug("Failed to locate procmon extra details data")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 231, __func__, "Failed to locate procmon extra details data" ); } } while (0);
232 | return false0;
233 | }
234 | /* However, pass the record data up as if it's consecutive */
235 | uint16_t extra_details_stream_size;
236 | if (!wtap_read_bytes(fh, &extra_details_stream_size, sizeof extra_details_stream_size, err, err_info)) {
237 | ws_debug("Failed to read procmon extra details offset")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 237, __func__, "Failed to read procmon extra details offset" ); } } while (0);
238 | return false0;
239 | }
240 | ws_buffer_append(&wblock.rec->data, (const uint8_t*)&extra_details_stream_size, sizeof extra_details_stream_size);
241 |
242 | if (!wtap_read_bytes_buffer(fh, &wblock.rec->data, extra_details_stream_size, err, err_info)) {
243 | ws_debug("Failed to read procmon extra detail data")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 243, __func__, "Failed to read procmon extra detail data"); } } while (0);
244 | return false0;
245 | }
246 |
247 | /* If the extra data doesn't immediately follow the other data */
248 | if (real_details_offset != 0)
249 | {
250 | if (file_seek(fh, current_offset, SEEK_SET0, err) == -1) {
251 | ws_debug("Failed to restore procmon event data location")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 251, __func__, "Failed to restore procmon event data location" ); } } while (0);
252 | return false0;
253 | }
254 | }
255 | }
256 |
257 | /*
258 | * We return these to the caller in procmon_read().
259 | */
260 | wtap_setup_ft_specific_event_rec(wblock.rec, procmon_file_type_subtype, event_header.event_class);
261 | wblock.rec->rec_header.ft_specific_header.record_len = (uint32_t)ws_buffer_length(&wblock.rec->data);
262 | wblock.rec->rec_header.ft_specific_header.pseudo_header.procmon.process_index_map = file_info->process_index_map;
263 | wblock.rec->rec_header.ft_specific_header.pseudo_header.procmon.process_index_map_size = file_info->process_index_map_size;
264 | wblock.rec->rec_header.ft_specific_header.pseudo_header.procmon.process_array = file_info->process_array;
265 | wblock.rec->rec_header.ft_specific_header.pseudo_header.procmon.process_array_size = file_info->process_array_size;
266 | wblock.rec->rec_header.ft_specific_header.pseudo_header.procmon.system_bitness = (file_info->header.system_bitness != 0);
267 | wblock.internal = false0;
268 |
269 | /*
270 | * We want dissectors (particularly packet_frame) to be able to
271 | * access packet comments and whatnot that are in the block. wblock->block
272 | * will be unref'd by procmon_seek_read(), so move the block to where
273 | * dissectors can find it.
274 | */
275 | wblock.rec->block = wblock.block;
276 | wblock.block = NULL((void*)0);
277 | return true1;
278 | }
279 |
280 | static bool_Bool procmon_read(wtap *wth, wtap_rec *rec,
281 | int *err, char **err_info, int64_t *data_offset)
282 | {
283 | procmon_file_info_t* file_info = (procmon_file_info_t*)wth->priv;
284 |
285 | *data_offset = file_info->event_offsets[file_info->cur_event];
286 | ws_noisy("file offset is %" PRId64 " array offset is %" PRId64, file_tell(wth->fh), *data_offset)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_NOISY, "wiretap/procmon.c" , 286, __func__, "file offset is %" "l" "d" " array offset is %" "l" "d", file_tell(wth->fh), *data_offset); } } while (0);
287 |
288 | if (file_seek(wth->fh, *data_offset, SEEK_SET0, err) == -1)
289 | {
290 | ws_debug("Failed to seek to event %u at offsets %" PRId64, file_info->cur_event, *data_offset)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 290, __func__, "Failed to seek to event %u at offsets %" "l" "d", file_info->cur_event, *data_offset); } } while (0);
291 | return false0;
292 | }
293 |
294 | /* Stop processing once offset reaches past events */
295 | if (file_info->cur_event >= file_info->header.num_events)
296 | {
297 | ws_debug("end of events")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 297, __func__, "end of events"); } } while (0);
298 | return false0;
299 | }
300 | file_info->cur_event++;
301 |
302 | // if (*data_offset+COMMON_EVENT_STRUCT_SIZE >= (int64_t)file_info->header.event_offsets_array_offset) {
303 | // *err = WTAP_ERR_BAD_FILE;
304 | // *err_info = ws_strdup_printf("procmon: Not enough room for event content at offset %" PRIi64, *data_offset);
305 | // return false;
306 | // }
307 |
308 | return procmon_read_event(wth->fh, rec, file_info, err, err_info);
309 | }
310 |
311 | static bool_Bool procmon_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
312 | int *err, char **err_info)
313 | {
314 | procmon_file_info_t* file_info = (procmon_file_info_t*)wth->priv;
315 |
316 | /* seek to the right file position */
317 | if (file_seek(wth->random_fh, seek_off, SEEK_SET0, err) < 0) {
318 | return false0; /* Seek error */
319 | }
320 | ws_noisy("reading at offset %" PRIu64, seek_off)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_NOISY, "wiretap/procmon.c" , 320, __func__, "reading at offset %" "l" "u", seek_off); } } while (0);
321 |
322 | return procmon_read_event(wth->random_fh, rec, file_info, err, err_info);
323 | }
324 |
325 | static const uint8_t procmon_magic[] = { 'P', 'M', 'L', '_' };
326 |
327 | wtap_open_return_val procmon_open(wtap *wth, int *err _U___attribute__((unused)), char **err_info _U___attribute__((unused)))
328 | {
329 | procmon_file_info_t* file_info = g_new0(procmon_file_info_t, 1)((procmon_file_info_t *) g_malloc0_n ((1), sizeof (procmon_file_info_t )));
330 | procmon_header_t* header = &file_info->header;
331 |
332 | ws_debug("opening file")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 332, __func__, "opening file"); } } while (0);
1 | Taking true branch | →
2 | ← | Loop condition is false. Exiting loop | →
333 | /*
334 | * First, try to read the procmon header.
335 | */
336 | if (!wtap_read_bytes_or_eof(wth->fh, header, sizeof(procmon_header_t), err, err_info))
3 | ← | Assuming the condition is false | →
4 | ← | Taking false branch | →
337 | {
338 | file_info_cleanup(file_info);
339 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 339, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
340 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12) {
341 | /*
342 | * Short read or EOF.
343 | *
344 | * We're reading this as part of an open, so
345 | * the file is too short to be a procmon file.
346 | */
347 | *err = 0;
348 | g_free(*err_info);
349 | *err_info = NULL((void*)0);
350 | }
351 | return WTAP_OPEN_NOT_MINE;
352 | }
353 |
354 | if (memcmp(&header->signature, procmon_magic, sizeof(procmon_magic)))
5 | ← | Assuming the condition is false | →
6 | ← | Taking false branch | →
355 | {
356 | file_info_cleanup(file_info);
357 | return WTAP_OPEN_NOT_MINE;
358 | }
359 |
360 | #if G_BYTE_ORDER1234 == G_BIG_ENDIAN4321
361 | header->version = GUINT32_SWAP_LE_BE(header->version)(((guint32) ( (((guint32) (header->version) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (header->version ) & (guint32) 0x0000ff00U) << 8) | (((guint32) (header ->version) & (guint32) 0x00ff0000U) >> 8) | (((guint32 ) (header->version) & (guint32) 0xff000000U) >> 24 ))));
362 | header->system_bitness = GUINT32_SWAP_LE_BE(header->system_bitness)(((guint32) ( (((guint32) (header->system_bitness) & ( guint32) 0x000000ffU) << 24) | (((guint32) (header-> system_bitness) & (guint32) 0x0000ff00U) << 8) | (( (guint32) (header->system_bitness) & (guint32) 0x00ff0000U ) >> 8) | (((guint32) (header->system_bitness) & (guint32) 0xff000000U) >> 24))));
363 | header->num_events = GUINT32_SWAP_LE_BE(header->num_events)(((guint32) ( (((guint32) (header->num_events) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (header->num_events ) & (guint32) 0x0000ff00U) << 8) | (((guint32) (header ->num_events) & (guint32) 0x00ff0000U) >> 8) | ( ((guint32) (header->num_events) & (guint32) 0xff000000U ) >> 24))));
364 | header->start_events_offset = GUINT64_SWAP_LE_BE(header->start_events_offset)(((guint64) ( (((guint64) (header->start_events_offset) & (guint64) (0x00000000000000ffUL)) << 56) | (((guint64) (header->start_events_offset) & (guint64) (0x000000000000ff00UL )) << 40) | (((guint64) (header->start_events_offset ) & (guint64) (0x0000000000ff0000UL)) << 24) | (((guint64 ) (header->start_events_offset) & (guint64) (0x00000000ff000000UL )) << 8) | (((guint64) (header->start_events_offset) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64 ) (header->start_events_offset) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (header->start_events_offset ) & (guint64) (0x00ff000000000000UL)) >> 40) | (((guint64 ) (header->start_events_offset) & (guint64) (0xff00000000000000UL )) >> 56))));
365 | header->event_offsets_array_offset = GUINT64_SWAP_LE_BE(header->event_offsets_array_offset)(((guint64) ( (((guint64) (header->event_offsets_array_offset ) & (guint64) (0x00000000000000ffUL)) << 56) | (((guint64 ) (header->event_offsets_array_offset) & (guint64) (0x000000000000ff00UL )) << 40) | (((guint64) (header->event_offsets_array_offset ) & (guint64) (0x0000000000ff0000UL)) << 24) | (((guint64 ) (header->event_offsets_array_offset) & (guint64) (0x00000000ff000000UL )) << 8) | (((guint64) (header->event_offsets_array_offset ) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64 ) (header->event_offsets_array_offset) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (header->event_offsets_array_offset ) & (guint64) (0x00ff000000000000UL)) >> 40) | (((guint64 ) (header->event_offsets_array_offset) & (guint64) (0xff00000000000000UL )) >> 56))));
366 | header->process_array_offset = GUINT64_SWAP_LE_BE(header->process_array_offset)(((guint64) ( (((guint64) (header->process_array_offset) & (guint64) (0x00000000000000ffUL)) << 56) | (((guint64) (header->process_array_offset) & (guint64) (0x000000000000ff00UL )) << 40) | (((guint64) (header->process_array_offset ) & (guint64) (0x0000000000ff0000UL)) << 24) | (((guint64 ) (header->process_array_offset) & (guint64) (0x00000000ff000000UL )) << 8) | (((guint64) (header->process_array_offset ) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64 ) (header->process_array_offset) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (header->process_array_offset ) & (guint64) (0x00ff000000000000UL)) >> 40) | (((guint64 ) (header->process_array_offset) & (guint64) (0xff00000000000000UL )) >> 56))));
367 | header->string_array_offset = GUINT64_SWAP_LE_BE(header->string_array_offset)(((guint64) ( (((guint64) (header->string_array_offset) & (guint64) (0x00000000000000ffUL)) << 56) | (((guint64) (header->string_array_offset) & (guint64) (0x000000000000ff00UL )) << 40) | (((guint64) (header->string_array_offset ) & (guint64) (0x0000000000ff0000UL)) << 24) | (((guint64 ) (header->string_array_offset) & (guint64) (0x00000000ff000000UL )) << 8) | (((guint64) (header->string_array_offset) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64 ) (header->string_array_offset) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (header->string_array_offset ) & (guint64) (0x00ff000000000000UL)) >> 40) | (((guint64 ) (header->string_array_offset) & (guint64) (0xff00000000000000UL )) >> 56))));
368 | header->icon_array_offset = GUINT64_SWAP_LE_BE(header->icon_array_offset)(((guint64) ( (((guint64) (header->icon_array_offset) & (guint64) (0x00000000000000ffUL)) << 56) | (((guint64) (header->icon_array_offset) & (guint64) (0x000000000000ff00UL )) << 40) | (((guint64) (header->icon_array_offset) & (guint64) (0x0000000000ff0000UL)) << 24) | (((guint64) (header->icon_array_offset) & (guint64) (0x00000000ff000000UL )) << 8) | (((guint64) (header->icon_array_offset) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64) ( header->icon_array_offset) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (header->icon_array_offset) & (guint64) (0x00ff000000000000UL)) >> 40) | (((guint64) (header->icon_array_offset) & (guint64) (0xff00000000000000UL )) >> 56))));
369 | header->maximum_user_address = GUINT64_SWAP_LE_BE(header->maximum_user_address)(((guint64) ( (((guint64) (header->maximum_user_address) & (guint64) (0x00000000000000ffUL)) << 56) | (((guint64) (header->maximum_user_address) & (guint64) (0x000000000000ff00UL )) << 40) | (((guint64) (header->maximum_user_address ) & (guint64) (0x0000000000ff0000UL)) << 24) | (((guint64 ) (header->maximum_user_address) & (guint64) (0x00000000ff000000UL )) << 8) | (((guint64) (header->maximum_user_address ) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64 ) (header->maximum_user_address) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (header->maximum_user_address ) & (guint64) (0x00ff000000000000UL)) >> 40) | (((guint64 ) (header->maximum_user_address) & (guint64) (0xff00000000000000UL )) >> 56))));
370 | header->os_version_info_size = GUINT32_SWAP_LE_BE(header->os_version_info_size)(((guint32) ( (((guint32) (header->os_version_info_size) & (guint32) 0x000000ffU) << 24) | (((guint32) (header-> os_version_info_size) & (guint32) 0x0000ff00U) << 8 ) | (((guint32) (header->os_version_info_size) & (guint32 ) 0x00ff0000U) >> 8) | (((guint32) (header->os_version_info_size ) & (guint32) 0xff000000U) >> 24))));
371 | header->major_version = GUINT32_SWAP_LE_BE(header->major_version)(((guint32) ( (((guint32) (header->major_version) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (header->major_version ) & (guint32) 0x0000ff00U) << 8) | (((guint32) (header ->major_version) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (header->major_version) & (guint32) 0xff000000U ) >> 24))));
372 | header->minor_version = GUINT32_SWAP_LE_BE(header->minor_version)(((guint32) ( (((guint32) (header->minor_version) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (header->minor_version ) & (guint32) 0x0000ff00U) << 8) | (((guint32) (header ->minor_version) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (header->minor_version) & (guint32) 0xff000000U ) >> 24))));
373 | header->build_number = GUINT32_SWAP_LE_BE(header->build_number)(((guint32) ( (((guint32) (header->build_number) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (header->build_number ) & (guint32) 0x0000ff00U) << 8) | (((guint32) (header ->build_number) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (header->build_number) & (guint32) 0xff000000U ) >> 24))));
374 | header->platform_id = GUINT32_SWAP_LE_BE(header->platform_id)(((guint32) ( (((guint32) (header->platform_id) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (header->platform_id ) & (guint32) 0x0000ff00U) << 8) | (((guint32) (header ->platform_id) & (guint32) 0x00ff0000U) >> 8) | ( ((guint32) (header->platform_id) & (guint32) 0xff000000U ) >> 24))));
375 | header->service_pack_major = GUINT16_SWAP_LE_BE(header->service_pack_major)(((guint16) ( (guint16) ((guint16) (header->service_pack_major ) >> 8) | (guint16) ((guint16) (header->service_pack_major ) << 8))));
376 | header->service_pack_minor = GUINT16_SWAP_LE_BE(header->service_pack_minor)(((guint16) ( (guint16) ((guint16) (header->service_pack_minor ) >> 8) | (guint16) ((guint16) (header->service_pack_minor ) << 8))));
377 | header->suite_mask = GUINT16_SWAP_LE_BE(header->suite_mask)(((guint16) ( (guint16) ((guint16) (header->suite_mask) >> 8) | (guint16) ((guint16) (header->suite_mask) << 8 ))));
378 | header->num_processors = GUINT32_SWAP_LE_BE(header->num_processors)(((guint32) ( (((guint32) (header->num_processors) & ( guint32) 0x000000ffU) << 24) | (((guint32) (header-> num_processors) & (guint32) 0x0000ff00U) << 8) | (( (guint32) (header->num_processors) & (guint32) 0x00ff0000U ) >> 8) | (((guint32) (header->num_processors) & (guint32) 0xff000000U) >> 24))));
379 | header->total_physical_memory = GUINT64_SWAP_LE_BE(header->total_physical_memory)(((guint64) ( (((guint64) (header->total_physical_memory) & (guint64) (0x00000000000000ffUL)) << 56) | (((guint64) (header->total_physical_memory) & (guint64) (0x000000000000ff00UL )) << 40) | (((guint64) (header->total_physical_memory ) & (guint64) (0x0000000000ff0000UL)) << 24) | (((guint64 ) (header->total_physical_memory) & (guint64) (0x00000000ff000000UL )) << 8) | (((guint64) (header->total_physical_memory ) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64 ) (header->total_physical_memory) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (header->total_physical_memory ) & (guint64) (0x00ff000000000000UL)) >> 40) | (((guint64 ) (header->total_physical_memory) & (guint64) (0xff00000000000000UL )) >> 56))));
380 | header->start_events_offset_dup = GUINT64_SWAP_LE_BE(header->start_events_offset_dup)(((guint64) ( (((guint64) (header->start_events_offset_dup ) & (guint64) (0x00000000000000ffUL)) << 56) | (((guint64 ) (header->start_events_offset_dup) & (guint64) (0x000000000000ff00UL )) << 40) | (((guint64) (header->start_events_offset_dup ) & (guint64) (0x0000000000ff0000UL)) << 24) | (((guint64 ) (header->start_events_offset_dup) & (guint64) (0x00000000ff000000UL )) << 8) | (((guint64) (header->start_events_offset_dup ) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64 ) (header->start_events_offset_dup) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (header->start_events_offset_dup ) & (guint64) (0x00ff000000000000UL)) >> 40) | (((guint64 ) (header->start_events_offset_dup) & (guint64) (0xff00000000000000UL )) >> 56))));
381 | header->host_port_array_offset = GUINT64_SWAP_LE_BE(header->host_port_array_offset)(((guint64) ( (((guint64) (header->host_port_array_offset) & (guint64) (0x00000000000000ffUL)) << 56) | (((guint64 ) (header->host_port_array_offset) & (guint64) (0x000000000000ff00UL )) << 40) | (((guint64) (header->host_port_array_offset ) & (guint64) (0x0000000000ff0000UL)) << 24) | (((guint64 ) (header->host_port_array_offset) & (guint64) (0x00000000ff000000UL )) << 8) | (((guint64) (header->host_port_array_offset ) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64 ) (header->host_port_array_offset) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (header->host_port_array_offset ) & (guint64) (0x00ff000000000000UL)) >> 40) | (((guint64 ) (header->host_port_array_offset) & (guint64) (0xff00000000000000UL )) >> 56))));
382 | #endif
383 |
384 | if (header->num_events > MAX_PROCMON_EVENTS(500 * 1000 * 1000)) {
7 | ← | Assuming the condition is false | →
8 | ← | Taking false branch | →
385 | ws_debug("Truncating events from %u to %u", header->num_events, MAX_PROCMON_EVENTS)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 385, __func__, "Truncating events from %u to %u", header-> num_events, (500 * 1000 * 1000)); } } while (0);
386 | header->num_events = MAX_PROCMON_EVENTS(500 * 1000 * 1000);
387 | }
388 |
389 | // Read the event offsets array, which we use in procmon_read(). It's not clear
390 | // if we really need this; in a test capture here the offsets in the array were
391 | // identical to the file positions we end up with if we just read sequentially.
392 | if (file_seek(wth->fh, header->event_offsets_array_offset, SEEK_SET0, err) == -1)
9 | ← | Assuming the condition is false | →
10 | ← | Taking false branch | →
393 | {
394 | file_info_cleanup(file_info);
395 | ws_debug("Failed to locate event offsets data")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 395, __func__, "Failed to locate event offsets data"); } } while (0);
396 | return WTAP_OPEN_NOT_MINE;
397 | }
398 | file_info->event_offsets = g_new(uint32_t, header->num_events)((uint32_t *) g_malloc_n ((header->num_events), sizeof (uint32_t )));
399 | for (unsigned idx = 0; idx
10.1 | 'idx' is < field 'num_events'
< header->num_events; idx++) {
11 | ← | Loop condition is true. Entering loop body | →
16 | ← | Assuming 'idx' is >= field 'num_events' | →
17 | ← | Loop condition is false. Execution continues on line 424 | →
400 | uint32_t event_offset;
401 | // Each offset entry is a uint32_t offset followed by a uint8_t maybe-flags
402 | if (!wtap_read_bytes_or_eof(wth->fh, &event_offset, sizeof(event_offset), err, err_info))
12 | ← | Assuming the condition is false | →
13 | ← | Taking false branch | →
403 | {
404 | file_info_cleanup(file_info);
405 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 405, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
406 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
407 | {
408 | // Short read or EOF.
409 | *err = 0;
410 | g_free(*err_info);
411 | *err_info = NULL((void*)0);
412 | }
413 | return WTAP_OPEN_NOT_MINE;
414 | }
415 | if (file_seek(wth->fh, 1, SEEK_CUR1, err) == -1)
14 | ← | Assuming the condition is false | →
15 | ← | Taking false branch | →
416 | {
417 | file_info_cleanup(file_info);
418 | ws_debug("Failed to skip flags")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 418, __func__, "Failed to skip flags"); } } while (0);
419 | return WTAP_OPEN_NOT_MINE;
420 | }
421 | file_info->event_offsets[idx] = GUINT32_FROM_LE(event_offset)(((guint32) (event_offset)));
422 | }
423 |
424 | if (file_seek(wth->fh, header->string_array_offset, SEEK_SET0, err) == -1)
18 | ← | Assuming the condition is false | →
19 | ← | Taking false branch | →
425 | {
426 | ws_debug("Failed to locate procmon string data")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 426, __func__, "Failed to locate procmon string data"); } } while (0);
427 | return WTAP_OPEN_NOT_MINE;
428 | }
429 |
430 | uint32_t num_strings;
431 | if (!wtap_read_bytes_or_eof(wth->fh, &num_strings, sizeof(num_strings), err, err_info))
20 | ← | Assuming the condition is false | →
21 | ← | Taking false branch | →
432 | {
433 | file_info_cleanup(file_info);
434 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 434, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
435 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
436 | {
437 | // Short read or EOF.
438 | *err = 0;
439 | g_free(*err_info);
440 | *err_info = NULL((void*)0);
441 | }
442 | return WTAP_OPEN_NOT_MINE;
443 | }
444 | #if G_BYTE_ORDER1234 == G_BIG_ENDIAN4321
445 | num_strings = GUINT32_SWAP_LE_BE(num_strings)(((guint32) ( (((guint32) (num_strings) & (guint32) 0x000000ffU ) << 24) | (((guint32) (num_strings) & (guint32) 0x0000ff00U ) << 8) | (((guint32) (num_strings) & (guint32) 0x00ff0000U ) >> 8) | (((guint32) (num_strings) & (guint32) 0xff000000U ) >> 24))));
446 | #endif
447 | if (num_strings > MAX_PROCMON_STRINGS(1000 * 1000)) {
22 | ← | Assuming the condition is false | →
23 | ← | Taking false branch | →
448 | ws_debug("Truncating strings from %u to %u", num_strings, MAX_PROCMON_STRINGS)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 448, __func__, "Truncating strings from %u to %u", num_strings , (1000 * 1000)); } } while (0);
449 | num_strings = MAX_PROCMON_STRINGS(1000 * 1000);
450 | }
451 |
452 | // Strings aren't necessarily contiguous (or even in order?)
453 | uint32_t *str_offsets = g_new(uint32_t, num_strings)((uint32_t *) g_malloc_n ((num_strings), sizeof (uint32_t)));
454 | if (!wtap_read_bytes_or_eof(wth->fh, str_offsets, sizeof(uint32_t) * num_strings, err, err_info))
24 | ← | Assuming the condition is false | →
25 | ← | Taking false branch | →
455 | {
456 | file_info_cleanup(file_info);
457 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 457, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
458 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
459 | {
460 | // Short read or EOF.
461 | *err = 0;
462 | g_free(*err_info);
463 | *err_info = NULL((void*)0);
464 | }
465 | g_free(str_offsets);
466 | return WTAP_OPEN_NOT_MINE;
467 | }
468 | #if G_BYTE_ORDER1234 == G_BIG_ENDIAN4321
469 | for (unsigned idx = 0; idx < num_strings; idx++)
470 | {
471 | str_offsets[idx] = GUINT32_SWAP_LE_BE(str_offsets[idx])(((guint32) ( (((guint32) (str_offsets[idx]) & (guint32) 0x000000ffU ) << 24) | (((guint32) (str_offsets[idx]) & (guint32 ) 0x0000ff00U) << 8) | (((guint32) (str_offsets[idx]) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (str_offsets [idx]) & (guint32) 0xff000000U) >> 24))));
472 | }
473 | #endif
474 |
475 | file_info->string_array_size = num_strings;
476 | file_info->string_array = g_new0(const char *, num_strings)((const char * *) g_malloc0_n ((num_strings), sizeof (const char *)));
477 | gunichar2 *cur_str = g_new(gunichar2, MAX_PROCMON_STRING_LENGTH)((gunichar2 *) g_malloc_n ((8192), sizeof (gunichar2)));
478 | for (unsigned idx = 0; idx
25.1 | 'idx' is < 'num_strings'
< num_strings; idx++) {
26 | ← | Loop condition is true. Entering loop body | →
35 | ← | Assuming 'idx' is >= 'num_strings' | →
36 | ← | Loop condition is false. Execution continues on line 529 | →
479 | if (file_seek(wth->fh, header->string_array_offset + str_offsets[idx], SEEK_SET0, err) == -1)
27 | ← | Assuming the condition is false | →
28 | ← | Taking false branch | →
480 | {
481 | file_info_cleanup(file_info);
482 | g_free(str_offsets);
483 | g_free(cur_str);
484 | ws_debug("Failed to locate procmon string %u", idx)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 484, __func__, "Failed to locate procmon string %u", idx); } } while (0);
485 | return WTAP_OPEN_NOT_MINE;
486 | }
487 |
488 | uint32_t cur_str_size;
489 | if (!wtap_read_bytes_or_eof(wth->fh, &cur_str_size, sizeof(cur_str_size), err, err_info))
29 | ← | Assuming the condition is false | →
30 | ← | Taking false branch | →
490 | {
491 | file_info_cleanup(file_info);
492 | g_free(str_offsets);
493 | g_free(cur_str);
494 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 494, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
495 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
496 | {
497 | // Short read or EOF.
498 | *err = 0;
499 | g_free(*err_info);
500 | *err_info = NULL((void*)0);
501 | }
502 | return WTAP_OPEN_NOT_MINE;
503 | }
504 | #if G_BYTE_ORDER1234 == G_BIG_ENDIAN4321
505 | cur_str_size = GUINT32_SWAP_LE_BE(cur_str_size)(((guint32) ( (((guint32) (cur_str_size) & (guint32) 0x000000ffU ) << 24) | (((guint32) (cur_str_size) & (guint32) 0x0000ff00U ) << 8) | (((guint32) (cur_str_size) & (guint32) 0x00ff0000U ) >> 8) | (((guint32) (cur_str_size) & (guint32) 0xff000000U ) >> 24))));
506 | #endif
507 | // XXX check cur_str_size
508 | if (cur_str_size > MAX_PROCMON_STRING_LENGTH8192) {
31 | ← | Assuming 'cur_str_size' is <= MAX_PROCMON_STRING_LENGTH | →
32 | ← | Taking false branch | →
509 | ws_debug("Truncating string %u from %u bytes to %u", idx, cur_str_size, MAX_PROCMON_STRING_LENGTH)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 509, __func__, "Truncating string %u from %u bytes to %u", idx , cur_str_size, 8192); } } while (0);
510 | cur_str_size = MAX_PROCMON_STRING_LENGTH8192;
511 | }
512 | if (!wtap_read_bytes_or_eof(wth->fh, cur_str, sizeof(gunichar2) * (unsigned)cur_str_size, err, err_info))
33 | ← | Assuming the condition is false | →
34 | ← | Taking false branch | →
513 | {
514 | file_info_cleanup(file_info);
515 | g_free(str_offsets);
516 | g_free(cur_str);
517 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 517, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
518 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
519 | {
520 | // Short read or EOF.
521 | *err = 0;
522 | g_free(*err_info);
523 | *err_info = NULL((void*)0);
524 | }
525 | return WTAP_OPEN_NOT_MINE;
526 | }
527 | file_info->string_array[idx] = g_utf16_to_utf8(cur_str, cur_str_size, NULL((void*)0), NULL((void*)0), NULL((void*)0));
528 | }
529 | g_free(str_offsets);
530 | g_free(cur_str);
531 |
532 | if (file_seek(wth->fh, header->process_array_offset, SEEK_SET0, err) == -1)
37 | ← | Assuming the condition is false | →
38 | ← | Taking false branch | →
533 | {
534 | ws_debug("Failed to locate procmon process data")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 534, __func__, "Failed to locate procmon process data"); } } while (0);
535 | return false0;
536 | }
537 |
538 | uint32_t num_processes;
539 | if (!wtap_read_bytes_or_eof(wth->fh, &num_processes, sizeof(num_processes), err, err_info))
39 | ← | Assuming the condition is false | →
40 | ← | Taking false branch | →
540 | {
541 | file_info_cleanup(file_info);
542 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 542, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
543 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
544 | {
545 | // Short read or EOF.
546 | *err = 0;
547 | g_free(*err_info);
548 | *err_info = NULL((void*)0);
549 | }
550 | return WTAP_OPEN_NOT_MINE;
551 | }
552 | #if G_BYTE_ORDER1234 == G_BIG_ENDIAN4321
553 | num_processes = GUINT32_SWAP_LE_BE(num_processes)(((guint32) ( (((guint32) (num_processes) & (guint32) 0x000000ffU ) << 24) | (((guint32) (num_processes) & (guint32) 0x0000ff00U ) << 8) | (((guint32) (num_processes) & (guint32) 0x00ff0000U ) >> 8) | (((guint32) (num_processes) & (guint32) 0xff000000U ) >> 24))));
554 | #endif
555 | if (num_processes > MAX_PROCMON_PROCESSES(500 * 1000)) {
41 | ← | Assuming the condition is false | →
42 | ← | Taking false branch | →
556 | ws_debug("Truncating processes from %u to %u", num_processes, MAX_PROCMON_PROCESSES)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 556, __func__, "Truncating processes from %u to %u", num_processes , (500 * 1000)); } } while (0);
557 | num_processes = MAX_PROCMON_PROCESSES(500 * 1000);
558 | }
559 |
560 | uint32_t *process_indices = g_new(uint32_t, num_processes)((uint32_t *) g_malloc_n ((num_processes), sizeof (uint32_t)) );
561 | if (!wtap_read_bytes_or_eof(wth->fh, process_indices, sizeof(uint32_t) * num_processes, err, err_info))
43 | ← | Assuming the condition is false | →
44 | ← | Taking false branch | →
562 | {
563 | file_info_cleanup(file_info);
564 | g_free(process_indices);
565 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 565, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
566 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
567 | {
568 | // Short read or EOF.
569 | *err = 0;
570 | g_free(*err_info);
571 | *err_info = NULL((void*)0);
572 | }
573 | return WTAP_OPEN_NOT_MINE;
574 | }
575 |
576 | uint32_t max_process_index = 0;
577 | for (unsigned idx = 0; idx
44.1 | 'idx' is < 'num_processes'
< num_processes; idx++) {
48 | ← | Assuming 'idx' is >= 'num_processes' | →
49 | ← | Loop condition is false. Execution continues on line 583 | →
578 | #if G_BYTE_ORDER1234 == G_BIG_ENDIAN4321
579 | process_indices[idx] = GUINT32_SWAP_LE_BE(process_indices[idx])(((guint32) ( (((guint32) (process_indices[idx]) & (guint32 ) 0x000000ffU) << 24) | (((guint32) (process_indices[idx ]) & (guint32) 0x0000ff00U) << 8) | (((guint32) (process_indices [idx]) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (process_indices[idx]) & (guint32) 0xff000000U) >> 24))));
580 | #endif
581 | max_process_index = MAX(max_process_index, process_indices[idx])(((max_process_index) > (process_indices[idx])) ? (max_process_index ) : (process_indices[idx]));
45 | ← | Loop condition is true. Entering loop body | →
46 | ← | Assuming the condition is false | →
47 | ← | '?' condition is false | →
582 | }
583 | g_free(process_indices);
584 | if (max_process_index > MAX_PROCMON_PROCESSES(500 * 1000) * 2) {
50 | ← | Assuming the condition is false | →
51 | ← | Taking false branch | →
585 | ws_debug("Truncating max process index from %u to %u", max_process_index, MAX_PROCMON_PROCESSES * 2)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 585, __func__, "Truncating max process index from %u to %u" , max_process_index, (500 * 1000) * 2); } } while (0);
586 | max_process_index = MAX_PROCMON_PROCESSES(500 * 1000) * 2;
587 | }
588 | file_info->process_index_map = g_new(uint32_t, max_process_index + 1)((uint32_t *) g_malloc_n ((max_process_index + 1), sizeof (uint32_t )));
589 | // Try to make invalid entries obvious.
590 | memset(file_info->process_index_map, 0xff, sizeof(uint32_t) * (max_process_index + 1));
591 | file_info->process_index_map_size = max_process_index + 1;
592 |
593 | uint32_t *proc_offsets = g_new(uint32_t, num_processes)((uint32_t *) g_malloc_n ((num_processes), sizeof (uint32_t)) );
594 | if (!wtap_read_bytes_or_eof(wth->fh, proc_offsets, sizeof(uint32_t) * num_processes, err, err_info))
52 | ← | Assuming the condition is false | →
53 | ← | Taking false branch | →
595 | {
596 | file_info_cleanup(file_info);
597 | g_free(proc_offsets);
598 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 598, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
599 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
600 | {
601 | // Short read or EOF.
602 | *err = 0;
603 | g_free(*err_info);
604 | *err_info = NULL((void*)0);
605 | }
606 | return WTAP_OPEN_NOT_MINE;
607 | }
608 |
609 | file_info->process_array = g_new(procmon_process_t, num_processes)((procmon_process_t *) g_malloc_n ((num_processes), sizeof (procmon_process_t )));
54 | ← | Memory is allocated | →
610 | file_info->process_array_size = num_processes;
611 | for (unsigned idx = 0; idx < num_processes; idx++) {
55 | ← | Loop condition is true. Entering loop body | →
612 | if (file_seek(wth->fh, header->process_array_offset + proc_offsets[idx], SEEK_SET0, err) == -1)
56 | ← | Assuming the condition is false | →
57 | ← | Taking false branch | →
613 | {
614 | file_info_cleanup(file_info);
615 | g_free(proc_offsets);
616 | ws_debug("Failed to locate procmon process %u", idx)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 616, __func__, "Failed to locate procmon process %u", idx); } } while (0);
617 | return WTAP_OPEN_NOT_MINE;
618 | }
619 | procmon_raw_process_t cur_raw_process;
620 | if (!wtap_read_bytes_or_eof(wth->fh, &cur_raw_process, sizeof(cur_raw_process), err, err_info))
58 | ← | Assuming the condition is false | →
59 | ← | Taking false branch | →
621 | {
622 | file_info_cleanup(file_info);
623 | g_free(proc_offsets);
624 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 624, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
625 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
626 | {
627 | // Short read or EOF.
628 | *err = 0;
629 | g_free(*err_info);
630 | *err_info = NULL((void*)0);
631 | }
632 | return WTAP_OPEN_NOT_MINE;
633 | }
634 | uint32_t process_index = GUINT32_FROM_LE(cur_raw_process.process_index)(((guint32) (cur_raw_process.process_index)));
635 | if (process_index <= max_process_index) {
60 | ← | Assuming 'process_index' is > 'max_process_index' | →
61 | ← | Taking false branch | →
636 | file_info->process_index_map[process_index] = idx;
637 | } else {
638 | ws_debug("Process %u index %u exceeds max process index %u", idx, process_index, max_process_index)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 638, __func__, "Process %u index %u exceeds max process index %u" , idx, process_index, max_process_index); } } while (0);
62 | ← | Taking true branch | →
63 | ← | Loop condition is false. Exiting loop | →
639 | }
640 | procmon_process_t *cur_process = &file_info->process_array[idx];
641 | cur_raw_process.start_time = GUINT64_FROM_LE(cur_raw_process.start_time)(((guint64) (cur_raw_process.start_time)));
642 | cur_raw_process.end_time = GUINT64_FROM_LE(cur_raw_process.end_time)(((guint64) (cur_raw_process.end_time)));
643 | uint64_t filetime = GUINT64_FROM_LE(cur_raw_process.start_time)(((guint64) (cur_raw_process.start_time)));
644 | filetime_to_nstime(&cur_process->start_time, filetime);
645 | filetime = GUINT64_FROM_LE(cur_raw_process.end_time)(((guint64) (cur_raw_process.end_time)));
646 | filetime_to_nstime(&cur_process->end_time, filetime);
647 |
648 | cur_process->process_id = GUINT32_FROM_LE(cur_raw_process.process_id)(((guint32) (cur_raw_process.process_id)));
649 | cur_process->parent_process_id = GUINT32_FROM_LE(cur_raw_process.parent_process_id)(((guint32) (cur_raw_process.parent_process_id)));
650 | cur_process->parent_process_index = MAX(GUINT32_FROM_LE(cur_raw_process.parent_process_index), max_process_index)((((((guint32) (cur_raw_process.parent_process_index)))) > (max_process_index)) ? ((((guint32) (cur_raw_process.parent_process_index )))) : (max_process_index));
64 | ← | Assuming 'max_process_index' is >= field 'parent_process_index' | →
65 | ← | '?' condition is false | →
651 | cur_process->authentication_id = GUINT64_FROM_LE(cur_raw_process.authentication_id)(((guint64) (cur_raw_process.authentication_id)));
652 | cur_process->session_number = GUINT32_FROM_LE(cur_raw_process.session_number)(((guint32) (cur_raw_process.session_number)));
653 | cur_process->is_virtualized = cur_raw_process.is_virtualized != 0;
66 | ← | Assuming field 'is_virtualized' is equal to 0 | →
654 | cur_process->is_64_bit = cur_raw_process.is_64_bit != 0;
67 | ← | Assuming field 'is_64_bit' is equal to 0 | →
655 | cur_process->integrity = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_process.integrity_si)(((guint32) (cur_raw_process.integrity_si))));
656 | cur_process->user_name = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_process.user_name_si)(((guint32) (cur_raw_process.user_name_si))));
657 | cur_process->process_name = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_process.process_name_si)(((guint32) (cur_raw_process.process_name_si))));
658 | cur_process->image_path = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_process.image_path_si)(((guint32) (cur_raw_process.image_path_si))));
659 | cur_process->command_line = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_process.command_line_si)(((guint32) (cur_raw_process.command_line_si))));
660 | cur_process->company = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_process.company_si)(((guint32) (cur_raw_process.company_si))));
661 | cur_process->version = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_process.version_si)(((guint32) (cur_raw_process.version_si))));
662 | cur_process->description = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_process.description_si)(((guint32) (cur_raw_process.description_si))));
663 | if (file_seek(wth->fh, header->system_bitness ? 8 : 4, SEEK_CUR1, err) == -1)
68 | ← | Assuming field 'system_bitness' is 0 | →
69 | ← | '?' condition is false | →
70 | ← | Assuming the condition is false | →
71 | ← | Taking false branch | →
664 | {
665 | file_info_cleanup(file_info);
666 | g_free(proc_offsets);
667 | ws_debug("Failed to locate number of modules %u", idx)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 667, __func__, "Failed to locate number of modules %u", idx ); } } while (0);
668 | return WTAP_OPEN_NOT_MINE;
669 | }
670 | uint32_t num_modules;
671 | if (!wtap_read_bytes_or_eof(wth->fh, &num_modules, sizeof(num_modules), err, err_info))
72 | ← | Assuming the condition is false | →
672 | {
673 | file_info_cleanup(file_info);
674 | g_free(proc_offsets);
675 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 675, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
676 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
677 | {
678 | // Short read or EOF.
679 | *err = 0;
680 | g_free(*err_info);
681 | *err_info = NULL((void*)0);
682 | }
683 | return WTAP_OPEN_NOT_MINE;
684 | }
685 |
686 | cur_process->num_modules = MIN(GUINT32_FROM_LE(num_modules), MAX_PROCMON_MODULES)((((((guint32) (num_modules)))) < (1000)) ? ((((guint32) ( num_modules)))) : (1000));
73 | ← | Taking false branch | →
74 | ← | Assuming 'num_modules' is >= 1000 | →
75 | ← | '?' condition is false | →
687 | if (cur_process->num_modules
75.1 | Field 'num_modules' is > 0
> 0) {
76 | ← | Taking true branch | →
688 | cur_process->modules = g_new(procmon_module_t, cur_process->num_modules)((procmon_module_t *) g_malloc_n ((cur_process->num_modules ), sizeof (procmon_module_t)));
689 | for (unsigned mod_idx = 0; mod_idx < cur_process->num_modules; mod_idx++) {
77 | ← | Loop condition is true. Entering loop body | →
690 | if (cur_process->is_64_bit
77.1 | Field 'is_64_bit' is false
) {
78 | ← | Taking false branch | →
691 | procmon_raw_module_64_t cur_raw_module;
692 | if (!wtap_read_bytes_or_eof(wth->fh, &cur_raw_module, sizeof(cur_raw_module), err, err_info)) {
693 | file_info_cleanup(file_info);
694 | g_free(proc_offsets);
695 | g_free(cur_process->modules);
696 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 696, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
697 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
698 | {
699 | // Short read or EOF.
700 | *err = 0;
701 | g_free(*err_info);
702 | *err_info = NULL((void*)0);
703 | }
704 | return WTAP_OPEN_NOT_MINE;
705 | }
706 | procmon_module_t *cur_module = &cur_process->modules[mod_idx];
707 | cur_module->base_address = GUINT64_FROM_LE(cur_raw_module.base_address)(((guint64) (cur_raw_module.base_address)));
708 | cur_module->size = GUINT32_FROM_LE(cur_raw_module.size)(((guint32) (cur_raw_module.size)));
709 | cur_module->image_path = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_module.image_path_si)(((guint32) (cur_raw_module.image_path_si))));
710 | cur_module->version = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_module.version_si)(((guint32) (cur_raw_module.version_si))));
711 | cur_module->company = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_module.company_si)(((guint32) (cur_raw_module.company_si))));
712 | cur_module->description = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_module.description_si)(((guint32) (cur_raw_module.description_si))));
713 | // filetime = GUINT64_FROM_LE(cur_raw_module.timestamp);
714 | // filetime_to_nstime(&cur_module->timestamp, filetime);
715 | } else {
716 | procmon_raw_module_32_t cur_raw_module;
717 | if (!wtap_read_bytes_or_eof(wth->fh, &cur_raw_module, sizeof(cur_raw_module), err, err_info)) {
79 | ← | Assuming the condition is true | →
80 | ← | Taking true branch | →
718 | file_info_cleanup(file_info);
81 | ← | Calling 'file_info_cleanup' | →
86 | ← | Returning; memory was released | →
719 | g_free(proc_offsets);
720 | g_free(cur_process->modules);
87 | ← | Use of memory after it is freed
721 | ws_debug("wtap_read_bytes_or_eof() failed, err = %d.", *err)do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 721, __func__, "wtap_read_bytes_or_eof() failed, err = %d." , *err); } } while (0);
722 | if (*err == 0 || *err == WTAP_ERR_SHORT_READ-12)
723 | {
724 | // Short read or EOF.
725 | *err = 0;
726 | g_free(*err_info);
727 | *err_info = NULL((void*)0);
728 | }
729 | return WTAP_OPEN_NOT_MINE;
730 | }
731 | procmon_module_t *cur_module = &cur_process->modules[mod_idx];
732 | cur_module->base_address = GUINT32_FROM_LE(cur_raw_module.base_address)(((guint32) (cur_raw_module.base_address)));
733 | cur_module->size = GUINT32_FROM_LE(cur_raw_module.size)(((guint32) (cur_raw_module.size)));
734 | cur_module->image_path = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_module.image_path_si)(((guint32) (cur_raw_module.image_path_si))));
735 | cur_module->version = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_module.version_si)(((guint32) (cur_raw_module.version_si))));
736 | cur_module->company = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_module.company_si)(((guint32) (cur_raw_module.company_si))));
737 | cur_module->description = procmon_string(file_info, GUINT32_FROM_LE(cur_raw_module.description_si)(((guint32) (cur_raw_module.description_si))));
738 | // filetime = GUINT64_FROM_LE(cur_raw_module.timestamp);
739 | // filetime_to_nstime(&cur_module->timestamp, filetime);
740 | }
741 | }
742 | } else {
743 | cur_process->modules = NULL((void*)0);
744 | }
745 | }
746 | g_free(proc_offsets);
747 |
748 | if (file_seek(wth->fh, header->start_events_offset, SEEK_SET0, err) == -1)
749 | {
750 | ws_debug("Failed to locate procmon events data")do { if (1) { ws_log_full("Wiretap", LOG_LEVEL_DEBUG, "wiretap/procmon.c" , 750, __func__, "Failed to locate procmon events data"); } } while (0);
751 | return false0;
752 | }
753 |
754 | wth->meta_events = g_array_new(false0, false0, sizeof(wtap_block_t));
755 |
756 | wth->priv = file_info;
757 | wth->file_type_subtype = procmon_file_type_subtype;
758 | wth->file_encap = WTAP_ENCAP_PROCMON227;
759 |
760 | wth->snapshot_length = 0;
761 | wth->file_tsprec = WTAP_TSPREC_SEC0;
762 |
763 | wth->subtype_read = procmon_read;
764 | wth->subtype_seek_read = procmon_seek_read;
765 |
766 | return WTAP_OPEN_MINE;
767 | }
768 |
769 | /* Options for meta event blocks. */
770 | static const struct supported_option_type ft_specific_event_block_options_supported[] = {
771 | { OPT_COMMENT1, MULTIPLE_OPTIONS_SUPPORTED },
772 | { OPT_CUSTOM_STR_COPY2988, MULTIPLE_OPTIONS_SUPPORTED },
773 | { OPT_CUSTOM_BIN_COPY2989, MULTIPLE_OPTIONS_SUPPORTED },
774 | { OPT_CUSTOM_STR_NO_COPY19372, MULTIPLE_OPTIONS_SUPPORTED },
775 | { OPT_CUSTOM_BIN_NO_COPY19373, MULTIPLE_OPTIONS_SUPPORTED }
776 | };
777 |
778 |
779 | static const struct supported_block_type procmon_blocks_supported[] = {
780 |
781 | /* Multiple file-type specific events (including local ones). */
782 | { WTAP_BLOCK_FT_SPECIFIC_EVENT, MULTIPLE_BLOCKS_SUPPORTED, OPTION_TYPES_SUPPORTED(ft_specific_event_block_options_supported)(sizeof (ft_specific_event_block_options_supported) / sizeof ( ft_specific_event_block_options_supported)[0]), ft_specific_event_block_options_supported },
783 |
784 | /* Multiple custom blocks. */
785 | { WTAP_BLOCK_CUSTOM, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED0, ((void*)0) },
786 | };
787 |
788 | static const struct file_type_subtype_info procmon_info = {
789 | "MS Procmon files", "procmon", NULL((void*)0), NULL((void*)0),
790 | false0, BLOCKS_SUPPORTED(procmon_blocks_supported)(sizeof (procmon_blocks_supported) / sizeof (procmon_blocks_supported )[0]), procmon_blocks_supported,
791 | NULL((void*)0), NULL((void*)0), NULL((void*)0)
792 | };
793 |
794 | void register_procmon(void)
795 | {
796 | procmon_file_type_subtype = wtap_register_file_type_subtype(&procmon_info);
797 |
798 | /*
799 | * Register name for backwards compatibility with the
800 | * wtap_filetypes table in Lua.
801 | */
802 | wtap_register_backwards_compatibility_lua_name("Procmon", procmon_file_type_subtype);
803 | }
804 |
805 | /*
806 | * Editor modelines - https://www.wireshark.org/tools/modelines.html
807 | *
808 | * Local Variables:
809 | * c-basic-offset: 4
810 | * tab-width: 8
811 | * indent-tabs-mode: nil
812 | * End:
813 | *
814 | * vi: set shiftwidth=4 tabstop=8 expandtab:
815 | * :indentSize=4:tabSize=8:noTabs=true:
816 | */