diff options
Diffstat (limited to 'methods/rred.cc')
-rw-r--r-- | methods/rred.cc | 156 |
1 files changed, 88 insertions, 68 deletions
diff --git a/methods/rred.cc b/methods/rred.cc index 981364a9e..f53f05ad5 100644 --- a/methods/rred.cc +++ b/methods/rred.cc @@ -7,12 +7,15 @@ #include <config.h> +#ifndef APT_EXCLUDE_RRED_METHOD_CODE #include "aptmethod.h" #include <apt-pkg/configuration.h> +#include <apt-pkg/init.h> +#endif + #include <apt-pkg/error.h> #include <apt-pkg/fileutl.h> #include <apt-pkg/hashes.h> -#include <apt-pkg/init.h> #include <apt-pkg/strutl.h> #include <apt-private/private-cmndline.h> @@ -23,7 +26,7 @@ #include <vector> #include <stddef.h> -#include <assert.h> +#include <cassert> #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -33,7 +36,9 @@ #include <apti18n.h> -#define BLOCK_SIZE (512*1024) +#ifndef APT_MEMBLOCK_SIZE +#define APT_MEMBLOCK_SIZE (512*1024) +#endif static bool ShowHelp(CommandLine &) { @@ -66,9 +71,9 @@ class MemBlock { char *start; size_t size; char *free; - MemBlock *next; + MemBlock *next = nullptr; - explicit MemBlock(size_t size) : size(size), next(NULL) + explicit MemBlock(size_t size) : size(size) { free = start = new char[size]; } @@ -77,11 +82,7 @@ class MemBlock { public: - MemBlock(void) { - free = start = new char[BLOCK_SIZE]; - size = BLOCK_SIZE; - next = NULL; - } + MemBlock() : MemBlock(APT_MEMBLOCK_SIZE) {} ~MemBlock() { delete [] start; @@ -100,11 +101,9 @@ class MemBlock { for (MemBlock *k = this; k; k = k->next) { if (k->free == last) { if (len <= k->avail()) { - char *n = k->add(src, len); - assert(last == n); - if (last == n) - return NULL; - return n; + char * const n = k->add(src, len); + assert(last == n); // we checked already that the block is big enough, so a new one shouldn't be used + return (last == n) ? nullptr : n; } else { break; } @@ -119,10 +118,10 @@ class MemBlock { char *add(char *src, size_t len) { if (len > avail()) { if (!next) { - if (len > BLOCK_SIZE) { + if (len > APT_MEMBLOCK_SIZE) { next = new MemBlock(len); } else { - next = new MemBlock; + next = new MemBlock(); } } return next->add(src, len); @@ -155,24 +154,27 @@ struct Change { } /* actually, don't write <lines> lines from <add> */ - void skip_lines(size_t lines) + bool skip_lines(size_t lines) { while (lines > 0) { char *s = (char*) memchr(add, '\n', add_len); - assert(s != NULL); + if (s == nullptr) + return _error->Error("No line left in add_len data to skip (1)"); s++; add_len -= (s - add); add_cnt--; lines--; if (add_len == 0) { - add = NULL; - assert(add_cnt == 0); - assert(lines == 0); + add = nullptr; + if (add_cnt != 0 || lines != 0) + return _error->Error("No line left in add_len data to skip (2)"); } else { add = s; - assert(add_cnt > 0); + if (add_cnt == 0) + return _error->Error("No line left in add_len data to skip (3)"); } } + return true; } }; @@ -183,7 +185,8 @@ class FileChanges { bool pos_is_okay(void) const { -#ifdef POSDEBUG +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // this isn't unsafe, it is just a moderately expensive check we want to avoid normally size_t cpos = 0; std::list<struct Change>::const_iterator x; for (x = changes.begin(); x != where; ++x) { @@ -208,33 +211,40 @@ class FileChanges { std::list<struct Change>::reverse_iterator rbegin(void) { return changes.rbegin(); } std::list<struct Change>::reverse_iterator rend(void) { return changes.rend(); } - void add_change(Change c) { + bool add_change(Change c) { assert(pos_is_okay()); - go_to_change_for(c.offset); - assert(pos + where->offset == c.offset); + if (not go_to_change_for(c.offset) || + pos + where->offset != c.offset) + return false; if (c.del_cnt > 0) - delete_lines(c.del_cnt); - assert(pos + where->offset == c.offset); + if (not delete_lines(c.del_cnt)) + return false; + if (pos + where->offset != c.offset) + return false; if (c.add_len > 0) { assert(pos_is_okay()); if (where->add_len > 0) - new_change(); - assert(where->add_len == 0 && where->add_cnt == 0); + if (not new_change()) + return false; + if (where->add_len != 0 || where->add_cnt != 0) + return false; where->add_len = c.add_len; where->add_cnt = c.add_cnt; where->add = c.add; } assert(pos_is_okay()); - merge(); - assert(pos_is_okay()); + if (not merge()) + return false; + return pos_is_okay(); } private: - void merge(void) + bool merge(void) { while (where->offset == 0 && where != changes.begin()) { - left(); + if (not left()) + return false; } std::list<struct Change>::iterator next = where; ++next; @@ -253,53 +263,56 @@ class FileChanges { ++next; } } + return true; } - void go_to_change_for(size_t line) + bool go_to_change_for(size_t line) { while(where != changes.end()) { if (line < pos) { - left(); + if (not left()) + return false; continue; } if (pos + where->offset + where->add_cnt <= line) { - right(); + if (not right()) + return false; continue; } // line is somewhere in this slot if (line < pos + where->offset) { break; } else if (line == pos + where->offset) { - return; + return true; } else { - split(line - pos); - right(); - return; + if (not split(line - pos)) + return false; + return right(); } } /* it goes before this patch */ - insert(line-pos); + return insert(line-pos); } - void new_change(void) { insert(where->offset); } + bool new_change(void) { return insert(where->offset); } - void insert(size_t offset) + bool insert(size_t offset) { assert(pos_is_okay()); - assert(where == changes.end() || offset <= where->offset); + if (where != changes.end() && offset > where->offset) + return false; if (where != changes.end()) where->offset -= offset; changes.insert(where, Change(offset)); --where; - assert(pos_is_okay()); + return pos_is_okay(); } - void split(size_t offset) + bool split(size_t offset) { assert(pos_is_okay()); - - assert(where->offset < offset); - assert(offset < where->offset + where->add_cnt); + if (where->offset >= offset || offset >= where->offset + where->add_cnt) + return false; size_t keep_lines = offset - where->offset; @@ -307,27 +320,29 @@ class FileChanges { where->del_cnt = 0; where->offset = 0; - where->skip_lines(keep_lines); + if (not where->skip_lines(keep_lines)) + return false; before.add_cnt = keep_lines; before.add_len -= where->add_len; changes.insert(where, before); --where; - assert(pos_is_okay()); + return pos_is_okay(); } - void delete_lines(size_t cnt) + bool delete_lines(size_t cnt) { - std::list<struct Change>::iterator x = where; assert(pos_is_okay()); + std::list<struct Change>::iterator x = where; while (cnt > 0) { size_t del; del = x->add_cnt; if (del > cnt) del = cnt; - x->skip_lines(del); + if (not x->skip_lines(del)) + return false; cnt -= del; ++x; @@ -342,21 +357,21 @@ class FileChanges { where->del_cnt += del; cnt -= del; } - assert(pos_is_okay()); + return pos_is_okay(); } - void left(void) { + bool left(void) { assert(pos_is_okay()); --where; pos -= where->offset + where->add_cnt; - assert(pos_is_okay()); + return pos_is_okay(); } - void right(void) { + bool right(void) { assert(pos_is_okay()); pos += where->offset + where->add_cnt; ++where; - assert(pos_is_okay()); + return pos_is_okay(); } }; @@ -378,7 +393,7 @@ class Patch { static void dump_rest(FileFd &o, FileFd &i, Hashes * const start_hash, Hashes * const end_hash) { - char buffer[BLOCK_SIZE]; + char buffer[APT_MEMBLOCK_SIZE]; unsigned long long l = 0; while (i.Read(buffer, sizeof(buffer), &l)) { if (l ==0 || !retry_fwrite(buffer, l, o, start_hash, end_hash)) @@ -389,7 +404,7 @@ class Patch { static void dump_lines(FileFd &o, FileFd &i, size_t n, Hashes * const start_hash, Hashes * const end_hash) { - char buffer[BLOCK_SIZE]; + char buffer[APT_MEMBLOCK_SIZE]; while (n > 0) { if (i.ReadLine(buffer, sizeof(buffer)) == NULL) buffer[0] = '\0'; @@ -402,7 +417,7 @@ class Patch { static void skip_lines(FileFd &i, int n, Hashes * const start_hash) { - char buffer[BLOCK_SIZE]; + char buffer[APT_MEMBLOCK_SIZE]; while (n > 0) { if (i.ReadLine(buffer, sizeof(buffer)) == NULL) buffer[0] = '\0'; @@ -422,7 +437,7 @@ class Patch { bool read_diff(FileFd &f, Hashes * const h) { - char buffer[BLOCK_SIZE]; + char buffer[APT_MEMBLOCK_SIZE]; bool cmdwanted = true; Change ch(std::numeric_limits<size_t>::max()); @@ -478,7 +493,8 @@ class Patch { ch.add = NULL; ch.add_cnt = 0; ch.add_len = 0; - filechanges.add_change(ch); + if (not filechanges.add_change(ch)) + return _error->Error("Parsing patchfile %s failed: Delete command could not be added to changes", f.Name().c_str()); break; default: return _error->Error("Parsing patchfile %s failed: Unknown command", f.Name().c_str()); @@ -486,7 +502,8 @@ class Patch { } else { /* !cmdwanted */ if (strcmp(buffer, ".\n") == 0) { cmdwanted = true; - filechanges.add_change(ch); + if (not filechanges.add_change(ch)) + return _error->Error("Parsing patchfile %s failed: Data couldn't be added for command (1)", f.Name().c_str()); } else { char *last = NULL; char *add; @@ -500,7 +517,8 @@ class Patch { ch.add_cnt++; } else { if (ch.add) { - filechanges.add_change(ch); + if (not filechanges.add_change(ch)) + return _error->Error("Parsing patchfile %s failed: Data couldn't be added for command (2)", f.Name().c_str()); ch.del_cnt = 0; } ch.offset += ch.add_cnt; @@ -575,6 +593,7 @@ class Patch { } }; +#ifndef APT_EXCLUDE_RRED_METHOD_CODE class RredMethod : public aptMethod { private: bool Debug; @@ -859,3 +878,4 @@ int main(int argc, const char *argv[]) input.Close(); return DispatchCommandLine(CmdL, {}); } +#endif |