]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
lib:util: Add bytearray.h
authorAndreas Schneider <asn@samba.org>
Thu, 20 Dec 2018 07:37:32 +0000 (08:37 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 21 Feb 2020 02:09:33 +0000 (02:09 +0000)
This is an implementation which doesn't have undefined behavior
problems. It casts correctly that calculations are don in the correct
integer space. Also the naming is less confusing than what we have in
byteorder.h.

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
lib/util/bytearray.h [new file with mode: 0644]
lib/util/tests/test_bytearray.c [new file with mode: 0644]
lib/util/wscript_build
selftest/tests.py

diff --git a/lib/util/bytearray.h b/lib/util/bytearray.h
new file mode 100644 (file)
index 0000000..b48d9c1
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Macros for handling integer types in byte arrays
+ *
+ * This file is originally from the libssh.org project
+ *
+ * Copyright (c) 2018 Andreas Schneider <asn@cryptomilk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef _BYTEARRAY_H
+#define _BYTEARRAY_H
+
+#define _DATA_BYTE_CONST(data, pos) \
+    ((uint8_t)(((const uint8_t *)(data))[(pos)]))
+
+#define _DATA_BYTE(data, pos) \
+    (((uint8_t *)(data))[(pos)])
+
+/*
+ * These macros pull or push integer values from byte arrays stored in
+ * little-endian byte order.
+ */
+#define PULL_LE_U8(data, pos) \
+    (_DATA_BYTE_CONST(data, pos))
+
+#define PULL_LE_U16(data, pos) \
+    ((uint16_t)PULL_LE_U8(data, pos) | ((uint16_t)(PULL_LE_U8(data, (pos) + 1))) << 8)
+
+#define PULL_LE_U32(data, pos) \
+    ((uint32_t)(PULL_LE_U16(data, pos) | ((uint32_t)PULL_LE_U16(data, (pos) + 2)) << 16))
+
+#define PULL_LE_U64(data, pos) \
+    ((uint64_t)(PULL_LE_U32(data, pos) | ((uint64_t)PULL_LE_U32(data, (pos) + 4)) << 32))
+
+
+#define PUSH_LE_U8(data, pos, val) \
+    (_DATA_BYTE(data, pos) = ((uint8_t)(val)))
+
+#define PUSH_LE_U16(data, pos, val) \
+    (PUSH_LE_U8((data), (pos), (uint8_t)((uint16_t)(val) & 0xff)), PUSH_LE_U8((data), (pos) + 1, (uint8_t)((uint16_t)(val) >> 8)))
+
+#define PUSH_LE_U32(data, pos, val) \
+    (PUSH_LE_U16((data), (pos), (uint16_t)((uint32_t)(val) & 0xffff)), PUSH_LE_U16((data), (pos) + 2, (uint16_t)((uint32_t)(val) >> 16)))
+
+#define PUSH_LE_U64(data, pos, val) \
+    (PUSH_LE_U32((data), (pos), (uint32_t)((uint64_t)(val) & 0xffffffff)), PUSH_LE_U32((data), (pos) + 4, (uint32_t)((uint64_t)(val) >> 32)))
+
+
+
+/*
+ * These macros pull or push integer values from byte arrays stored in
+ * big-endian byte order (network byte order).
+ */
+#define PULL_BE_U8(data, pos) \
+    (_DATA_BYTE_CONST(data, pos))
+
+#define PULL_BE_U16(data, pos) \
+    ((((uint16_t)(PULL_BE_U8(data, pos))) << 8) | (uint16_t)PULL_BE_U8(data, (pos) + 1))
+
+#define PULL_BE_U32(data, pos) \
+    ((((uint32_t)PULL_BE_U16(data, pos)) << 16) | (uint32_t)(PULL_BE_U16(data, (pos) + 2)))
+
+#define PULL_BE_U64(data, pos) \
+    ((((uint64_t)PULL_BE_U32(data, pos)) << 32) | (uint64_t)(PULL_BE_U32(data, (pos) + 4)))
+
+
+
+#define PUSH_BE_U8(data, pos, val) \
+    (_DATA_BYTE(data, pos) = ((uint8_t)(val)))
+
+#define PUSH_BE_U16(data, pos, val) \
+    (PUSH_BE_U8((data), (pos), (uint8_t)(((uint16_t)(val)) >> 8)), PUSH_BE_U8((data), (pos) + 1, (uint8_t)((val) & 0xff)))
+
+#define PUSH_BE_U32(data, pos, val) \
+    (PUSH_BE_U16((data), (pos), (uint16_t)(((uint32_t)(val)) >> 16)), PUSH_BE_U16((data), (pos) + 2, (uint16_t)((val) & 0xffff)))
+
+#define PUSH_BE_U64(data, pos, val) \
+    (PUSH_BE_U32((data), (pos), (uint32_t)(((uint64_t)(val)) >> 32)), PUSH_BE_U32((data), (pos) + 4, (uint32_t)((val) & 0xffffffff)))
+
+#endif /* _BYTEARRAY_H */
diff --git a/lib/util/tests/test_bytearray.c b/lib/util/tests/test_bytearray.c
new file mode 100644 (file)
index 0000000..fcf63d8
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018-2019 Andreas Schneider <asn@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include "lib/util/bytearray.h"
+
+static void torture_pull_le_u8(void **state)
+{
+       uint8_t data[2] = {0};
+       uint8_t result;
+
+       (void)state;
+
+       result = PULL_LE_U8(data, 0);
+       assert_int_equal(result, 0);
+
+       data[0] = 0x2a;
+       result = PULL_LE_U8(data, 0);
+       assert_int_equal(result, 42);
+
+
+       data[0] = 0xf;
+       result = PULL_LE_U8(data, 0);
+       assert_int_equal(result, 0xf);
+
+       data[0] = 0xff;
+       result = PULL_LE_U8(data, 0);
+       assert_int_equal(result, 0xff);
+
+       data[1] = 0x2a;
+       result = PULL_LE_U8(data, 1);
+       assert_int_equal(result, 42);
+}
+
+static void torture_pull_le_u16(void **state)
+{
+       uint8_t data[2] = {0, 0};
+       uint16_t result;
+
+       (void)state;
+
+       result = PULL_LE_U16(data, 0);
+       assert_int_equal(result, 0);
+
+       data[0] = 0x2a;
+       data[1] = 0x00;
+       result = PULL_LE_U16(data, 0);
+       assert_int_equal(result, 42);
+
+       data[0] = 0xff;
+       data[1] = 0x00;
+       result = PULL_LE_U16(data, 0);
+       assert_int_equal(result, 0x00ff);
+
+       data[0] = 0x00;
+       data[1] = 0xff;
+       result = PULL_LE_U16(data, 0);
+       assert_int_equal(result, 0xff00);
+
+       data[0] = 0xff;
+       data[1] = 0xff;
+       result = PULL_LE_U16(data, 0);
+       assert_int_equal(result, 0xffff);
+}
+
+static void torture_pull_le_u32(void **state)
+{
+       uint8_t data[4] = {0, 0, 0, 0};
+       uint32_t result;
+
+       (void)state;
+
+       result = PULL_LE_U32(data, 0);
+       assert_int_equal(result, 0);
+
+       data[0] = 0x2a;
+       data[1] = 0x00;
+       data[2] = 0x00;
+       data[3] = 0x00;
+       result = PULL_LE_U32(data, 0);
+       assert_int_equal(result, 42);
+
+       data[0] = 0xff;
+       data[1] = 0x00;
+       data[2] = 0x00;
+       data[3] = 0x00;
+       result = PULL_LE_U32(data, 0);
+       assert_int_equal(result, 0x00ff);
+
+       data[0] = 0x00;
+       data[1] = 0xff;
+       data[2] = 0x00;
+       data[3] = 0x00;
+       result = PULL_LE_U32(data, 0);
+       assert_int_equal(result, 0xff00);
+
+       data[0] = 0x00;
+       data[1] = 0x00;
+       data[2] = 0xff;
+       data[3] = 0x00;
+       result = PULL_LE_U32(data, 0);
+       assert_int_equal(result, 0xff0000);
+
+       data[0] = 0x00;
+       data[1] = 0x00;
+       data[2] = 0x00;
+       data[3] = 0xff;
+       result = PULL_LE_U32(data, 0);
+       assert_int_equal(result, 0xff000000);
+
+       data[0] = 0xff;
+       data[1] = 0xff;
+       data[2] = 0xff;
+       data[3] = 0xff;
+       result = PULL_LE_U32(data, 0);
+       assert_int_equal(result, 0xffffffff);
+}
+
+static void torture_push_le_u8(void **state)
+{
+       uint8_t data[4] = {0, 0, 0, 0};
+       uint8_t data2[4] = {42, 42, 42, 42};
+
+       (void)state;
+
+       PUSH_LE_U8(data, 0, 42);
+       PUSH_LE_U8(data, 1, 42);
+       PUSH_LE_U8(data, 2, 42);
+       PUSH_LE_U8(data, 3, 42);
+       assert_memory_equal(data, data2, sizeof(data));
+}
+
+static void torture_push_le_u16(void **state)
+{
+       uint8_t data[4] = {0, 0, 0, 0};
+       uint8_t data2[4] = {0xa6, 0x7f, 0x2a, 0x00};
+       uint16_t result;
+
+       (void)state;
+
+       PUSH_LE_U16(data, 0, 32678);
+       PUSH_LE_U16(data, 2, 42);
+       assert_memory_equal(data, data2, sizeof(data));
+
+       result = PULL_LE_U16(data, 2);
+       assert_int_equal(result, 42);
+
+       result = PULL_LE_U16(data, 0);
+       assert_int_equal(result, 32678);
+}
+
+static void torture_push_le_u32(void **state)
+{
+       uint8_t data[8] = {0};
+       uint8_t data2[8] = {0xa6, 0x7f, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00};
+       uint32_t result;
+
+       (void)state;
+
+       PUSH_LE_U32(data, 0, 32678);
+       PUSH_LE_U32(data, 4, 42);
+       assert_memory_equal(data, data2, sizeof(data));
+
+       result = PULL_LE_U32(data, 4);
+       assert_int_equal(result, 42);
+
+       result = PULL_LE_U32(data, 0);
+       assert_int_equal(result, 32678);
+
+       PUSH_LE_U32(data, 0, 0xfffefffe);
+       result = PULL_LE_U32(data, 0);
+       assert_int_equal(result, 0xfffefffe);
+}
+
+static void torture_push_le_u64(void **state)
+{
+       uint8_t data[16] = {0};
+       uint64_t result;
+
+       (void)state;
+
+       PUSH_LE_U64(data, 0, 32678);
+
+       result = PULL_LE_U64(data, 0);
+       assert_int_equal(result, 32678);
+
+       PUSH_LE_U64(data, 0, 0xfffefffefffefffeUL);
+
+       result = PULL_LE_U64(data, 0);
+       assert_int_equal(result, 0xfffefffefffefffeUL);
+}
+
+/****************** BIG ENDIAN ********************/
+
+static void torture_pull_be_u8(void **state)
+{
+       uint8_t data[2] = {0};
+       uint8_t result;
+
+       (void)state;
+
+       result = PULL_BE_U8(data, 0);
+       assert_int_equal(result, 0);
+
+       data[0] = 0x2a;
+       result = PULL_BE_U8(data, 0);
+       assert_int_equal(result, 42);
+
+
+       data[0] = 0xf;
+       result = PULL_BE_U8(data, 0);
+       assert_int_equal(result, 0xf);
+
+       data[0] = 0xff;
+       result = PULL_BE_U8(data, 0);
+       assert_int_equal(result, 0xff);
+
+       data[1] = 0x2a;
+       result = PULL_BE_U8(data, 1);
+       assert_int_equal(result, 42);
+}
+
+static void torture_pull_be_u16(void **state)
+{
+       uint8_t data[2] = {0, 0};
+       uint16_t result;
+
+       (void)state;
+
+       result = PULL_BE_U16(data, 0);
+       assert_int_equal(result, 0);
+
+       data[0] = 0x00;
+       data[1] = 0x2a;
+       result = PULL_BE_U16(data, 0);
+       assert_int_equal(result, 42);
+
+       data[0] = 0x00;
+       data[1] = 0xff;
+       result = PULL_BE_U16(data, 0);
+       assert_int_equal(result, 0x00ff);
+
+       data[0] = 0xff;
+       data[1] = 0x00;
+       result = PULL_BE_U16(data, 0);
+       assert_int_equal(result, 0xff00);
+
+       data[0] = 0xff;
+       data[1] = 0xff;
+       result = PULL_BE_U16(data, 0);
+       assert_int_equal(result, 0xffff);
+}
+
+static void torture_pull_be_u32(void **state)
+{
+       uint8_t data[4] = {0, 0, 0, 0};
+       uint32_t result;
+
+       (void)state;
+
+       result = PULL_BE_U32(data, 0);
+       assert_int_equal(result, 0);
+
+       data[0] = 0x00;
+       data[1] = 0x00;
+       data[2] = 0x00;
+       data[3] = 0x2a;
+       result = PULL_BE_U32(data, 0);
+       assert_int_equal(result, 42);
+
+       data[0] = 0x00;
+       data[1] = 0x00;
+       data[2] = 0x00;
+       data[3] = 0xff;
+       result = PULL_BE_U32(data, 0);
+       assert_int_equal(result, 0x00ff);
+
+       data[0] = 0x00;
+       data[1] = 0x00;
+       data[2] = 0xff;
+       data[3] = 0x00;
+       result = PULL_BE_U32(data, 0);
+       assert_int_equal(result, 0xff00);
+
+       data[0] = 0x00;
+       data[1] = 0xff;
+       data[2] = 0x00;
+       data[3] = 0x00;
+       result = PULL_BE_U32(data, 0);
+       assert_int_equal(result, 0xff0000);
+
+       data[0] = 0xff;
+       data[1] = 0x00;
+       data[2] = 0x00;
+       data[3] = 0x00;
+       result = PULL_BE_U32(data, 0);
+       assert_int_equal(result, 0xff000000);
+
+       data[0] = 0xff;
+       data[1] = 0xff;
+       data[2] = 0xff;
+       data[3] = 0xff;
+       result = PULL_BE_U32(data, 0);
+       assert_int_equal(result, 0xffffffff);
+}
+
+static void torture_push_be_u8(void **state)
+{
+       uint8_t data[4] = {0, 0, 0, 0};
+       uint8_t data2[4] = {42, 42, 42, 42};
+
+       (void)state;
+
+       PUSH_BE_U8(data, 0, 42);
+       PUSH_BE_U8(data, 1, 42);
+       PUSH_BE_U8(data, 2, 42);
+       PUSH_BE_U8(data, 3, 42);
+       assert_memory_equal(data, data2, sizeof(data));
+}
+
+static void torture_push_be_u16(void **state)
+{
+       uint8_t data[4] = {0, 0, 0, 0};
+       uint8_t data2[4] = {0x7f, 0xa6, 0x00, 0x2a};
+       uint16_t result;
+
+       (void)state;
+
+       PUSH_BE_U16(data, 0, 32678);
+       PUSH_BE_U16(data, 2, 42);
+       assert_memory_equal(data, data2, sizeof(data));
+
+       result = PULL_BE_U16(data, 2);
+       assert_int_equal(result, 42);
+
+       result = PULL_BE_U16(data, 0);
+       assert_int_equal(result, 32678);
+}
+
+static void torture_push_be_u32(void **state)
+{
+       uint8_t data[8] = {0};
+       uint8_t data2[8] = {0x00, 0x00, 0x7f, 0xa6, 0x00, 0x00, 0x00, 0x2a};
+       uint32_t result;
+
+       (void)state;
+
+       PUSH_BE_U32(data, 0, 32678);
+       PUSH_BE_U32(data, 4, 42);
+       assert_memory_equal(data, data2, sizeof(data));
+
+       result = PULL_BE_U32(data, 4);
+       assert_int_equal(result, 42);
+
+       result = PULL_BE_U32(data, 0);
+       assert_int_equal(result, 32678);
+
+       PUSH_BE_U32(data, 0, 0xfffefffe);
+       result = PULL_BE_U32(data, 0);
+       assert_int_equal(result, 0xfffefffe);
+}
+
+static void torture_push_be_u64(void **state)
+{
+       uint8_t data[16] = {0};
+       uint64_t result;
+
+       (void)state;
+
+       PUSH_BE_U64(data, 0, 32678);
+
+       result = PULL_BE_U64(data, 0);
+       assert_int_equal(result, 32678);
+
+       PUSH_LE_U64(data, 8, 0xfffefffe);
+
+       result = PULL_LE_U64(data, 8);
+       assert_int_equal(result, 0xfffefffe);
+}
+
+int main(int argc, char *argv[])
+{
+       int rc;
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(torture_pull_le_u8),
+               cmocka_unit_test(torture_pull_le_u16),
+               cmocka_unit_test(torture_pull_le_u32),
+
+               cmocka_unit_test(torture_push_le_u8),
+               cmocka_unit_test(torture_push_le_u16),
+               cmocka_unit_test(torture_push_le_u32),
+               cmocka_unit_test(torture_push_le_u64),
+
+               /* BIG ENDIAN */
+               cmocka_unit_test(torture_pull_be_u8),
+               cmocka_unit_test(torture_pull_be_u16),
+               cmocka_unit_test(torture_pull_be_u32),
+
+               cmocka_unit_test(torture_push_be_u8),
+               cmocka_unit_test(torture_push_be_u16),
+               cmocka_unit_test(torture_push_be_u32),
+               cmocka_unit_test(torture_push_be_u64),
+       };
+
+       if (argc == 2) {
+               cmocka_set_test_filter(argv[1]);
+       }
+       cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+       rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+       return rc;
+}
index a827eea3ed946d3fa1ad467e948b1ba96ab7b5d9..f181e82fa3abf4d9159e29624df30b8797fc5dec 100644 (file)
@@ -154,6 +154,7 @@ else:
                   public_deps='talloc tevent execinfo pthread LIBCRYPTO charset util_setid',
                   public_headers='''
                                  attr.h
+                                 bytearray.h
                                  byteorder.h
                                  data_blob.h
                                  debug.h
@@ -288,3 +289,9 @@ else:
                      deps='cmocka replace samba-util',
                      local_include=False,
                      for_selftest=True)
+
+    bld.SAMBA_BINARY('test_bytearray',
+                     source='tests/test_bytearray.c',
+                     deps='cmocka replace samba-util',
+                     local_include=False,
+                     for_selftest=True)
index 96d3f8d631771ada9689969f5cbf7dfe05408a2a..a15a53848972d7ade90d93f415b821fb8a73ef68 100644 (file)
@@ -389,6 +389,8 @@ plantestsuite("samba.unittests.ms_fnmatch", "none",
               [os.path.join(bindir(), "default/lib/util/test_ms_fnmatch")])
 plantestsuite("samba.unittests.byteorder", "none",
               [os.path.join(bindir(), "default/lib/util/test_byteorder")])
+plantestsuite("samba.unittests.bytearray", "none",
+              [os.path.join(bindir(), "default/lib/util/test_bytearray")])
 plantestsuite("samba.unittests.ntlm_check", "none",
               [os.path.join(bindir(), "default/libcli/auth/test_ntlm_check")])
 plantestsuite("samba.unittests.gnutls", "none",