mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	Fixed segmentation fault in DynamicJsonBuffer when memory allocation fails (issue #92)
				
					
				
			This commit is contained in:
		
							
								
								
									
										3
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| # http://clang.llvm.org/docs/ClangFormatStyleOptions.html | ||||
|  | ||||
| BasedOnStyle: Google | ||||
							
								
								
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| *.sh text eol=lf | ||||
| @@ -1,6 +1,11 @@ | ||||
| Arduino JSON: change log | ||||
| ======================== | ||||
|  | ||||
| v4.6 | ||||
| ---- | ||||
|  | ||||
| * Fixed segmentation fault in `DynamicJsonBuffer` when memory allocation fails (issue #92) | ||||
|  | ||||
| v4.5 | ||||
| ---- | ||||
|  | ||||
|   | ||||
| @@ -6,41 +6,12 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonBuffer.hpp" | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include "Internals/BlockJsonBuffer.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
|  | ||||
| // Forward declaration | ||||
| namespace Internals { | ||||
| struct DynamicJsonBufferBlock; | ||||
| } | ||||
|  | ||||
| // Implements a JsonBuffer with dynamic memory allocation. | ||||
| // You are strongly encouraged to consider using StaticJsonBuffer which is much | ||||
| // more suitable for embedded systems. | ||||
| class DynamicJsonBuffer : public JsonBuffer { | ||||
|  public: | ||||
|   DynamicJsonBuffer(); | ||||
|   ~DynamicJsonBuffer(); | ||||
|  | ||||
|   size_t size() const; | ||||
|  | ||||
|  protected: | ||||
|   virtual void* alloc(size_t bytes); | ||||
|  | ||||
|  private: | ||||
|   typedef Internals::DynamicJsonBufferBlock Block; | ||||
|  | ||||
|   static const size_t FIRST_BLOCK_CAPACITY = 32; | ||||
|  | ||||
|   static Block* createBlock(size_t capacity); | ||||
|  | ||||
|   inline bool canAllocInHead(size_t bytes) const; | ||||
|   inline void* allocInHead(size_t bytes); | ||||
|   inline void addNewBlock(); | ||||
|  | ||||
|   Block* _head; | ||||
| }; | ||||
| typedef Internals::BlockJsonBuffer<Internals::DefaultAllocator> | ||||
|     DynamicJsonBuffer; | ||||
| } | ||||
|   | ||||
							
								
								
									
										93
									
								
								include/ArduinoJson/Internals/BlockJsonBuffer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								include/ArduinoJson/Internals/BlockJsonBuffer.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../JsonBuffer.hpp" | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| class DefaultAllocator { | ||||
|  public: | ||||
|   void* allocate(size_t size) { return malloc(size); } | ||||
|   void deallocate(void* pointer) { free(pointer); } | ||||
| }; | ||||
|  | ||||
| template <typename TAllocator> | ||||
| class BlockJsonBuffer : public JsonBuffer { | ||||
|   struct Block; | ||||
|   struct EmptyBlock { | ||||
|     Block* next; | ||||
|     size_t capacity; | ||||
|     size_t size; | ||||
|   }; | ||||
|   struct Block : EmptyBlock { | ||||
|     uint8_t data[1]; | ||||
|   }; | ||||
|  | ||||
|  public: | ||||
|   BlockJsonBuffer() : _head(NULL) {} | ||||
|  | ||||
|   ~BlockJsonBuffer() { | ||||
|     Block* currentBlock = _head; | ||||
|  | ||||
|     while (currentBlock != NULL) { | ||||
|       Block* nextBlock = currentBlock->next; | ||||
|       _allocator.deallocate(currentBlock); | ||||
|       currentBlock = nextBlock; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   size_t size() const { | ||||
|     size_t total = 0; | ||||
|     for (const Block* b = _head; b; b = b->next) total += b->size; | ||||
|     return total; | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   virtual void* alloc(size_t bytes) { | ||||
|     return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   static const size_t FIRST_BLOCK_CAPACITY = 32; | ||||
|  | ||||
|   bool canAllocInHead(size_t bytes) const { | ||||
|     return _head != NULL && _head->size + bytes <= _head->capacity; | ||||
|   } | ||||
|  | ||||
|   void* allocInHead(size_t bytes) { | ||||
|     void* p = _head->data + _head->size; | ||||
|     _head->size += bytes; | ||||
|     return p; | ||||
|   } | ||||
|  | ||||
|   void* allocInNewBlock(size_t bytes) { | ||||
|     size_t capacity = FIRST_BLOCK_CAPACITY; | ||||
|     if (_head != NULL) capacity = _head->capacity * 2; | ||||
|     if (bytes > capacity) capacity = bytes; | ||||
|     if (!addNewBlock(capacity)) return NULL; | ||||
|     return allocInHead(bytes); | ||||
|   } | ||||
|  | ||||
|   bool addNewBlock(size_t capacity) { | ||||
|     size_t size = sizeof(EmptyBlock) + capacity; | ||||
|     Block* block = static_cast<Block*>(_allocator.allocate(size)); | ||||
|     if (block == NULL) return false; | ||||
|     block->capacity = capacity; | ||||
|     block->size = 0; | ||||
|     block->next = _head; | ||||
|     _head = block; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   Block* _head; | ||||
|   TAllocator _allocator; | ||||
| }; | ||||
| } | ||||
| } | ||||
| @@ -1,6 +1,5 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| ZIP="C:\Program Files\7-Zip\7z.exe" | ||||
| TAG=$(git describe) | ||||
| OUTPUT="ArduinoJson-$TAG.zip" | ||||
|  | ||||
| @@ -10,7 +9,7 @@ cd ../.. | ||||
| rm -f $OUTPUT | ||||
|  | ||||
| # create zip | ||||
| "$ZIP" a $OUTPUT \ | ||||
| 7z a $OUTPUT \ | ||||
| 	ArduinoJson/CHANGELOG.md \ | ||||
| 	ArduinoJson/examples \ | ||||
| 	ArduinoJson/include \ | ||||
|   | ||||
| @@ -1,79 +0,0 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include "../include/ArduinoJson/DynamicJsonBuffer.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| struct DynamicJsonBufferBlockWithoutData { | ||||
|   DynamicJsonBufferBlock* next; | ||||
|   size_t capacity; | ||||
|   size_t size; | ||||
| }; | ||||
|  | ||||
|  | ||||
| struct DynamicJsonBufferBlock : DynamicJsonBufferBlockWithoutData { | ||||
|   uint8_t data[1]; | ||||
| }; | ||||
| } | ||||
| } | ||||
|  | ||||
| using namespace ArduinoJson; | ||||
| using namespace ArduinoJson::Internals; | ||||
|  | ||||
| DynamicJsonBuffer::DynamicJsonBuffer() { | ||||
|   _head = createBlock(FIRST_BLOCK_CAPACITY); | ||||
| } | ||||
|  | ||||
| DynamicJsonBuffer::~DynamicJsonBuffer() { | ||||
|   Block* currentBlock = _head; | ||||
|  | ||||
|   while (currentBlock != NULL) { | ||||
|     Block* nextBlock = currentBlock->next; | ||||
|     free(currentBlock); | ||||
|     currentBlock = nextBlock; | ||||
|   } | ||||
| } | ||||
|  | ||||
| size_t DynamicJsonBuffer::size() const { | ||||
|   size_t total = 0; | ||||
|  | ||||
|   for (const Block* b = _head; b != NULL; b = b->next) { | ||||
|     total += b->size; | ||||
|   } | ||||
|  | ||||
|   return total; | ||||
| } | ||||
|  | ||||
| void* DynamicJsonBuffer::alloc(size_t bytes) { | ||||
|   if (!canAllocInHead(bytes)) addNewBlock(); | ||||
|   return allocInHead(bytes); | ||||
| } | ||||
|  | ||||
| bool DynamicJsonBuffer::canAllocInHead(size_t bytes) const { | ||||
|   return _head->size + bytes <= _head->capacity; | ||||
| } | ||||
|  | ||||
| void* DynamicJsonBuffer::allocInHead(size_t bytes) { | ||||
|   void* p = _head->data + _head->size; | ||||
|   _head->size += bytes; | ||||
|   return p; | ||||
| } | ||||
|  | ||||
| void DynamicJsonBuffer::addNewBlock() { | ||||
|   Block* block = createBlock(_head->capacity * 2); | ||||
|   block->next = _head; | ||||
|   _head = block; | ||||
| } | ||||
|  | ||||
| DynamicJsonBuffer::Block* DynamicJsonBuffer::createBlock(size_t capacity) { | ||||
|   size_t blkSize = sizeof(DynamicJsonBufferBlockWithoutData) + capacity; | ||||
|   Block* block = static_cast<Block*>(malloc(blkSize)); | ||||
|   block->capacity = capacity; | ||||
|   block->size = 0; | ||||
|   block->next = NULL; | ||||
|   return block; | ||||
| } | ||||
							
								
								
									
										37
									
								
								test/DynamicJsonBuffer_NoMemory_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								test/DynamicJsonBuffer_NoMemory_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| // Copyright Benoit Blanchon 2014-2015 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #include <ArduinoJson.h> | ||||
