8000 JsonArray::remove() and JsonObject::remove() now release the memory o… · java64/ArduinoJson@f375459 · GitHub
[go: up one dir, main page]

Skip to content

Commit f375459

Browse files
committed
JsonArray::remove() and JsonObject::remove() now release the memory of strings
1 parent e842838 commit f375459

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1502
-738
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ HEAD
88
* Removed `JsonObject::is<T>(k)` and `JsonObject::set(k,v)`
99
* Replaced `T JsonArray::get<T>(i)` with `JsonVariant JsonArray::get(i)`
1010
* Replaced `T JsonObject::get<T>(k)` with `JsonVariant JsonObject::get(k)`
11-
* `JsonArray::remove()` and `JsonObject::remove()` now release the memory of the variant
11+
* `JsonArray::remove()` and `JsonObject::remove()` now release the memory
12+
* Added `JSON_STRING_SIZE()`
1213

1314
v6.5.0-beta (2018-10-13)
1415
-----------

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ if(${COVERAGE})
1111
set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
1212
endif()
1313

14+
add_definitions(-DARDUINOJSON_DEBUG)
15+
1416
include_directories(${CMAKE_CURRENT_LIST_DIR}/src)
1517
add_subdirectory(third-party/catch)
1618
add_subdirectory(test)

fuzzing/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# CAUTION: this file is invoked by https://github.com/google/oss-fuzz
22

3-
CXXFLAGS += -I../src
3+
CXXFLAGS += -I../src -DARDUINOJSON_DEBUG
44

55
all: \
66
$(OUT)/json_fuzzer \

fuzzing/fuzzer_main.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,34 @@
55
// This file is NOT use by Google's OSS fuzz
66
// I only use it to reproduce the bugs found
77

8-
#include <stdint.h>
9-
#include <fstream>
8+
#include <stdint.h> // size_t
9+
#include <stdio.h> // fopen et al.
10+
#include <stdlib.h> // exit
1011
#include <iostream>
11-
#include <string>
12+
#include <vector>
1213

1314
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
1415

