gems/vfs.h: make 'File_content' more robust

This patch addresses two problems: By guarding the buffer allocation in
a nested class, an exception in the body of the 'File_content'
constructor reverts the allocation. Second, if the file has no content
no allocation should be performed. The previous version wrongly passed
a size of zero to the allocator in this case.
This commit is contained in:
Norman Feske 2018-08-21 14:05:22 +02:00 committed by Christian Helmuth
parent 89d0d648ed
commit 3976a43c84

View File

@ -426,16 +426,26 @@ class Genode::File_content
{ {
private: private:
Allocator &_alloc; class Buffer
size_t const _size; {
private:
char *_buffer = (char *)_alloc.alloc(_size);
/* /*
* Noncopyable * Noncopyable
*/ */
File_content(File_content const &); Buffer(Buffer const &);
File_content &operator = (File_content const &); Buffer &operator = (Buffer const &);
public:
Allocator &alloc;
size_t const size;
char * const ptr = size ? (char *)alloc.alloc(size) : nullptr;
Buffer(Allocator &alloc, size_t size) : alloc(alloc), size(size) { }
~Buffer() { if (ptr) alloc.free(ptr, size); }
} _buffer;
public: public:
@ -456,15 +466,12 @@ class Genode::File_content
File_content(Allocator &alloc, Directory const &dir, Path const &rel_path, File_content(Allocator &alloc, Directory const &dir, Path const &rel_path,
Limit limit) Limit limit)
: :
_alloc(alloc), _buffer(alloc, min(dir.file_size(rel_path), (Vfs::file_size)limit.value))
_size(min(dir.file_size(rel_path), (Vfs::file_size)limit.value))
{ {
if (Readonly_file(dir, rel_path).read(_buffer, _size) != _size) if (Readonly_file(dir, rel_path).read(_buffer.ptr, _buffer.size) != _buffer.size)
throw Truncated_during_read(); throw Truncated_during_read();
} }
~File_content() { _alloc.free(_buffer, _size); }
/** /**
* Call functor 'fn' with content as 'Xml_node' argument * Call functor 'fn' with content as 'Xml_node' argument
* *
@ -474,7 +481,7 @@ class Genode::File_content
template <typename FN> template <typename FN>
void xml(FN const &fn) const void xml(FN const &fn) const
{ {
try { fn(Xml_node(_buffer, _size)); } try { fn(Xml_node(_buffer.ptr, _buffer.size)); }
catch (Xml_node::Invalid_syntax) { fn(Xml_node("<empty/>")); } catch (Xml_node::Invalid_syntax) { fn(Xml_node("<empty/>")); }
} }
@ -486,14 +493,14 @@ class Genode::File_content
template <typename STRING, typename FN> template <typename STRING, typename FN>
void for_each_line(FN const &fn) const void for_each_line(FN const &fn) const
{ {
char const *src = _buffer; char const *src = _buffer.ptr;
char const *curr_line = src; char const *curr_line = src;
size_t curr_line_len = 0; size_t curr_line_len = 0;
for (size_t n = 0; ; n++) { for (size_t n = 0; ; n++) {
char const c = *src++; char const c = *src++;
bool const end_of_data = (c == 0 || n == _size); bool const end_of_data = (c == 0 || n == _buffer.size);
bool const end_of_line = (c == '\n'); bool const end_of_line = (c == '\n');
if (!end_of_data && !end_of_line) { if (!end_of_data && !end_of_line) {
@ -516,7 +523,7 @@ class Genode::File_content
* Call functor 'fn' with the data pointer and size in bytes * Call functor 'fn' with the data pointer and size in bytes
*/ */
template <typename FN> template <typename FN>
void bytes(FN const &fn) const { fn((char const *)_buffer, _size); } void bytes(FN const &fn) const { fn((char const *)_buffer.ptr, _buffer.size); }
}; };