Repository: couchdb-couch
Updated Branches:
  refs/heads/master 49774f269 -> 23f188096


Raise exception on attempt of reading beyound end of file


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/89990e18
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/89990e18
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/89990e18

Branch: refs/heads/master
Commit: 89990e1800934823b83341152d2a103cd4bcad8b
Parents: 49774f2
Author: Eric Avdey <e...@eiri.ca>
Authored: Mon May 16 10:15:38 2016 -0300
Committer: Eric Avdey <e...@eiri.ca>
Committed: Mon May 16 16:48:13 2016 -0300

----------------------------------------------------------------------
 src/couch_file.erl        | 16 ++++++++++++----
 test/couch_file_tests.erl | 19 ++++++++++++++++---
 2 files changed, 28 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/89990e18/src/couch_file.erl
----------------------------------------------------------------------
diff --git a/src/couch_file.erl b/src/couch_file.erl
index eb5c22e..4bb8be8 100644
--- a/src/couch_file.erl
+++ b/src/couch_file.erl
@@ -20,6 +20,7 @@
 -define(INITIAL_WAIT, 60000).
 -define(MONITOR_CHECK, 10000).
 -define(SIZE_BLOCK, 16#1000). % 4 KiB
+-define(READ_AHEAD, 2 * ?SIZE_BLOCK).
 
 
 -record(file, {
@@ -413,8 +414,10 @@ handle_call(close, _From, #file{fd=Fd}=File) ->
 handle_call({pread_iolist, Pos}, _From, File) ->
     {RawData, NextPos} = try
         % up to 8Kbs of read ahead
-        read_raw_iolist_int(File, Pos, 2 * ?SIZE_BLOCK - (Pos rem ?SIZE_BLOCK))
+        read_raw_iolist_int(File, Pos, ?READ_AHEAD - (Pos rem ?SIZE_BLOCK))
     catch
+    throw:read_beyond_eof ->
+        throw(read_beyond_eof);
     _:_ ->
         read_raw_iolist_int(File, Pos, 4)
     end,
@@ -550,11 +553,16 @@ maybe_read_more_iolist(Buffer, DataSize, NextPos, File) ->
     {Data::iolist(), CurPos::non_neg_integer()}.
 read_raw_iolist_int(Fd, {Pos, _Size}, Len) -> % 0110 UPGRADE CODE
     read_raw_iolist_int(Fd, Pos, Len);
-read_raw_iolist_int(#file{fd = Fd}, Pos, Len) ->
+read_raw_iolist_int(#file{fd = Fd} = F, Pos, Len) ->
     BlockOffset = Pos rem ?SIZE_BLOCK,
     TotalBytes = calculate_total_read_len(BlockOffset, Len),
-    {ok, <<RawBin:TotalBytes/binary>>} = file:pread(Fd, Pos, TotalBytes),
-    {remove_block_prefixes(BlockOffset, RawBin), Pos + TotalBytes}.
+    case Pos + TotalBytes of
+    Size when Size > F#file.eof + ?READ_AHEAD ->
+        throw(read_beyond_eof);
+    Size ->
+        {ok, <<RawBin:TotalBytes/binary>>} = file:pread(Fd, Pos, TotalBytes),
+        {remove_block_prefixes(BlockOffset, RawBin), Size}
+    end.
 
 -spec extract_md5(iolist()) -> {binary(), iolist()}.
 extract_md5(FullIoList) ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/89990e18/test/couch_file_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_file_tests.erl b/test/couch_file_tests.erl
index 27e0414..24edf46 100644
--- a/test/couch_file_tests.erl
+++ b/test/couch_file_tests.erl
@@ -24,7 +24,10 @@ setup() ->
     Fd.
 
 teardown(Fd) ->
-    ok = couch_file:close(Fd).
+    case is_process_alive(Fd) of
+        true -> ok = couch_file:close(Fd);
+        false -> ok
+    end.
 
 open_close_test_() ->
     {
@@ -126,8 +129,18 @@ should_read_iolist(Fd) ->
 should_fsync(Fd) ->
     {"How does on test fsync?", ?_assertMatch(ok, couch_file:sync(Fd))}.
 
-should_not_read_beyond_eof(_) ->
-    {"No idea how to test reading beyond EOF", ?_assert(true)}.
+should_not_read_beyond_eof(Fd) ->
+    BigBin = list_to_binary(lists:duplicate(100000, 0)),
+    DoubleBin = round(byte_size(BigBin) * 2),
+    {ok, Pos, _Size} = couch_file:append_binary(Fd, BigBin),
+    {_, Filepath} = couch_file:process_info(Fd),
+    %% corrupt db file
+    {ok, Io} = file:open(Filepath, [read, write, binary]),
+    ok = file:pwrite(Io, Pos, <<0:1/integer, DoubleBin:31/integer>>),
+    file:close(Io),
+    unlink(Fd),
+    ExpectedError = {badmatch, {'EXIT', {bad_return_value, read_beyond_eof}}},
+    ?_assertError(ExpectedError, couch_file:pread_binary(Fd, Pos)).
 
 should_truncate(Fd) ->
     {ok, 0, _} = couch_file:append_term(Fd, foo),

Reply via email to