15-
std::string read(const char* path) {
16-
std::ifstream file(path);
17-
return std::string(std::istreambuf_iterator<char>(file),
18-
std::istreambuf_iterator<char>());
16+
std::vector<uint8_t> read(const char* path) {
17+
FILE* f = fopen(path, "rb");
18+
if (!f) {
19+
std::cerr << "Failed to open " << path << st 111C d::endl;
20+
exit(1);
21+
}
22+
23+
fseek(f, 0, SEEK_END);
24+
size_t size = ftell(f);
25+
fseek(f, 0, SEEK_SET);
26+
27+
std::vector<uint8_t> buffer(size);
28+
if (fread(buffer.data(), 1, size, f) != size) {
29+
fclose(f);
30+
std::cerr << "Failed to read " << path << std::endl;
31+
exit(1);
32+
}
33+
34+
fclose(f);
35+
return buffer;
1936
}
2037

2138
int main(int argc, const char* argv[]) {
@@ -26,9 +43,8 @@ int main(int argc, const char* argv[]) {
2643

2744
for (int i = 1; i < argc; i++) {
2845
std::cout << "Loading " << argv[i] << std::endl;
29-
std::string buffer = read(argv[i]);
30-
LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t*>(buffer.data()),
31-
buffer.size());
46+
std::vector<uint8_t> buffer = read(argv[i]);
47+
LLVMFuzzerTestOneInput(buffer.data(), buffer.size());
3248
}
3349
return 0;
3450
}

src/ArduinoJson/Configuration.hpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,6 @@
130130
#endif
131131
#endif
132132

133-
#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
134-
#ifdef ARDUINO_ARCH_AVR
135-
// alignment isn't needed for 8-bit AVR
136-
#define ARDUINOJSON_ENABLE_ALIGNMENT 0
137-
#else
138-
// but most processors need pointers to be align on word size
139-
#define ARDUINOJSON_ENABLE_ALIGNMENT 1
140-
#endif
141-
#endif
142-
143133
// Control the exponentiation threshold for big numbers
144134
// CAUTION: cannot be more that 1e9 !!!!
145135
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD

src/ArduinoJson/Data/ArrayFunctions.hpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
#pragma once
66

77
#include "JsonVariantData.hpp"
8-
#include "Slot.hpp"
98
#include "SlotFunctions.hpp"
109

1110
namespace ARDUINOJSON_NAMESPACE {
1211

1312
inline JsonVariantData* arrayAdd(JsonArrayData* arr, MemoryPool* pool) {
1413
if (!arr) return 0;
1514

16-
Slot* slot = pool->allocSlot();
15+
VariantSlot* slot = pool->allocVariant();
1716
if (!slot) return 0;
1817

1918
slot->next = 0;
@@ -29,20 +28,22 @@ inline JsonVariantData* arrayAdd(JsonArrayData* arr, MemoryPool* pool) {
2928
arr->tail = slot;
3029
}
3130

31+
slot->value.keyIsOwned = false;
3232
return &slot->value;
3333
}
3434

35-
inline Slot* arrayGetSlot(const JsonArrayData* arr, size_t index) {
35+
inline VariantSlot* arrayGetSlot(const JsonArrayData* arr, size_t index) {
3636
if (!arr) return 0;
3737
return slotAdvance(arr->head, index);
3838
}
3939

4040
inline JsonVariantData* arrayGet(const JsonArrayData* arr, size_t index) {
41-
Slot* slot = arrayGetSlot(arr, index);
41+
VariantSlot* slot = arrayGetSlot(arr, index);
4242
return slot ? &slot->value : 0;
4343
}
4444

45-
inline void arrayRemove(JsonArrayData* arr, Slot* slot, MemoryPool* pool) {
45+
inline void arrayRemove(JsonArrayData* arr, VariantSlot* slot,
46+
MemoryPool* pool) {
4647
if (!arr || !slot) return;
4748

4849
if (slot->prev)
@@ -73,7 +74,7 @@ inline bool arrayCopy(JsonArrayData* dst, const JsonArrayData* src,
7374
MemoryPool* pool) {
7475
if (!dst || !src) return false;
7576
arrayClear(dst);
76-
for (Slot* s = src->head; s; s = s->next) {
77+
for (VariantSlot* s = src->head; s; s = s->next) {
7778
if (!variantCopy(arrayAdd(dst, pool), &s->value, pool)) return false;
7879
}
7980
return true;
@@ -84,8 +85,8 @@ bool variantEquals(const JsonVariantData*, const JsonVariantData*);
8485
inline bool arrayEquals(const JsonArrayData* a1, const JsonArrayData* a2) {
8586
if (a1 == a2) return true;
8687
if (!a1 || !a2) return false;
87-
Slot* s1 = a1->head;
88-
Slot* s2 = a2->head;
88+
VariantSlot* s1 = a1->head;
89+
VariantSlot* s2 = a2->head;
8990
for (;;) {
9091
if (s1 == s2) return true;
9192
if (!s1 || !s2) return false;

src/ArduinoJson/Data/JsonVariantData.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ enum JsonVariantType {
2626
};
2727

2828
struct JsonObjectData {
29-
struct Slot *head;
30-
struct Slot *tail;
29+
struct VariantSlot *head;
30+
struct VariantSlot *tail;
3131
};
3232

3333
struct JsonArrayData {
34-
struct Slot *head;
35-
struct Slot *tail;
34+
struct VariantSlot *head;
35+
struct VariantSlot *tail;
3636
};
3737

3838
struct RawData {
@@ -48,6 +48,8 @@ union JsonVariantContent {
4848
JsonArrayData asArray;
4949
JsonObjectData asObject;
5050
const char *asString;
51+
struct StringSlot *asOwnedString;
52+
struct StringSlot *asOwnedRaw;
5153
struct {
5254
const char *data;
5355
size_t size;
@@ -56,7 +58,7 @@ union JsonVariantContent {
5658

5759
// this struct must be a POD type to prevent error calling offsetof on clang
5860
struct JsonVariantData {
59-
bool keyIsStatic : 1;
61+
bool keyIsOwned : 1;
6062
JsonVariantType type : 7;
6163
JsonVariantContent content;
6264
};

src/ArduinoJson/Data/ObjectFunctions.hpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
namespace ARDUINOJSON_NAMESPACE {
1212

1313
template <typename TKey>
14-
inline Slot* objectFindSlot(const JsonObjectData* obj, TKey key) {
14+
inline VariantSlot* objectFindSlot(const JsonObjectData* obj, TKey key) {
1515
if (!obj) return 0;
16-
Slot* slot = obj->head;
16+
VariantSlot* slot = obj->head;
1717
while (slot) {
18-
if (key.equals(slot->key)) break;
18+
if (key.equals(slotGetKey(slot))) break;
1919
slot = slot->next;
2020
}
2121
return slot;
@@ -29,7 +29,7 @@ inline bool objectContainsKey(const JsonObjectData* obj, const TKey& key) {
2929
template <typename TKey>
3030
inline JsonVariantData* objectAdd(JsonObjectData* obj, TKey key,
3131
MemoryPool* pool) {
32-
Slot* slot = pool->allocSlot();
32+
VariantSlot* slot = pool->allocVariant();
3333
if (!slot) return 0;
3434

3535
slot->next = 0;
@@ -58,15 +58,15 @@ inline JsonVariantData* objectSet(JsonObjectData* obj, TKey key,
5858
if (key.isNull()) return 0;
5959

6060
// search a matching key
61-
Slot* slot = objectFindSlot(obj, key);
61+
VariantSlot* slot = objectFindSlot(obj, key);
6262
if (slot) return &slot->value;
6363

6464
return objectAdd(obj, key, pool);
6565
}
6666

6767
template <typename TKey>
6868
inline JsonVariantData* objectGet(const JsonObjectData* obj, TKey key) {
69-
Slot* slot = objectFindSlot(obj, key);
69+
VariantSlot* slot = objectFindSlot(obj, key);
7070
return slot ? &slot->value : 0;
7171
}
7272

@@ -76,7 +76,8 @@ inline void objectClear(JsonObjectData* obj) {
7676
obj->tail = 0;
7777
}
7878

79-
inline void objectRemove(JsonObjectData* obj, Slot* slot, MemoryPool* pool) {
79+
inline void objectRemove(JsonObjectData* obj, VariantSlot* slot,
80+
MemoryPool* pool) {
8081
if (!obj) return;
8182
if (!slot) return;
8283
if (slot->prev)
@@ -102,12 +103,12 @@ inline bool objectCopy(JsonObjectData* dst, const JsonObjectData* src,
102103
MemoryPool* pool) {
103104
if (!dst || !src) return false;
104105
objectClear(dst);
105-
for (Slot* s = src->head; s; s = s->next) {
106+
for (VariantSlot* s = src->head; s; s = s->next) {
106107
JsonVariantData* var;
107-
if (s->value.keyIsStatic)
108-
var = objectAdd(dst, ZeroTerminatedRamStringConst(s->key), pool);
108+
if (s->value.keyIsOwned)
109+
var = objectAdd(dst, ZeroTerminatedRamString(s->ownedKey->value), pool);
109110
else
110-
var = objectAdd(dst, ZeroTerminatedRamString(s->key), pool);
111+
var = objectAdd(dst, ZeroTerminatedRamStringConst(s->linkedKey), pool);
111112
if (!variantCopy(var, &s->value, pool)) return false;
112113
}
113114
return true;
@@ -117,9 +118,9 @@ inline bool objectEquals(const JsonObjectData* o1, const JsonObjectData* o2) {
117118
if (o1 == o2) return true;
118119
if (!o1 || !o2) return false;
119120

120-
for (Slot* s = o1->head; s; s = s->next) {
121+
for (VariantSlot* s = o1->head; s; s = s->next) {
121122
JsonVariantData* v1 = &s->value;
122-
JsonVariantData* v2 = objectGet(o2, makeString(s->key));
123+
JsonVariantData* v2 = objectGet(o2, makeString(slotGetKey(s)));
123124
if (!variantEquals(v1, v2)) return false;
124125
}
125126
return true;

src/ArduinoJson/Data/SlotFunctions.hpp

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,65 +7,80 @@
77
#include "../Memory/MemoryPool.hpp"
88
#include "../Strings/StringTypes.hpp"
99
#include "JsonVariantData.hpp"
10-
#include "Slot.hpp"
1110

1211
namespace ARDUINOJSON_NAMESPACE {
1312

1413
template <typename TKey>
15-
inline bool slotSetKey(Slot* slot, TKey key, MemoryPool* pool) {
16-
const char* dup = key.save(pool);
17-
if (!dup) return false;
18-
slot->key = dup;
19-
slot->value.keyIsStatic = false;
14+
inline bool slotSetKey(VariantSlot* var, TKey key, MemoryPool* pool) {
15+
StringSlot* slot = key.save(pool);
16+
if (!slot) return false;
17+
var->ownedKey = slot;
18+
var->value.keyIsOwned = true;
2019
return true;
2120
}
2221

23-
inline bool slotSetKey(Slot* slot, ZeroTerminatedRamStringConst key,
24-
MemoryPool* pool) {
25-
slot->key = key.save(pool);
26-
slot->value.keyIsStatic = true;
22+
inline bool slotSetKey(VariantSlot* var, ZeroTerminatedRamStringConst key,
23+
MemoryPool*) {
24+
var->linkedKey = key.c_str();
25+
var->value.keyIsOwned = false;
2726
return true;
2827
}
2928

30-
inline bool slotSetKey(Slot* slot, StringInMemoryPool key, MemoryPool* pool) {
31-
slot->key = key.save(pool);
32-
slot->value.keyIsStatic = false;
29+
inline bool slotSetKey(VariantSlot* var, StringInMemoryPool key, MemoryPool*) {
30+
var->ownedKey = key.slot();
31+
var->value.keyIsOwned = true;
3332
return true;
3433
}
3534

36-
inline const Slot* slotAdvance(const Slot* slot, size_t distance) {
37-
while (distance && slot) {
38-
slot = slot->next;
35+
inline const char* slotGetKey(const VariantSlot* var) {
36+
return var->value.keyIsOwned ? var->ownedKey->value : var->linkedKey;
37+
}
38+
39+
inline const VariantSlot* slotAdvance(const VariantSlot* var, size_t distance) {
40+
while (distance && var) {
41+
var = var->next;
3942
distance--;
4043
}
41-
return slot;
44+
return var;
4245
}
4346

44-
inline Slot* slotAdvance(Slot* slot, size_t distance) {
45-
while (distance && slot) {
46-
slot = slot->next;
47+
inline VariantSlot* slotAdvance(VariantSlot* var, size_t distance) {
48+
while (distance && var) {
49+
var = var->next;
4750
distance--;
4851
}
49-
return slot;
52+
return var;
5053
}
5154

52-
inline size_t slotSize(const Slot* slot) {
55+
inline size_t slotSize(const VariantSlot* var) {
5356
size_t n = 0;
54-
while (slot) {
57+
while (var) {
5558
n++;
56-
slot = slot->next;
59+
var = var->next;
5760
}
5861
return n;
5962
}
6063

61-
inline void slotFree(Slot* slot, MemoryPool* pool) {
62-
const JsonVariantData& v = slot->value;
63-
if (v.type == JSON_ARRAY || v.type == JSON_OBJECT) {
64-
for (Slot* s = v.content.asObject.head; s; s = s->next) {
65-
slotFree(s, pool);
66-
}
64+
inline void slotFree(VariantSlot* var, MemoryPool* pool) {
65+
const JsonVariantData& v = var->value;
66+
67+
switch (v.type) {
68+
case JSON_ARRAY:
69+
case JSON_OBJECT:
70+
for (VariantSlot* s = v.content.asObject.head; s; s = s->next) {
71+
slotFree(s, pool);
72+
}
73+
break;
74+
case JSON_OWNED_STRING:
75+
case JSON_OWNED_RAW:
76+
pool->freeString(v.content.asOwnedString);
77+
break;
78+
default:
79+
break;
6780
}
6881

69-
pool->freeSlot(slot);
82+
if (v.keyIsOwned) pool->freeString(var->ownedKey);
83+
84+
pool->freeVariant(var);
7085
}
7186
} // namespace ARDUINOJSON_NAMESPACE

0 commit comments

Comments
 (0)
0