File indexing completed on 2024-05-12 17:15:22

0001 /*
0002    Copyright (C) 2016 Andreas Hartmetz <ahartmetz@gmail.com>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LGPL.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 
0019    Alternatively, this file is available under the Mozilla Public License
0020    Version 1.1.  You may obtain a copy of the License at
0021    http://www.mozilla.org/MPL/
0022 */
0023 
0024 #include "arguments.h"
0025 
0026 #include "../testutil.h"
0027 
0028 #include <cstring>
0029 #include <iostream>
0030 
0031 static void test_arrayLength()
0032 {
0033     const uint32 maxInt32Count = Arguments::MaxArrayLength / sizeof(uint32);
0034     for (int i = 0; i < 2; i++) {
0035         const bool withVariant = i == 1;
0036         {
0037             Arguments::Writer writer;
0038             if (withVariant) {
0039                 writer.beginVariant();
0040             }
0041             writer.beginArray();
0042             for (uint32 j = 0; j < maxInt32Count; j++) {
0043                 writer.writeUint32(j);
0044             }
0045             writer.endArray();
0046             if (withVariant) {
0047                 TEST(writer.state() != Arguments::InvalidData);
0048                 writer.endVariant();
0049             }
0050             Arguments arg = writer.finish();
0051             TEST(writer.state() == Arguments::Finished);
0052         }
0053         {
0054             Arguments::Writer writer;
0055             if (withVariant) {
0056                 writer.beginVariant();
0057             }
0058             writer.beginArray();
0059             for (uint32 j = 0; j < maxInt32Count + 1; j++) {
0060                 writer.writeUint32(j);
0061             }
0062             writer.endArray();
0063             if (withVariant) {
0064                 TEST(writer.state() != Arguments::InvalidData);
0065                 writer.endVariant();
0066             }
0067             TEST(writer.state() == Arguments::InvalidData);
0068         }
0069     }
0070 
0071     // Note: No need to test dicts, they are implemented pretty much like arrays regarding limits
0072 
0073     // The following two tests are overspecific to the implementation - it can only "guess" the full final
0074     // message size because it simply isn't known in the ArgumentList. Still better than nothing.
0075     {
0076         Arguments::Writer writer;
0077         for (uint32 i = 0; i < 2; i++) {
0078             writer.beginArray();
0079             // -2 because array length prefix adds one uint32 per array, and we must also subtract
0080             // (signature + alignment padding to 8 byte boundary), i.e. 8 bytes, / 2 = one more
0081             // sizeof(uint32) per array.
0082             for (uint32 j = 0; j < maxInt32Count - 2; j++) {
0083                 writer.writeUint32(j);
0084             }
0085             writer.endArray();
0086         }
0087         TEST(writer.state() != Arguments::InvalidData);
0088         Arguments arg = writer.finish();
0089         TEST(writer.state() == Arguments::Finished);
0090     }
0091     {
0092         Arguments::Writer writer;
0093         for (uint32 i = 0; i < 2; i++) {
0094             writer.beginArray();
0095             for (uint32 j = 0; j < maxInt32Count - 1; j++) {
0096                 writer.writeUint32(j);
0097             }
0098             writer.endArray();
0099         }
0100         writer.writeByte(123); // one byte too many!
0101         TEST(writer.state() != Arguments::InvalidData);
0102         Arguments arg = writer.finish();
0103         TEST(writer.state() == Arguments::InvalidData);
0104     }
0105 }
0106 
0107 static void test_argumentsLength()
0108 {
0109     static const uint32 bufferSize = Arguments::MaxArrayLength + 1024;
0110     byte *buffer = static_cast<byte *>(malloc(bufferSize));
0111     memset(buffer, 0, bufferSize);
0112 
0113     // Gross max length violations should be caught early
0114     for (int i = 0; i < 2; i++) {
0115         const bool withVariant = i == 1;
0116 
0117         Arguments::Writer writer;
0118         for (int j = 0; j < 4; j++) {
0119             if (withVariant) {
0120                 writer.beginVariant();
0121                 writer.beginStruct();
0122             }
0123             writer.writePrimitiveArray(Arguments::Byte, chunk(buffer, Arguments::MaxArrayLength));
0124             if (j == 1) {
0125                 // Now just over max size. Require the length check in Writer to be lenient before
0126                 // finish() - that is expected of the current implementation.
0127                 if (withVariant) {
0128                     for (int k = 0; k <= j; k++) {
0129                         writer.endStruct();
0130                         writer.endVariant();
0131                     }
0132                 }
0133                 Arguments::Writer writer2(writer);
0134                 TEST(writer2.state() != Arguments::InvalidData);
0135                 writer2.finish();
0136                 TEST(writer2.state() == Arguments::InvalidData);
0137             }
0138         }
0139         TEST(writer.state() == Arguments::InvalidData);
0140     }
0141 
0142     // Test message size exactly at maximum and exactly 1 byte over
0143     for (int i = 0; i < 4; i++) {
0144         const bool makeTooLong = i & 1;
0145         const bool withVariant = i & 2;
0146 
0147         Arguments::Writer writer;
0148         // note: Arguments does not count Arguments::signature() length towards length
0149         uint32 left = Arguments::MaxMessageLength;
0150         writer.writePrimitiveArray(Arguments::Byte, chunk(buffer, Arguments::MaxArrayLength));
0151         left -= 2 * sizeof(uint32) + Arguments::MaxArrayLength; // sizeof(uint32): array length field
0152         if (withVariant) {
0153             left -= 3; // variant signature "s", no alignment before next element
0154         }
0155         writer.writePrimitiveArray(Arguments::Byte, chunk(buffer, left - 4));
0156         // Now there are exactly 4 bytes left to MaxMessageLength
0157 
0158         TEST(writer.state() != Arguments::InvalidData);
0159 
0160         if (withVariant) {
0161             writer.beginVariant();
0162         }
0163         // Write a signature because it requires no alignment and its size can be anything from 2 to 257
0164         if (makeTooLong) {
0165             writer.writeSignature(cstring("xxx")); // + one byte length prefix + null terminator = 5 bytes
0166         } else {
0167             writer.writeSignature(cstring("xx"));
0168         }
0169         if (withVariant) {
0170             writer.endVariant();
0171         }
0172         TEST(writer.state() != Arguments::InvalidData);
0173         writer.finish();
0174         if (makeTooLong) {
0175             TEST(writer.state() == Arguments::InvalidData);
0176         } else {
0177             TEST(writer.state() == Arguments::Finished);
0178         }
0179     }
0180 }
0181 
0182 int main(int, char *[])
0183 {
0184     test_arrayLength();
0185     test_argumentsLength();
0186     std::cout << "Passed!\n";
0187 }