|  | ||||
| class DynamicJsonBuffer_NoMemory_Tests : public ::testing::Test { | ||||
|   class NoMemoryAllocator { | ||||
|    public: | ||||
|     void* allocate(size_t) { return NULL; } | ||||
|     void deallocate(void*) {} | ||||
|   }; | ||||
|  | ||||
|  protected: | ||||
|   Internals::BlockJsonBuffer<NoMemoryAllocator> _jsonBuffer; | ||||
| }; | ||||
|  | ||||
| TEST_F(DynamicJsonBuffer_NoMemory_Tests, CreateArray) { | ||||
|   ASSERT_FALSE(_jsonBuffer.createArray().success()); | ||||
| } | ||||
|  | ||||
| TEST_F(DynamicJsonBuffer_NoMemory_Tests, CreateObject) { | ||||
|   ASSERT_FALSE(_jsonBuffer.createObject().success()); | ||||
| } | ||||
|  | ||||
| TEST_F(DynamicJsonBuffer_NoMemory_Tests, ParseArray) { | ||||
|   char json[] = "[]"; | ||||
|   ASSERT_FALSE(_jsonBuffer.parseArray(json).success()); | ||||
| } | ||||
|  | ||||
| TEST_F(DynamicJsonBuffer_NoMemory_Tests, ParseObject) { | ||||
|   char json[] = "{}"; | ||||
|   ASSERT_FALSE(_jsonBuffer.parseObject(json).success()); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user