forked from bblanchon/ArduinoJson
Fixed memory alignment, which made ESP8266 crash (issue #104)
This commit is contained in:
@ -4,9 +4,10 @@ ArduinoJson: change log
|
||||
v5.0.2
|
||||
------
|
||||
|
||||
* Fixed Clang warning "register specifier is deprecated" (issue #102)
|
||||
* Fixed segmentation fault in `parseObject(String)` and `parseArray(String)`, when the
|
||||
`StaticJsonBuffer` is too small to hold a copy of the string (issue #104)
|
||||
`StaticJsonBuffer` is too small to hold a copy of the string
|
||||
* Fixed Clang warning "register specifier is deprecated" (issue #102)
|
||||
* Fixed memory alignment, which made ESP8266 crash (issue #104)
|
||||
* Fixed compilation on Visual Studio 2010 and 2012 (issue #107)
|
||||
|
||||
v5.0.1
|
||||
|
@ -63,7 +63,7 @@ class BlockJsonBuffer : public JsonBuffer {
|
||||
|
||||
void* allocInHead(size_t bytes) {
|
||||
void* p = _head->data + _head->size;
|
||||
_head->size += bytes;
|
||||
_head->size += round_size_up(bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -103,19 +103,33 @@ class JsonBuffer {
|
||||
// Return a pointer to the allocated memory or NULL if allocation fails.
|
||||
virtual void *alloc(size_t size) = 0;
|
||||
|
||||
protected:
|
||||
// Preserve aligment if nessary
|
||||
static FORCE_INLINE size_t round_size_up(size_t bytes) {
|
||||
#if defined ARDUINO_ARCH_AVR
|
||||
// alignment isn't needed for 8-bit AVR
|
||||
return bytes;
|
||||
#else
|
||||
const size_t x = sizeof(void *) - 1;
|
||||
return (bytes + x) & ~x;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
char *strdup(const char *, size_t);
|
||||
|
||||
// Default value of nesting limit of parseArray() and parseObject().
|
||||
//
|
||||
// The nesting limit is a contain on the level of nesting allowed in the JSON
|
||||
// The nesting limit is a contain on the level of nesting allowed in the
|
||||
// JSON
|
||||
// string.
|
||||
// If set to 0, only a flat array or objects can be parsed.
|
||||
// If set to 1, the object can contain nested arrays or objects but only 1
|
||||
// level deep.
|
||||
// And bigger values will allow more level of nesting.
|
||||
//
|
||||
// The purpose of this feature is to prevent stack overflow that could lead to
|
||||
// The purpose of this feature is to prevent stack overflow that could
|
||||
// lead to
|
||||
// a security risk.
|
||||
static const uint8_t DEFAULT_LIMIT = 10;
|
||||
};
|
||||
|
@ -21,11 +21,10 @@ class StaticJsonBuffer : public JsonBuffer {
|
||||
size_t capacity() const { return CAPACITY; }
|
||||
size_t size() const { return _size; }
|
||||
|
||||
protected:
|
||||
virtual void* alloc(size_t bytes) {
|
||||
if (_size + bytes > CAPACITY) return NULL;
|
||||
void* p = &_buffer[_size];
|
||||
_size += bytes;
|
||||
_size += round_size_up(bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,9 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
||||
|
||||
TEST_F(DynamicJsonBuffer_Basic_Tests, SizeIncreasesAfterAlloc) {
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(1, buffer.size());
|
||||
ASSERT_LE(1, buffer.size());
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(2, buffer.size());
|
||||
ASSERT_LE(2, buffer.size());
|
||||
}
|
||||
|
||||
TEST_F(DynamicJsonBuffer_Basic_Tests, ReturnDifferentPointer) {
|
||||
@ -32,3 +32,12 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, ReturnDifferentPointer) {
|
||||
void* p2 = buffer.alloc(2);
|
||||
ASSERT_NE(p1, p2);
|
||||
}
|
||||
|
||||
TEST_F(DynamicJsonBuffer_Basic_Tests, Alignment) {
|
||||
size_t mask = sizeof(void*) - 1;
|
||||
|
||||
for (size_t size = 1; size <= sizeof(void*); size++) {
|
||||
size_t addr = reinterpret_cast<size_t>(buffer.alloc(1));
|
||||
ASSERT_EQ(0, addr & mask);
|
||||
}
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#define ARDUINOJSON_ENABLE_STD_STREAM
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#define SOURCE "{\"mqtt.host\":\"mqtt.test.com\",\"mqtt.port\":1883}"
|
||||
|
||||
#define SIZE_WITH_COPY (sizeof(SOURCE) + JSON_OBJECT_SIZE(2))
|
||||
#define SIZE_WITHOUT_COPY (JSON_OBJECT_SIZE(2))
|
||||
|
||||
template <int N, typename S>
|
||||
void mustSucceedWith(S source) {
|
||||
StaticJsonBuffer<N> jsonBuffer;
|
||||
ASSERT_TRUE(jsonBuffer.parseObject(source).success());
|
||||
}
|
||||
|
||||
template <int N, typename S>
|
||||
void mustFailWith(S source) {
|
||||
StaticJsonBuffer<N> jsonBuffer;
|
||||
ASSERT_FALSE(jsonBuffer.parseObject(source).success());
|
||||
}
|
||||
|
||||
TEST(Issue104, CharPtrSucceeds) {
|
||||
char source[] = SOURCE;
|
||||
mustSucceedWith<SIZE_WITHOUT_COPY, char *>(source);
|
||||
}
|
||||
|
||||
TEST(Issue104, CharPtrFails) {
|
||||
char source[] = SOURCE;
|
||||
mustFailWith<SIZE_WITHOUT_COPY - 1, char *>(source);
|
||||
}
|
||||
|
||||
TEST(Issue104, ConstCharPtrSucceeds) {
|
||||
mustSucceedWith<SIZE_WITH_COPY, const char *>(SOURCE);
|
||||
}
|
||||
|
||||
TEST(Issue104, ConstCharPtrFails) {
|
||||
mustFailWith<SIZE_WITH_COPY - 1, const char *>(SOURCE);
|
||||
}
|
||||
|
||||
TEST(Issue104, StringSucceeds) {
|
||||
mustSucceedWith<SIZE_WITH_COPY, const String &>(SOURCE);
|
||||
}
|
||||
|
||||
TEST(Issue104, StringFails) {
|
||||
mustFailWith<SIZE_WITH_COPY - 1, const String &>(SOURCE);
|
||||
}
|
||||
|
||||
TEST(Issue104, TooSmallForStrDup) {
|
||||
mustFailWith<sizeof(SOURCE) - 1, const char *>(SOURCE);
|
||||
}
|
@ -13,11 +13,11 @@ using namespace ArduinoJson;
|
||||
|
||||
class StaticJsonBuffer_Basic_Tests : public testing::Test {
|
||||
protected:
|
||||
StaticJsonBuffer<42> buffer;
|
||||
StaticJsonBuffer<64> buffer;
|
||||
};
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, CapacityMatchTemplateParameter) {
|
||||
ASSERT_EQ(42, buffer.capacity());
|
||||
ASSERT_EQ(64, buffer.capacity());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
||||
@ -26,34 +26,43 @@ TEST_F(StaticJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, GrowsAfterAlloc) {
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(1, buffer.size());
|
||||
ASSERT_LE(1, buffer.size());
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(2, buffer.size());
|
||||
ASSERT_LE(2, buffer.size());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, DoesntGrowWhenFull) {
|
||||
buffer.alloc(42);
|
||||
buffer.alloc(64);
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(42, buffer.size());
|
||||
ASSERT_EQ(64, buffer.size());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, DoesntGrowWhenTooSmall) {
|
||||
buffer.alloc(43);
|
||||
buffer.alloc(65);
|
||||
ASSERT_EQ(0, buffer.size());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNonNull) {
|
||||
void *p = buffer.alloc(42);
|
||||
void *p = buffer.alloc(64);
|
||||
ASSERT_NE(static_cast<void *>(0), p);
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNullWhenFull) {
|
||||
buffer.alloc(42);
|
||||
buffer.alloc(64);
|
||||
void *p = buffer.alloc(1);
|
||||
ASSERT_EQ(NULL, p);
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNullWhenTooSmall) {
|
||||
void *p = buffer.alloc(43);
|
||||
void *p = buffer.alloc(65);
|
||||
ASSERT_EQ(NULL, p);
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, Alignment) {
|
||||
size_t mask = sizeof(void *) - 1;
|
||||
|
||||
for (size_t size = 1; size <= sizeof(void *); size++) {
|
||||
size_t addr = reinterpret_cast<size_t>(buffer.alloc(1));
|
||||
ASSERT_EQ(0, addr & mask);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user