mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +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 | Arduino JSON: change log | ||||||
| ======================== | ======================== | ||||||
|  |  | ||||||
|  | v4.6 | ||||||
|  | ---- | ||||||
|  |  | ||||||
|  | * Fixed segmentation fault in `DynamicJsonBuffer` when memory allocation fails (issue #92) | ||||||
|  |  | ||||||
| v4.5 | v4.5 | ||||||
| ---- | ---- | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,41 +6,12 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "JsonBuffer.hpp" | #include "Internals/BlockJsonBuffer.hpp" | ||||||
|  |  | ||||||
| #include <stdlib.h> |  | ||||||
|  |  | ||||||
| namespace ArduinoJson { | namespace ArduinoJson { | ||||||
|  |  | ||||||
| // Forward declaration |  | ||||||
| namespace Internals { |  | ||||||
| struct DynamicJsonBufferBlock; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Implements a JsonBuffer with dynamic memory allocation. | // Implements a JsonBuffer with dynamic memory allocation. | ||||||
| // You are strongly encouraged to consider using StaticJsonBuffer which is much | // You are strongly encouraged to consider using StaticJsonBuffer which is much | ||||||
| // more suitable for embedded systems. | // more suitable for embedded systems. | ||||||
| class DynamicJsonBuffer : public JsonBuffer { | typedef Internals::BlockJsonBuffer<Internals::DefaultAllocator> | ||||||
|  public: |     DynamicJsonBuffer; | ||||||
|   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; |  | ||||||
| }; |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										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 | #!/bin/bash | ||||||
|  |  | ||||||
| ZIP="C:\Program Files\7-Zip\7z.exe" |  | ||||||
| TAG=$(git describe) | TAG=$(git describe) | ||||||
| OUTPUT="ArduinoJson-$TAG.zip" | OUTPUT="ArduinoJson-$TAG.zip" | ||||||
|  |  | ||||||
| @@ -10,7 +9,7 @@ cd ../.. | |||||||
| rm -f $OUTPUT | rm -f $OUTPUT | ||||||
|  |  | ||||||
| # create zip | # create zip | ||||||
| "$ZIP" a $OUTPUT \ | 7z a $OUTPUT \ | ||||||
| 	ArduinoJson/CHANGELOG.md \ | 	ArduinoJson/CHANGELOG.md \ | ||||||
| 	ArduinoJson/examples \ | 	ArduinoJson/examples \ | ||||||
| 	ArduinoJson/include \ | 	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