issue 126: fwrite() failure with buffers straddling page boundaries during background AOF save
This commit is contained in:
Binary file not shown.
@@ -45,6 +45,7 @@ redis_WSACleanup WSACleanup = NULL;
|
||||
redis_WSAGetOverlappedResult WSAGetOverlappedResult = NULL;
|
||||
|
||||
// other API forwards
|
||||
redis_fwrite fdapi_fwrite = NULL;
|
||||
redis_setmode fdapi_setmode = NULL;
|
||||
redis_select select = NULL;
|
||||
redis_ntohl ntohl = NULL;
|
||||
@@ -906,6 +907,10 @@ int redis_setmode_impl(int fd,int mode) {
|
||||
return crtsetmode(fd,mode);
|
||||
}
|
||||
|
||||
size_t redis_fwrite_impl(const void * _Str, size_t _Size, size_t _Count, FILE * _File) {
|
||||
return crtfwrite(_Str, _Size, _Count, _File);
|
||||
}
|
||||
|
||||
auto f_select = dllfunctor_stdcall<int, int, fd_set*, fd_set*, fd_set*, const struct timeval*>("ws2_32.dll", "select");
|
||||
int redis_select_impl(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout) {
|
||||
try {
|
||||
@@ -1053,6 +1058,7 @@ private:
|
||||
inet_addr = redis_inet_addr_impl;
|
||||
gethostbyname = redis_gethostbyname_impl;
|
||||
inet_ntoa = redis_inet_ntoa_impl;
|
||||
fdapi_fwrite = redis_fwrite_impl;
|
||||
fdapi_setmode = redis_setmode_impl;
|
||||
WSASetLastError = redis_WSASetLastError_impl;
|
||||
WSAGetLastError = redis_WSAGetLastError_impl;
|
||||
|
||||
@@ -40,6 +40,7 @@ typedef int ssize_t;
|
||||
#define INCL_WINSOCK_API_PROTOTYPES 0 // Important! Do not include Winsock API definitions to avoid conflicts with API entry points defnied below.
|
||||
#include <WinSock2.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// the following are required to be defined before WS2tcpip is included.
|
||||
typedef void (*redis_WSASetLastError)(int iError);
|
||||
@@ -149,6 +150,7 @@ typedef BOOL (*redis_WSAGetOverlappedResult)(int rfd,LPWSAOVERLAPPED lpOverlappe
|
||||
|
||||
// other API forwards
|
||||
typedef int (*redis_setmode)(int fd,int mode);
|
||||
typedef size_t (*redis_fwrite)(const void * _Str, size_t _Size, size_t _Count, FILE * _File);
|
||||
|
||||
// API prototypes must match the unix implementation
|
||||
typedef int (*redis_socket)(int af,int type,int protocol);
|
||||
@@ -227,6 +229,7 @@ extern redis_getpeername getpeername;
|
||||
extern redis_getsockname getsockname;
|
||||
extern redis_ntohs ntohs;
|
||||
extern redis_setmode fdapi_setmode;
|
||||
extern redis_fwrite fdapi_fwrite;
|
||||
|
||||
extern redis_select select;
|
||||
extern redis_ntohl ntohl;
|
||||
@@ -250,6 +253,7 @@ int FDAPI_UpdateAcceptContext( int fd );
|
||||
#ifndef FDAPI_NOCRTREDEFS
|
||||
#define close(fd) fdapi_close(fd)
|
||||
#define setmode(fd,mode) fdapi_setmode(fd,mode)
|
||||
#define fwrite(Str, Size, Count, File) fdapi_fwrite(Str,Size,Count,File)
|
||||
#define _get_osfhandle(fd) fdapi_get_osfhandle(fd)
|
||||
|
||||
#define _INC_STAT_INL
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "Win32_fdapi_crt.h"
|
||||
#include <io.h>
|
||||
#include <stdlib.h>
|
||||
@@ -47,6 +48,25 @@ int crtsetmode(int fd, int mode) {
|
||||
return ::_setmode(fd, mode);
|
||||
}
|
||||
|
||||
size_t crtfwrite(const void * _Str, size_t _Size, size_t _Count, FILE * _File) {
|
||||
// fwrite() somehow locks its view of the buffer. If during a fork operation the buffer has not been loaded into the forkee's process space,
|
||||
// the VEH will be called to load the missing pages. Although the page gets loaded, fwrite() will not see the loaded page. The result is
|
||||
// that fwrite will fail with errno set to ERROR_INVALID_USER_BUFFER. The fix is to force the buffer into memory before fwrite(). This only
|
||||
// impacts wirites that straddle page boundaries.
|
||||
const intptr_t pageSize = 4096;
|
||||
char* p = (char*)_Str;
|
||||
char* pageStart = p - ((intptr_t)p % pageSize);
|
||||
char* pEnd = p + _Size;
|
||||
if ((intptr_t)(pEnd - pageStart) > pageSize) {
|
||||
for (size_t n = 0; n < _Size; n++) {
|
||||
char x = *((char*)_Str + n);
|
||||
}
|
||||
}
|
||||
|
||||
return ::fwrite(_Str, _Size, _Count, _File);
|
||||
}
|
||||
|
||||
|
||||
int crt_isatty(int fd) {
|
||||
return _isatty(fd);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <stdio.h>
|
||||
|
||||
int crt_close(int fd);
|
||||
int crt_read(int fd, void *buffer, unsigned int count);
|
||||
@@ -28,6 +29,7 @@ int crt_write(int fd, const void *buffer, unsigned int count);
|
||||
int crt_open(const char *filename, int oflag, int pmode);
|
||||
intptr_t crtget_osfhandle(int fd);
|
||||
int crtsetmode(int fd, int mode);
|
||||
size_t crtfwrite(const void * _Str, size_t _Size, size_t _Count, FILE * _File);
|
||||
int crt_isatty(int fd);
|
||||
int crt_access(const char *pathname, int mode);
|
||||
__int64 crt_lseek64(int fd, __int64 offset, int origin);
|
||||
@@ -54,7 +54,7 @@
|
||||
#include "rio.h"
|
||||
#include "util.h"
|
||||
#ifdef _WIN32
|
||||
//#include "win32fixes.h"
|
||||
#include "Win32_Interop\Win32_FDAPI.h"
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "redis.h"
|
||||
@@ -86,7 +86,6 @@ static off_t rioBufferTell(rio *r) {
|
||||
/* Returns 1 or 0 for success/failure. */
|
||||
static size_t rioFileWrite(rio *r, const void *buf, size_t len) {
|
||||
size_t retval;
|
||||
|
||||
retval = fwrite(buf,len,1,r->io.file.fp);
|
||||
r->io.file.buffered += (off_t)len;
|
||||
|
||||
|
||||
@@ -112,6 +112,10 @@
|
||||
#include "endianconv.h"
|
||||
#include "redisassert.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Win32_Interop\Win32_FDAPI.h"
|
||||
#endif
|
||||
|
||||
#define ZIP_END 255
|
||||
#define ZIP_BIGLEN 254
|
||||
|
||||
|
||||
Reference in New Issue
Block a user