Bug Summary

File:builds/wireshark/wireshark/epan/wslua/wslua_struct.c
Warning:line 453, column 48
The result of left shift is undefined because the right operand is negative

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 wslua_struct.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-18/lib/clang/18 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /usr/include/lua5.4 -isystem /builds/wireshark/wireshark/build/epan/wslua -isystem /builds/wireshark/wireshark/epan/wslua -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-18/lib/clang/18/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-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -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 -dwarf-debug-flags /usr/lib/llvm-18/bin/clang -### --analyze -x c -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /usr/include/lua5.4 -isystem /builds/wireshark/wireshark/build/epan/wslua -isystem /builds/wireshark/wireshark/epan/wslua -fvisibility=hidden -fexcess-precision=fast -fstrict-flex-arrays=3 -fstack-clash-protection -fcf-protection=full -D _GLIBCXX_ASSERTIONS -fstack-protector-strong -fno-delete-null-pointer-checks -fno-strict-overflow -fno-strict-aliasing -fexceptions -Wno-format-truncation -Wno-format-nonliteral -fdiagnostics-color=always -Wno-pointer-sign -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -std=gnu11 -fPIC /builds/wireshark/wireshark/epan/wslua/wslua_struct.c -o /builds/wireshark/wireshark/sbout/2024-12-02-100256-3913-1 -Xclang -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2024-12-02-100256-3913-1 -x c /builds/wireshark/wireshark/epan/wslua/wslua_struct.c
1/******************************************************************************
2* Copyright (C) 2010-2012 Lua.org, PUC-Rio. All rights reserved.
3*
4* SPDX-License-Identifier: MIT
5*
6******************************************************************************/
7/*
8** {======================================================
9** Library for packing/unpacking structures.
10** See Copyright Notice above.
11**
12** Small changes were made by Hadriel Kaplan - those changes
13** are in the Public Domain.
14**
15** Some changes are based on a patch to struct.h from
16** Flemming Madsen, from here:
17** http://lua-users.org/lists/lua-l/2009-10/msg00572.html
18** In particular, these changes from him:
19** -Can handle 'long long' integers (i8 / I8); though they're converted to doubles
20** -Can insert/specify padding anywhere in a struct. ('X' eg. when a string is following a union)
21** -Can report current offset in both pack and unpack ('=')
22** -Can mask out return values when you only want to calculate sizes or unmarshal pascal-style strings. '(' & ')'
23**
24** Changes I made:
25** -Added support for Int64/UInt64 being packed/unpacked, using 'e'/'E'
26** -Made it follow Wireshark's conventions so we could get API docs
27** =======================================================
28*/
29/*
30** Valid formats:
31** > - big endian
32** < - little endian
33** ![num] - alignment
34** x[num] - pad num bytes, default 1
35** X[num] - pad to num align, default MAXALIGN
36**
37** Following are system-dependent sizes:
38** i/I - signed/unsigned int
39** l/L - signed/unsigned long
40** f - float
41** T - size_t
42**
43** Following are system-independent sizes:
44** b/B - signed/unsigned byte
45** h/H - signed/unsigned short
46** in/In - signed/unsigned integer of size `n' bytes
47 Note: Unpack of i/I is done to a Lua_number, typically a double,
48 so unpacking a 64-bit field (i8/I8) will lose precision.
49 Use e/E to unpack into a Wireshark Int64/UInt64 object/userdata instead.
50** e/E - signed/unsigned eight-byte Integer (64bits, long long), to/from Int64/UInt64 object
51** d - double
52** cn - sequence of `n' chars (from/to a string); when packing, n==0 means
53 the whole string; when unpacking, n==0 means use the previous
54 read number as the string length
55** s - zero-terminated string
56** ' ' - ignored
57** '(' ')' - stop assigning items. ')' start assigning (padding when packing)
58** '=' - return current position / offset
59*/
60
61#include "config.h"
62
63#include <limits.h>
64#include <wsutil/array.h>
65#include "wslua.h"
66
67/* WSLUA_MODULE Struct Binary encode/decode support
68
69 The Struct class offers basic facilities to convert Lua values to and from C-style structs
70 in binary Lua strings. This is based on Roberto Ierusalimschy's Lua struct library found
71 in http://www.inf.puc-rio.br/~roberto/struct/, with some minor modifications as follows:
72 * Added support for `Int64`/`UInt64` being packed/unpacked, using 'e'/'E'.
73 * Can handle 'long long' integers (i8 / I8); though they're converted to doubles.
74 * Can insert/specify padding anywhere in a struct. ('X' eg. when a string is following a union).
75 * Can report current offset in both `pack` and `unpack` ('`=`').
76 * Can mask out return values when you only want to calculate sizes or unmarshal
77 pascal-style strings using '`(`' & '`)`'.
78
79 All but the first of those changes are based on an email from Flemming Madsen, on the lua-users
80 mailing list, which can be found http://lua-users.org/lists/lua-l/2009-10/msg00572.html[here].
81
82 The main functions are `Struct.pack`, which packs multiple Lua values into a struct-like
83 Lua binary string; and `Struct.unpack`, which unpacks multiple Lua values from a given
84 struct-like Lua binary string. There are some additional helper functions available as well.
85
86 All functions in the Struct library are called as static member functions, not object methods,
87 so they are invoked as "Struct.pack(...)" instead of "object:pack(...)".
88
89 The fist argument to several of the `Struct` functions is a format string, which describes
90 the layout of the structure. The format string is a sequence of conversion elements, which
91 respect the current endianness and the current alignment requirements. Initially, the
92 current endianness is the machine's native endianness and the current alignment requirement
93 is 1 (meaning no alignment at all). You can change these settings with appropriate directives
94 in the format string.
95
96 The supported elements in the format string are as follows:
97
98 * `$$ $$' (empty space) ignored.
99 * `++!++__n__' flag to set the current alignment requirement to 'n' (necessarily a power of 2);
100 an absent 'n' means the machine's native alignment.
101 * `++>++' flag to set mode to big endian (i.e., network-order).
102 * `++<++' flag to set mode to little endian.
103 * `++x++' a padding zero byte with no corresponding Lua value.
104 * `++b++' a signed char.
105 * `++B++' an unsigned char.
106 * `++h++' a signed short (native size).
107 * `++H++' an unsigned short (native size).
108 * `++l++' a signed long (native size).
109 * `++L++' an unsigned long (native size).
110 * `++T++' a size_t (native size).
111 * `++i++__n__' a signed integer with 'n' bytes. An absent 'n' means the native size of an int.
112 * `++I++__n__' like `++i++__n__' but unsigned.
113 * `++e++' signed 8-byte Integer (64-bits, long long), to/from a +Int64+ object.
114 * `++E++' unsigned 8-byte Integer (64-bits, long long), to/from a +UInt64+ object.
115 * `++f++' a float (native size).
116 * `++d++' a double (native size).
117 * `++s++' a zero-terminated string.
118 * `++c++__n__' a sequence of exactly 'n' chars corresponding to a single Lua string. An absent 'n'
119 means 1. When packing, the given string must have at least 'n' characters (extra
120 characters are discarded).
121 * `++c0++' this is like `++c++__n__', except that the 'n' is given by other means: When packing, 'n' is
122 the length of the given string; when unpacking, 'n' is the value of the previous unpacked
123 value (which must be a number). In that case, this previous value is not returned.
124 * `++x++__n__' pad to 'n' number of bytes, default 1.
125 * `++X++__n__' pad to 'n' alignment, default MAXALIGN.
126 * `++(++' to stop assigning items, and `++)++' start assigning (padding when packing).
127 * `++=++' to return the current position / offset.
128
129 [IMPORTANT]
130 ====
131 Using `i`, `I`, `h`, `H`, `l`, `L`, `f`, and `T` is strongly discouraged, as those sizes
132 are system-dependent. Use the explicitly sized variants instead, such as `i4` or `E`.
133
134 Unpacking of `i`/`I` is done to a Lua number, a double-precision floating point,
135 so unpacking a 64-bit field (`i8`/`I8`) will lose precision.
136 Use `e`/`E` to unpack into a Wireshark `Int64`/`UInt64` object instead.
137 ====
138
139 [NOTE]
140 ====
141 Lua 5.3 and later provides several built-in functions for struct unpacking and packing:
142 https://www.lua.org/manual/5.4/manual.html#pdf-string.pack[string.pack],
143 https://www.lua.org/manual/5.4/manual.html#pdf-string.packsize[string.packsize], and
144 https://www.lua.org/manual/5.4/manual.html#pdf-string.unpack[string.unpack].
145 You can use those as well, but note that the
146 https://www.lua.org/manual/5.4/manual.html#6.4.2[format string] conversion elements
147 are slightly different, and they do not support the Wireshark `Int64`/`UInt64` objects.
148 ====
149 */
150
151
152/* The following line is here so that make-reg.py does the right thing. This 'Struct' class
153 isn't really a class, so it doesn't have the checkStruct/pushStruct/etc. functions
154 the following macro would generate; but it does need to be registered and such, so...
155 WSLUA_CLASS_DEFINE_BASE(Struct,NOP,0);
156 */
157
158/* basic integer type - yes this is system-specific size - it's meant to be */
159#if !defined(STRUCT_INTlong)
160#define STRUCT_INTlong long
161#endif
162
163typedef STRUCT_INTlong Inttype;
164
165/* corresponding unsigned version */
166typedef unsigned STRUCT_INTlong Uinttype;
167
168/* maximum size (in bytes) for integral types */
169#define MAXINTSIZE32 32
170
171/* is 'x' a power of 2? */
172#define isp2(x)((x) > 0 && ((x) & ((x) - 1)) == 0) ((x) > 0 && ((x) & ((x) - 1)) == 0)
173
174/* dummy structure to get padding/alignment requirements */
175struct cD {
176 char c;
177 double d;
178};
179
180
181#define PADDING(sizeof(struct cD) - sizeof(double)) (sizeof(struct cD) - sizeof(double))
182#define MAXALIGN((sizeof(struct cD) - sizeof(double)) > sizeof(int) ? (sizeof
(struct cD) - sizeof(double)) : sizeof(int))
(PADDING(sizeof(struct cD) - sizeof(double)) > sizeof(int) ? PADDING(sizeof(struct cD) - sizeof(double)) : sizeof(int))
183
184
185/* endian options */
186#define BIG0 0
187#define LITTLE1 1
188
189/* trick to determine native endianness of system */
190static union {
191 int dummy;
192 char endian;
193} const native = {1};
194
195/* settings info */
196typedef struct Header {
197 int endian;
198 int align;
199 bool_Bool noassign;
200} Header;
201
202/* For options that take a number argument, gets the number */
203static int getnum (lua_State *L, const char **fmt, int df) {
204 if (!g_ascii_isdigit(**fmt)((g_ascii_table[(guchar) (**fmt)] & G_ASCII_DIGIT) != 0)) /* no number? */
205 return df; /* return default value */
206 else {
207 int a = 0;
208 do {
209 if (a > (INT_MAX2147483647 / 10) || a * 10 > (INT_MAX2147483647 - (**fmt - '0')))
210 luaL_error(L, "integral size overflow");
211 a = a*10 + *((*fmt)++) - '0';
212 } while (g_ascii_isdigit(**fmt)((g_ascii_table[(guchar) (**fmt)] & G_ASCII_DIGIT) != 0));
213 return a;
214 }
215}
216
217
218#define defaultoptions(h)((h)->endian = native.endian, (h)->align = 1, (h)->noassign
= 0)
((h)->endian = native.endian, (h)->align = 1, (h)->noassign = false0)
219
220
221/* gets size (number of bytes) for a given type */
222static size_t optsize (lua_State *L, char opt, const char **fmt) {
223 switch (opt) {
224 case 'B': case 'b': return sizeof(char);
225 case 'H': case 'h': return sizeof(short);
226 case 'L': case 'l': return sizeof(long);
227 case 'E': case 'e': return sizeof(int64_t);
228 case 'T': return sizeof(size_t);
229 case 'f': return sizeof(float);
230 case 'd': return sizeof(double);
231 case 'x': return getnum(L, fmt, 1);
232 case 'X': return getnum(L, fmt, MAXALIGN((sizeof(struct cD) - sizeof(double)) > sizeof(int) ? (sizeof
(struct cD) - sizeof(double)) : sizeof(int))
);
233 case 'c': return getnum(L, fmt, 1);
234 case 'i': case 'I': {
235 int sz = getnum(L, fmt, sizeof(int));
236 if (sz > MAXINTSIZE32)
237 luaL_error(L, "integral size %d is larger than limit of %d",
238 sz, MAXINTSIZE32);
239 return sz;
240 }
241 case 's': case ' ':
242 case '<': case '>':
243 case '(': case ')':
244 case '!': case '=':
245 return 0; /* these cases do not have a size */
246 default: {
247 const char *msg = lua_pushfstring(L, "invalid format option [%c]", opt);
248 return luaL_argerror(L, 1, msg);
249 }
250 }
251}
252
253
254/*
255** return number of bytes needed to align an element of size 'size'
256** at current position 'len'
257*/
258static int gettoalign (size_t len, Header *h, int opt, size_t size) {
259 if (size == 0 || opt == 'c' || opt == 's') return 0;
3
Assuming 'size' is equal to 0
4
Returning without writing to 'h->noassign', which participates in a condition later
260 if (size > (size_t)h->align)
261 size = h->align; /* respect max. alignment */
262 return (int)((size - (len & (size - 1))) & (size - 1));
263}
264
265
266/*
267** options to control endianness and alignment settings
268*/
269static void controloptions (lua_State *L, int opt, const char **fmt,
270 Header *h) {
271 switch (opt) {
272 case ' ': return; /* ignore white spaces */
273 case '>': h->endian = BIG0; return;
274 case '<': h->endian = LITTLE1; return;
275 case '(': h->noassign = true1; return;
276 case ')': h->noassign = false0; return;
277 case '!': {
278 int a = getnum(L, fmt, MAXALIGN((sizeof(struct cD) - sizeof(double)) > sizeof(int) ? (sizeof
(struct cD) - sizeof(double)) : sizeof(int))
);
279 if (!isp2(a)((a) > 0 && ((a) & ((a) - 1)) == 0))
280 luaL_error(L, "alignment %d is not a power of 2", a);
281 h->align = a;
282 return;
283 }
284 default: {
285 const char *msg = lua_pushfstring(L, "invalid format option '%c'", opt);
286 luaL_argerror(L, 1, msg);
287 }
288 }
289}
290
291/* Encodes a Lua number as an integer of given size and endianness into a string struct */
292static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian,
293 int size) {
294 lua_Number n = luaL_checknumber(L, arg);
295 /* this one's not system dependent size - it's a long long */
296 int64_t value;
297 char buff[MAXINTSIZE32];
298 if (n < 0)
299 value = (uint64_t)(int64_t)n;
300 else
301 value = (uint64_t)n;
302 if (endian == LITTLE1) {
303 int i;
304 for (i = 0; i < size; i++) {
305 buff[i] = (value & 0xff);
306 value >>= 8;
307 }
308 }
309 else {
310 int i;
311 for (i = size - 1; i >= 0; i--) {
312 buff[i] = (value & 0xff);
313 value >>= 8;
314 }
315 }
316 luaL_addlstring(b, buff, size);
317}
318
319/* corrects endianness - usually done by other functions themselves, but is
320 * used for float/doubles, since on some platforms they're endian'ed as well
321 */
322static void correctbytes (char *b, int size, int endian) {
323 if (endian != native.endian) {
324 int i = 0;
325 while (i < --size) {
326 char temp = b[i];
327 b[i++] = b[size];
328 b[size] = temp;
329 }
330 }
331}
332
333
334WSLUA_CONSTRUCTORstatic int Struct_pack (lua_State *L) {
335 /* Returns a string containing the values arg1, arg2, etc. packed/encoded according to the format string. */
336#define WSLUA_ARG_Struct_pack_FORMAT1 1 /* The format string */
337#define WSLUA_ARG_Struct_pack_VALUE2 2 /* One or more Lua value(s) to encode, based on the given format. */
338 luaL_Buffer b;
339 const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_pack_FORMAT1);
340 Header h;
341 int poscnt = 0;
342 int posBuf[10];
343 int arg = 2;
344 size_t totalsize = 0;
345 defaultoptions(&h)((&h)->endian = native.endian, (&h)->align = 1,
(&h)->noassign = 0)
;
346 lua_pushnil(L); /* mark to separate arguments from string buffer */
347 luaL_buffinit(L, &b);
348 while (*fmt != '\0') {
349 int opt = *fmt++;
350 size_t size = optsize(L, opt, &fmt);
351 int toalign = gettoalign(totalsize, &h, opt, size);
352 totalsize += toalign;
353 while (toalign-- > 0) luaL_addchar(&b, '\0')((void)((&b)->n < (&b)->size || luaL_prepbuffsize
((&b), 1)), ((&b)->b[(&b)->n++] = ('\0')))
;
354 if (opt == 'X') size = 0; /* 'X' is about alignment, not size */
355 if (h.noassign && size) opt = 'x'; /* for pack, "(i4)" is the same as "x4" */
356 switch (opt) {
357 case 'b': case 'B': case 'h': case 'H':
358 case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
359 putinteger(L, &b, arg++, h.endian, (int)size);
360 break;
361 }
362 case 'e': {
363 Int64_pack(L, &b, arg++, h.endian == LITTLE1);
364 break;
365 }
366 case 'E': {
367 UInt64_pack(L, &b, arg++, h.endian == LITTLE1);
368 break;
369 }
370 case 'x': case 'X': {
371 size_t len = size;
372 while (len-- > 0)
373 luaL_addchar(&b, '\0')((void)((&b)->n < (&b)->size || luaL_prepbuffsize
((&b), 1)), ((&b)->b[(&b)->n++] = ('\0')))
;
374 break;
375 }
376 case 'f': {
377 float f = (float)luaL_checknumber(L, arg++);
378 correctbytes((char *)&f, (int)size, h.endian);
379 luaL_addlstring(&b, (char *)&f, size);
380 break;
381 }
382 case 'd': {
383 double d = luaL_checknumber(L, arg++);
384 correctbytes((char *)&d, (int)size, h.endian);
385 luaL_addlstring(&b, (char *)&d, size);
386 break;
387 }
388 case 'c': case 's': {
389 size_t l;
390 const char *s = luaL_checklstring(L, arg++, &l);
391 if (size == 0) size = l;
392 luaL_argcheck(L, l >= (size_t)size, arg, "string too short")((void)((__builtin_expect(((l >= (size_t)size) != 0), 1)) ||
luaL_argerror(L, (arg), ("string too short"))))
;
393 luaL_addlstring(&b, s, size);
394 if (opt == 's') {
395 luaL_addchar(&b, '\0')((void)((&b)->n < (&b)->size || luaL_prepbuffsize
((&b), 1)), ((&b)->b[(&b)->n++] = ('\0')))
; /* add zero at the end */
396 size++;
397 }
398 break;
399 }
400 case '=': {
401 if (poscnt < (int)array_length(posBuf)(sizeof (posBuf) / sizeof (posBuf)[0]))
402 posBuf[poscnt++] = (int)totalsize + 1;
403 break;
404 }
405 default: controloptions(L, opt, &fmt, &h);
406 }
407 totalsize += size;
408 }
409 luaL_pushresult(&b);
410 for (arg = 0; arg < poscnt; arg++)
411 lua_pushinteger(L, posBuf[arg]);
412 WSLUA_RETURN(poscnt + 1)return (poscnt + 1); /* The packed binary Lua string, plus any positions due to '=' being used in format. */
413}
414
415static Uinttype decodeinteger (const char *buff, int endian, int size)
416{
417 Uinttype l = 0;
418 int i;
419 if (endian == BIG0) {
420 for (i = 0; i < size; i++) {
421 l <<= 8;
422 l |= (Uinttype)(unsigned char)buff[i];
423 }
424 }
425 else {
426 for (i = size - 1; i >= 0; i--) {
427 l <<= 8;
428 l |= (Uinttype)(unsigned char)buff[i];
429 }
430 }
431 return l;
432}
433
434/* Decodes an integer from a string struct into a lua_Integer, if it fits
435 * without truncation, or a lua_Number, based on given endianness and size.
436 * If the integer type is signed, that is handled correctly as well.
437 * Note for large values of size there can be a loss of precision.
438 */
439static void getinteger (lua_State *L, const char *buff, int endian,
440 int issigned, int size) {
441 Uinttype l = decodeinteger(buff, endian, size);
442 if (!issigned
10.1
'issigned' is 1
) {
11
Taking false branch
443 if (size < LUA_INTEGER_SIZE8) {
444 /* Fits in a lua_Integer (we need a larger size as lua_Integer
445 * is signed.) */
446 lua_pushinteger(L, (lua_Integer)l);
447 } else {
448 /* Does not fit in a lua_Integer */
449 lua_pushnumber(L, (lua_Number)l);
450 }
451 }
452 else { /* signed format */
453 Uinttype mask = (Uinttype)(~((Uinttype)0)) << (size*8 - 1);
12
The result of left shift is undefined because the right operand is negative
454 if (l & mask) /* negative value? */
455 l |= mask; /* sign extension */
456 if (size <= LUA_INTEGER_SIZE8) {
457 /* Fits in a lua_Integer */
458 lua_pushinteger(L, (lua_Integer)(Inttype)l);
459 } else {
460 /* Does not fit in a lua_Integer */
461 lua_pushnumber(L, (lua_Number)(Inttype)l);
462 }
463 }
464}
465
466#define b_pushnumber(n){ if (!h.noassign) lua_pushnumber(L, (lua_Number)(n)); } { if (!h.noassign) lua_pushnumber(L, (lua_Number)(n)); }
467
468WSLUA_CONSTRUCTORstatic int Struct_unpack (lua_State *L) {
469 /* Unpacks/decodes multiple Lua values from a given struct-like binary Lua string.
470 The number of returned values depends on the format given, plus an additional value of the position where it stopped reading is returned. */
471#define WSLUA_ARG_Struct_unpack_FORMAT1 1 /* The format string */
472#define WSLUA_ARG_Struct_unpack_STRUCT2 2 /* The binary Lua string to unpack */
473#define WSLUA_OPTARG_Struct_unpack_BEGIN3 3 /* The position to begin reading from (default=1) */
474 Header h;
475 const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_unpack_FORMAT1);
476 size_t ld;
477 const char *data = wslua_checklstring_only(L, WSLUA_ARG_Struct_unpack_STRUCT2, &ld);
478 size_t pos = luaL_optinteger(L, WSLUA_OPTARG_Struct_unpack_BEGIN3, 1) - 1;
479 defaultoptions(&h)((&h)->endian = native.endian, (&h)->align = 1,
(&h)->noassign = 0)
;
480 lua_settop(L, 2);
481 while (*fmt) {
1
Loop condition is true. Entering loop body
482 int opt = *fmt++;
483 size_t size = optsize(L, opt, &fmt);
484 pos += gettoalign(pos, &h, opt, size);
2
Calling 'gettoalign'
5
Returning from 'gettoalign'
485 luaL_argcheck(L, pos+size <= ld, 2, "data string too short")((void)((__builtin_expect(((pos+size <= ld) != 0), 1)) || luaL_argerror
(L, (2), ("data string too short"))))
;
6
Assuming the condition is true
486
487 if (opt == 'X') size = 0;
7
Assuming the condition is false
488 if (h.noassign
7.1
Field 'noassign' is false
&& size > 0) {
489 /* if we're not assigning, and the opt type has a size, then loop again */
490 /* this will not be the case for control options, 'c0', 's', and '=' */
491 pos += size;
492 continue;
493 }
494
495 luaL_checkstack(L, 1, "too many results");
496 switch (opt) {
8
Control jumps to 'case 73:' at line 498
497 case 'b': case 'B': case 'h': case 'H':
498 case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
499 int issigned = g_ascii_islower(opt)((g_ascii_table[(guchar) (opt)] & G_ASCII_LOWER) != 0);
9
Assuming the condition is true
500 getinteger(L, data+pos, h.endian, issigned, (int)size);
10
Calling 'getinteger'
501 break;
502 }
503 case 'e': {
504 Int64_unpack(L, data+pos, h.endian == LITTLE1);
505 break;
506 }
507 case 'E': {
508 UInt64_unpack(L, data+pos, h.endian == LITTLE1);
509 break;
510 }
511 case 'x': case 'X': {
512 break;
513 }
514 case 'f': {
515 float f;
516 memcpy(&f, data+pos, size);
517 correctbytes((char *)&f, sizeof(f), h.endian);
518 lua_pushnumber(L, f);
519 break;
520 }
521 case 'd': {
522 double d;
523 memcpy(&d, data+pos, size);
524 correctbytes((char *)&d, sizeof(d), h.endian);
525 lua_pushnumber(L, d);
526 break;
527 }
528 case 'c': {
529 if (size == 0) {
530 if (!lua_isnumber(L, -1))
531 luaL_error(L, "format `c0' needs a previous size");
532 size = wslua_touint32(L, -1)(uint32_t) ( lua_tointegerx(L,(-1),((void*)0)) );
533 lua_pop(L, 1)lua_settop(L, -(1)-1);
534 luaL_argcheck(L, pos+size <= ld, 2, "data string too short")((void)((__builtin_expect(((pos+size <= ld) != 0), 1)) || luaL_argerror
(L, (2), ("data string too short"))))
;
535 }
536 if (!h.noassign)
537 lua_pushlstring(L, data+pos, size);
538 break;
539 }
540 case 's': {
541 const char *e = (const char *)memchr(data+pos, '\0', ld - pos);
542 if (e == NULL((void*)0))
543 luaL_error(L, "unfinished string in data");
544 size = (e - (data+pos)) + 1;
545 if (!h.noassign)
546 lua_pushlstring(L, data+pos, size - 1);
547 break;
548 }
549 case '=': {
550 lua_pushinteger(L, pos + 1);
551 break;
552 }
553 default: controloptions(L, opt, &fmt, &h);
554 }
555 pos += size;
556 }
557 lua_pushinteger(L, pos + 1);
558 WSLUA_RETURN(lua_gettop(L) - 2)return (lua_gettop(L) - 2); /* One or more values based on format, plus the position it stopped unpacking. */
559}
560
561
562WSLUA_CONSTRUCTORstatic int Struct_size (lua_State *L) {
563 /* Returns the length of a binary string that would be consumed/handled by the given format string. */
564#define WSLUA_ARG_Struct_size_FORMAT1 1 /* The format string */
565 Header h;
566 const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_size_FORMAT1);
567 size_t pos = 0;
568 defaultoptions(&h)((&h)->endian = native.endian, (&h)->align = 1,
(&h)->noassign = 0)
;
569 while (*fmt) {
570 int opt = *fmt++;
571 size_t size = optsize(L, opt, &fmt);
572 pos += gettoalign(pos, &h, opt, size);
573 if (opt == 's')
574 luaL_argerror(L, 1, "option 's' has no fixed size");
575 else if (opt == 'c' && size == 0)
576 luaL_argerror(L, 1, "option 'c0' has no fixed size");
577 if (!g_ascii_isalnum(opt)((g_ascii_table[(guchar) (opt)] & G_ASCII_ALNUM) != 0))
578 controloptions(L, opt, &fmt, &h);
579 pos += size;
580 }
581 lua_pushinteger(L, pos);
582 WSLUA_RETURN(1)return (1); /* The size number */
583}
584
585WSLUA_CONSTRUCTORstatic int Struct_values (lua_State *L) {
586 /* Returns the number of Lua values contained in the given format string.
587 This will be the number of returned values from a call to Struct.unpack()
588 not including the extra return value of offset position. (i.e., Struct.values()
589 does not count that extra return value) This will also be the number of
590 arguments Struct.pack() expects, not including the format string argument. */
591#define WSLUA_ARG_Struct_values_FORMAT1 1 /* The format string */
592 Header h;
593 const char *fmt = wslua_checkstring_only(L, WSLUA_ARG_Struct_values_FORMAT1);
594 size_t vals = 0;
595 defaultoptions(&h)((&h)->endian = native.endian, (&h)->align = 1,
(&h)->noassign = 0)
;
596 while (*fmt) {
597 int opt = *fmt++;
598 /* we use a size != 0 to mean it is a value */
599 size_t size = optsize(L, opt, &fmt);
600 /* but some will be zero and not be a value, or vice-versa */
601 switch (opt) {
602 case 's': case 'c':
603 /* these are values */
604 size = 1;
605 break;
606 case 'x': case 'X':
607 /* these are not */
608 size = 0;
609 break;
610 default:
611 break;
612 }
613 if (!g_ascii_isalnum(opt)((g_ascii_table[(guchar) (opt)] & G_ASCII_ALNUM) != 0))
614 controloptions(L, opt, &fmt, &h);
615 else if (size && !h.noassign)
616 vals++;
617 }
618 lua_pushinteger(L, vals);
619 WSLUA_RETURN(1)return (1); /* The number of values */
620}
621
622WSLUA_CONSTRUCTORstatic int Struct_tohex (lua_State *L) {
623 /* Converts the passed-in binary string to a hex-ascii string. */
624#define WSLUA_ARG_Struct_tohex_BYTESTRING1 1 /* A Lua string consisting of binary bytes */
625#define WSLUA_OPTARG_Struct_tohex_LOWERCASE2 2 /* True to use lower-case hex characters (default=false). */
626#define WSLUA_OPTARG_Struct_tohex_SEPARATOR3 3 /* A string separator to insert between hex bytes (default=nil). */
627 const char* s = NULL((void*)0);
628 size_t len = 0;
629 bool_Bool lowercase = false0;
630 const char* sep = NULL((void*)0);
631
632 /* luaL_checklstring coerces the argument to a string, and that's ok for tohex,
633 just not fromhex. In fact, we should accept/coerce a Int64/UInt64 here too someday. */
634 s = luaL_checklstring(L, WSLUA_ARG_Struct_tohex_BYTESTRING1, &len);
635
636 lowercase = wslua_optbool(L,WSLUA_OPTARG_Struct_tohex_LOWERCASE2,false0);
637 sep = luaL_optstring(L,WSLUA_OPTARG_Struct_tohex_SEPARATOR,NULL)(luaL_optlstring(L, (3), (((void*)0)), ((void*)0)));
638
639 wslua_bin2hex(L, s, (unsigned)len, lowercase, sep);
640 WSLUA_RETURN(1)return (1); /* The Lua hex-ascii string */
641}
642
643WSLUA_CONSTRUCTORstatic int Struct_fromhex (lua_State *L) {
644 /* Converts the passed-in hex-ascii string to a binary string. */
645#define WSLUA_ARG_Struct_fromhex_HEXBYTES1 1 /* A string consisting of hexadecimal bytes like "00 B1 A2" or "1a2b3c4d" */
646#define WSLUA_OPTARG_Struct_fromhex_SEPARATOR2 2 /* A string separator between hex bytes/words (default none). */
647 const char* s = NULL((void*)0);
648 size_t len = 0;
649 const char* sep = NULL((void*)0);
650
651 /* luaL_checklstring coerces the argument to a string, and we don't want to do that */
652 s = wslua_checklstring_only(L, WSLUA_ARG_Struct_fromhex_HEXBYTES1, &len);
653
654 sep = luaL_optstring(L,WSLUA_OPTARG_Struct_fromhex_SEPARATOR,NULL)(luaL_optlstring(L, (2), (((void*)0)), ((void*)0)));
655
656 wslua_hex2bin(L, s, (unsigned)len, sep);
657 WSLUA_RETURN(1)return (1); /* The Lua binary string */
658}
659
660/* }====================================================== */
661
662/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
663static int Struct__gc(lua_State* L _U___attribute__((unused))) {
664 return 0;
665}
666
667WSLUA_METHODSstatic const luaL_Reg Struct_methods[] = {
668 WSLUA_CLASS_FNREG(Struct,pack){ "pack", Struct_pack },
669 WSLUA_CLASS_FNREG(Struct,unpack){ "unpack", Struct_unpack },
670 WSLUA_CLASS_FNREG(Struct,size){ "size", Struct_size },
671 WSLUA_CLASS_FNREG(Struct,values){ "values", Struct_values },
672 WSLUA_CLASS_FNREG(Struct,tohex){ "tohex", Struct_tohex },
673 WSLUA_CLASS_FNREG(Struct,fromhex){ "fromhex", Struct_fromhex },
674 { NULL((void*)0), NULL((void*)0) }
675};
676
677WSLUA_METAstatic const luaL_Reg Struct_meta[] = {
678 { NULL((void*)0), NULL((void*)0) }
679};
680
681LUALIB_APIextern int Struct_register(lua_State* L) {
682 WSLUA_REGISTER_CLASS(Struct){ const wslua_class Struct_class = { .name = "Struct", .class_methods
= Struct_methods, .class_meta = Struct_meta, .instance_methods
= Struct_methods, .instance_meta = Struct_meta, .attrs = ((void
*)0) }; wslua_register_class(L, &Struct_class); (lua_getfield
(L, (-1000000 - 1000), ("Struct"))); lua_pushcclosure(L, (Struct__gc
), 0); lua_setfield(L, -2, "__gc"); lua_settop(L, -(1)-1); }
;
683 return 0;
684}
685
686/*
687 * Editor modelines - https://www.wireshark.org/tools/modelines.html
688 *
689 * Local Variables:
690 * c-basic-offset: 2
691 * tab-width: 8
692 * indent-tabs-mode: nil
693 * End:
694 *
695 * vi: set shiftwidth=2 tabstop=8 expandtab:
696 * :indentSize=2:tabSize=8:noTabs=true:
697 */