Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Hej, I think the patch went in and out in git.git, please see below. (I coudn't the following in msysgit, but if it was there, the clipped_write() for Windows could go away. /Torsten commit 0b6806b9e45c659d25b87fb5713c920a3081eac8 Author: Steffen Prohaska Date: Tue Aug 20 08:43:54 2013 +0200 xread, xwrite: limit size of IO to 8MB Checking out 2GB or more through an external filter (see test) fails on Mac OS X 10.8.4 (12E55) for a 64-bit executable with: error: read from external filter cat failed error: cannot feed the input to external filter cat error: cat died of signal 13 error: external filter cat failed 141 error: external filter cat failed The reason is that read() immediately returns with EINVAL when asked to read more than 2GB. According to POSIX [1], if the value of nbyte passed to read() is greater than SSIZE_MAX, the result is implementation-defined. The write function has the same restriction [2]. Since OS X still supports running 32-bit executables, the 32-bit limit (SSIZE_MAX = INT_MAX = 2GB - 1) seems to be also imposed on 64-bit executables under certain conditions. For write, the problem has been addressed earlier [6c642a]. Address the problem for read() and write() differently, by limiting size of IO chunks unconditionally on all platforms in xread() and xwrite(). Large chunks only cause problems, like causing latencies when killing the process, even if OS X was not buggy. Doing IO in reasonably sized smaller chunks should have no negative impact on performance. The compat wrapper clipped_write() introduced earlier [6c642a] is not needed anymore. It will be reverted in a separate commit. The new test catches read and write problems. Note that 'git add' exits with 0 even if it prints filtering errors to stderr. The test, therefore, checks stderr. 'git add' should probably be changed (sometime in another commit) to exit with nonzero if filtering fails. The test could then be changed to use test_must_fail. On 2013-11-20 11.15, Erik Faye-Lund wrote: > I know I'm extremely late to the party, and this patch has already > landed, but... > > On Sat, May 11, 2013 at 1:05 AM, Junio C Hamano wrote: >> Filipe Cabecinhas writes: >> >>> Due to a bug in the Darwin kernel, write() calls have a maximum size of >>> INT_MAX bytes. >>> >>> This patch introduces a new compat function: clipped_write >>> This function behaves the same as write() but will write, at most, INT_MAX >>> characters. >>> It may be necessary to include this function on Windows, too. > > We are already doing something similar for Windows in mingw_write (see > compat/mingw.c), but with a much smaller size. > > It feels a bit pointless to duplicate this logic. > >> diff --git a/compat/clipped-write.c b/compat/clipped-write.c >> new file mode 100644 >> index 000..9183698 >> --- /dev/null >> +++ b/compat/clipped-write.c >> @@ -0,0 +1,13 @@ >> +#include >> +#include >> + >> +/* >> + * Version of write that will write at most INT_MAX bytes. >> + * Workaround a xnu bug on Mac OS X >> + */ >> +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte) >> +{ >> + if (nbyte > INT_MAX) >> + nbyte = INT_MAX; >> + return write(fildes, buf, nbyte); >> +} > > If we were to reuse this logic with Windows, we'd need to have some > way of overriding the max-size of the write. > -- > To unsubscribe from this list: send the line "unsubscribe git" in > the body of a message to majord...@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
I know I'm extremely late to the party, and this patch has already landed, but... On Sat, May 11, 2013 at 1:05 AM, Junio C Hamano wrote: > Filipe Cabecinhas writes: > >> Due to a bug in the Darwin kernel, write() calls have a maximum size of >> INT_MAX bytes. >> >> This patch introduces a new compat function: clipped_write >> This function behaves the same as write() but will write, at most, INT_MAX >> characters. >> It may be necessary to include this function on Windows, too. We are already doing something similar for Windows in mingw_write (see compat/mingw.c), but with a much smaller size. It feels a bit pointless to duplicate this logic. > diff --git a/compat/clipped-write.c b/compat/clipped-write.c > new file mode 100644 > index 000..9183698 > --- /dev/null > +++ b/compat/clipped-write.c > @@ -0,0 +1,13 @@ > +#include > +#include > + > +/* > + * Version of write that will write at most INT_MAX bytes. > + * Workaround a xnu bug on Mac OS X > + */ > +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte) > +{ > + if (nbyte > INT_MAX) > + nbyte = INT_MAX; > + return write(fildes, buf, nbyte); > +} If we were to reuse this logic with Windows, we'd need to have some way of overriding the max-size of the write. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Filipe Cabecinhas writes: > It compiles cleanly and runs. I'm running the test suite anyway, but > don't expect any change from your latest patch. Heh, I do not think we did write(2) of that many bytes in our test suite ;-) Thanks. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Hi Junio, It compiles cleanly and runs. I'm running the test suite anyway, but don't expect any change from your latest patch. Thank you, Filipe F On Fri, May 10, 2013 at 4:13 PM, Filipe Cabecinhas wrote: > Hi Junio, > > Thanks for helping. Your text is correct and only diffs from my patch > in the #define write(...) part, where I suppose you stripped the > spaced in the arglist. > > Thank you, > > Filipe > > F > > > On Fri, May 10, 2013 at 4:05 PM, Junio C Hamano wrote: >> Filipe Cabecinhas writes: >> >>> Due to a bug in the Darwin kernel, write() calls have a maximum size of >>> INT_MAX bytes. >>> >>> This patch introduces a new compat function: clipped_write >>> This function behaves the same as write() but will write, at most, INT_MAX >>> characters. >>> It may be necessary to include this function on Windows, too. >>> >>> Signed-off-by: Filipe Cabecinhas >>> --- >> >> Somehow your MUA seems to have lost _all_ tabs, not just in the new >> lines in your patch but also in the existing context lines. >> >>> diff --git a/Makefile b/Makefile >>> index 0f931a2..ccb8f3f 100644 >>> --- a/Makefile >>> +++ b/Makefile >>> @@ -1466,6 +1466,11 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS >>> MSGFMT += --check --statistics >>> endif >>> >>> +ifdef NEEDS_CLIPPED_WRITE >>> + BASIC_CFLAGS += -DNEEDS_CLIPPED_WRITE >>> + COMPAT_OBJS += compat/clipped-write.o >>> +endif >>> + >>> ... >> >> Here is what I resurrected and queued. I _think_ I did not make any >> silly mistake while transcribing from your whitespace-mangled patch, >> but please double check; I do not have any Darwin, so this hasn't >> even been compile tested. >> >> Also I have a small suggestion I'd like you to try on top of it, >> which I'll be sending in a separate message. >> >> Thanks. >> >> -- >8 -- >> From: Filipe Cabecinhas >> Date: Fri, 10 May 2013 15:24:57 -0700 >> Subject: [PATCH] compate/clipped-write.c: large write(2) fails on Mac OS >> X/XNU >> >> Due to a bug in the Darwin kernel, write(2) calls have a maximum size >> of INT_MAX bytes. >> >> Introduce a new compat function, clipped_write(), that only writes >> at most INT_MAX bytes and returns the number of bytes written, as >> a substitute for write(2), and allow platforms that need this to >> enable it from the build mechanism with NEEDS_CLIPPED_WRITE. >> >> Set it for Mac OS X by default. It may be necessary to include this >> function on Windows, too. >> >> Signed-off-by: Filipe Cabecinhas >> Signed-off-by: Junio C Hamano >> --- >> Makefile | 5 + >> compat/clipped-write.c | 13 + >> config.mak.uname | 1 + >> git-compat-util.h | 5 + >> 4 files changed, 24 insertions(+) >> create mode 100644 compat/clipped-write.c >> >> diff --git a/Makefile b/Makefile >> index 26d3332..7076b15 100644 >> --- a/Makefile >> +++ b/Makefile >> @@ -1463,6 +1463,11 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS >> MSGFMT += --check --statistics >> endif >> >> +ifdef NEEDS_CLIPPED_WRITE >> + BASIC_CFLAGS += -DNEEDS_CLIPPED_WRITE >> + COMPAT_OBJS += compat/clipped-write.o >> +endif >> + >> ifneq (,$(XDL_FAST_HASH)) >> BASIC_CFLAGS += -DXDL_FAST_HASH >> endif >> diff --git a/compat/clipped-write.c b/compat/clipped-write.c >> new file mode 100644 >> index 000..9183698 >> --- /dev/null >> +++ b/compat/clipped-write.c >> @@ -0,0 +1,13 @@ >> +#include >> +#include >> + >> +/* >> + * Version of write that will write at most INT_MAX bytes. >> + * Workaround a xnu bug on Mac OS X >> + */ >> +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte) >> +{ >> + if (nbyte > INT_MAX) >> + nbyte = INT_MAX; >> + return write(fildes, buf, nbyte); >> +} >> diff --git a/config.mak.uname b/config.mak.uname >> index e09af8f..e689a9a 100644 >> --- a/config.mak.uname >> +++ b/config.mak.uname >> @@ -95,6 +95,7 @@ ifeq ($(uname_S),Darwin) >> NO_MEMMEM = YesPlease >> USE_ST_TIMESPEC = YesPlease >> HAVE_DEV_TTY = YesPlease >> + NEEDS_CLIPPED_WRITE = YesPlease >> COMPAT_OBJS += compat/precompose_utf8.o >> BASIC_CFLAGS += -DPRECOMPOSE_UNICODE >> endif >> diff --git a/git-compat-util.h b/git-compat-util.h >> index b636e0d..3144b8d 100644 >> --- a/git-compat-util.h >> +++ b/git-compat-util.h >> @@ -181,6 +181,11 @@ typedef unsigned long uintptr_t; >> #define probe_utf8_pathname_composition(a,b) >> #endif >> >> +#ifdef NEEDS_CLIPPED_WRITE >> +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte); >> +#define write(x,y,z) clipped_write((x),(y),(z)) >> +#endif >> + >> #ifdef MKDIR_WO_TRAILING_SLASH >> #define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b)) >> extern int compat_mkdir_wo_trailing_slash(const char*, mode_t); >> -- >> 1.8.3-rc1-268-g30389da >> -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Hi Junio, Thanks for helping. Your text is correct and only diffs from my patch in the #define write(...) part, where I suppose you stripped the spaced in the arglist. Thank you, Filipe F On Fri, May 10, 2013 at 4:05 PM, Junio C Hamano wrote: > Filipe Cabecinhas writes: > >> Due to a bug in the Darwin kernel, write() calls have a maximum size of >> INT_MAX bytes. >> >> This patch introduces a new compat function: clipped_write >> This function behaves the same as write() but will write, at most, INT_MAX >> characters. >> It may be necessary to include this function on Windows, too. >> >> Signed-off-by: Filipe Cabecinhas >> --- > > Somehow your MUA seems to have lost _all_ tabs, not just in the new > lines in your patch but also in the existing context lines. > >> diff --git a/Makefile b/Makefile >> index 0f931a2..ccb8f3f 100644 >> --- a/Makefile >> +++ b/Makefile >> @@ -1466,6 +1466,11 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS >> MSGFMT += --check --statistics >> endif >> >> +ifdef NEEDS_CLIPPED_WRITE >> + BASIC_CFLAGS += -DNEEDS_CLIPPED_WRITE >> + COMPAT_OBJS += compat/clipped-write.o >> +endif >> + >> ... > > Here is what I resurrected and queued. I _think_ I did not make any > silly mistake while transcribing from your whitespace-mangled patch, > but please double check; I do not have any Darwin, so this hasn't > even been compile tested. > > Also I have a small suggestion I'd like you to try on top of it, > which I'll be sending in a separate message. > > Thanks. > > -- >8 -- > From: Filipe Cabecinhas > Date: Fri, 10 May 2013 15:24:57 -0700 > Subject: [PATCH] compate/clipped-write.c: large write(2) fails on Mac OS X/XNU > > Due to a bug in the Darwin kernel, write(2) calls have a maximum size > of INT_MAX bytes. > > Introduce a new compat function, clipped_write(), that only writes > at most INT_MAX bytes and returns the number of bytes written, as > a substitute for write(2), and allow platforms that need this to > enable it from the build mechanism with NEEDS_CLIPPED_WRITE. > > Set it for Mac OS X by default. It may be necessary to include this > function on Windows, too. > > Signed-off-by: Filipe Cabecinhas > Signed-off-by: Junio C Hamano > --- > Makefile | 5 + > compat/clipped-write.c | 13 + > config.mak.uname | 1 + > git-compat-util.h | 5 + > 4 files changed, 24 insertions(+) > create mode 100644 compat/clipped-write.c > > diff --git a/Makefile b/Makefile > index 26d3332..7076b15 100644 > --- a/Makefile > +++ b/Makefile > @@ -1463,6 +1463,11 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS > MSGFMT += --check --statistics > endif > > +ifdef NEEDS_CLIPPED_WRITE > + BASIC_CFLAGS += -DNEEDS_CLIPPED_WRITE > + COMPAT_OBJS += compat/clipped-write.o > +endif > + > ifneq (,$(XDL_FAST_HASH)) > BASIC_CFLAGS += -DXDL_FAST_HASH > endif > diff --git a/compat/clipped-write.c b/compat/clipped-write.c > new file mode 100644 > index 000..9183698 > --- /dev/null > +++ b/compat/clipped-write.c > @@ -0,0 +1,13 @@ > +#include > +#include > + > +/* > + * Version of write that will write at most INT_MAX bytes. > + * Workaround a xnu bug on Mac OS X > + */ > +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte) > +{ > + if (nbyte > INT_MAX) > + nbyte = INT_MAX; > + return write(fildes, buf, nbyte); > +} > diff --git a/config.mak.uname b/config.mak.uname > index e09af8f..e689a9a 100644 > --- a/config.mak.uname > +++ b/config.mak.uname > @@ -95,6 +95,7 @@ ifeq ($(uname_S),Darwin) > NO_MEMMEM = YesPlease > USE_ST_TIMESPEC = YesPlease > HAVE_DEV_TTY = YesPlease > + NEEDS_CLIPPED_WRITE = YesPlease > COMPAT_OBJS += compat/precompose_utf8.o > BASIC_CFLAGS += -DPRECOMPOSE_UNICODE > endif > diff --git a/git-compat-util.h b/git-compat-util.h > index b636e0d..3144b8d 100644 > --- a/git-compat-util.h > +++ b/git-compat-util.h > @@ -181,6 +181,11 @@ typedef unsigned long uintptr_t; > #define probe_utf8_pathname_composition(a,b) > #endif > > +#ifdef NEEDS_CLIPPED_WRITE > +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte); > +#define write(x,y,z) clipped_write((x),(y),(z)) > +#endif > + > #ifdef MKDIR_WO_TRAILING_SLASH > #define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b)) > extern int compat_mkdir_wo_trailing_slash(const char*, mode_t); > -- > 1.8.3-rc1-268-g30389da > -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Junio C Hamano writes: > Also I have a small suggestion I'd like you to try on top of it, > which I'll be sending in a separate message. The first hunk is to match other Makefile knobs the builders can tweak with minimum documentation. As you hinted that there may be other platforms that may want to use the clipped-write, I would prefer to see this file _not_ directly include any system headers, but let git-compat-util.h to absorb platform differences instead. Of course, inside this file, we do need to use the underlying write(2), so immediately after including the header, we #undef write so that this compilation unit will make a call to the platform implementation of the function. I do not expect the follow-up patch to Makefile to cause any problem, but I'd like to see the change to compat/clipped-write.c double checked on a real Mac OS X system, so that we can squash this patch into your original. Thanks. Makefile | 3 +++ compat/clipped-write.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7076b15..0434715 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,9 @@ all:: # Define NO_MSGFMT_EXTENDED_OPTIONS if your implementation of msgfmt # doesn't support GNU extensions like --check and --statistics # +# Define NEEDS_CLIPPED_WRITE if your write(2) cannot write more than +# INT_MAX bytes at once (e.g. MacOS X). +# # Define HAVE_PATHS_H if you have paths.h and want to use the default PATH # it specifies. # diff --git a/compat/clipped-write.c b/compat/clipped-write.c index 9183698..b8f98ff 100644 --- a/compat/clipped-write.c +++ b/compat/clipped-write.c @@ -1,5 +1,5 @@ -#include -#include +#include "../git-compat-util.h" +#undef write /* * Version of write that will write at most INT_MAX bytes. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Filipe Cabecinhas writes: > Due to a bug in the Darwin kernel, write() calls have a maximum size of > INT_MAX bytes. > > This patch introduces a new compat function: clipped_write > This function behaves the same as write() but will write, at most, INT_MAX > characters. > It may be necessary to include this function on Windows, too. > > Signed-off-by: Filipe Cabecinhas > --- Somehow your MUA seems to have lost _all_ tabs, not just in the new lines in your patch but also in the existing context lines. > diff --git a/Makefile b/Makefile > index 0f931a2..ccb8f3f 100644 > --- a/Makefile > +++ b/Makefile > @@ -1466,6 +1466,11 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS > MSGFMT += --check --statistics > endif > > +ifdef NEEDS_CLIPPED_WRITE > + BASIC_CFLAGS += -DNEEDS_CLIPPED_WRITE > + COMPAT_OBJS += compat/clipped-write.o > +endif > + > ... Here is what I resurrected and queued. I _think_ I did not make any silly mistake while transcribing from your whitespace-mangled patch, but please double check; I do not have any Darwin, so this hasn't even been compile tested. Also I have a small suggestion I'd like you to try on top of it, which I'll be sending in a separate message. Thanks. -- >8 -- From: Filipe Cabecinhas Date: Fri, 10 May 2013 15:24:57 -0700 Subject: [PATCH] compate/clipped-write.c: large write(2) fails on Mac OS X/XNU Due to a bug in the Darwin kernel, write(2) calls have a maximum size of INT_MAX bytes. Introduce a new compat function, clipped_write(), that only writes at most INT_MAX bytes and returns the number of bytes written, as a substitute for write(2), and allow platforms that need this to enable it from the build mechanism with NEEDS_CLIPPED_WRITE. Set it for Mac OS X by default. It may be necessary to include this function on Windows, too. Signed-off-by: Filipe Cabecinhas Signed-off-by: Junio C Hamano --- Makefile | 5 + compat/clipped-write.c | 13 + config.mak.uname | 1 + git-compat-util.h | 5 + 4 files changed, 24 insertions(+) create mode 100644 compat/clipped-write.c diff --git a/Makefile b/Makefile index 26d3332..7076b15 100644 --- a/Makefile +++ b/Makefile @@ -1463,6 +1463,11 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS MSGFMT += --check --statistics endif +ifdef NEEDS_CLIPPED_WRITE + BASIC_CFLAGS += -DNEEDS_CLIPPED_WRITE + COMPAT_OBJS += compat/clipped-write.o +endif + ifneq (,$(XDL_FAST_HASH)) BASIC_CFLAGS += -DXDL_FAST_HASH endif diff --git a/compat/clipped-write.c b/compat/clipped-write.c new file mode 100644 index 000..9183698 --- /dev/null +++ b/compat/clipped-write.c @@ -0,0 +1,13 @@ +#include +#include + +/* + * Version of write that will write at most INT_MAX bytes. + * Workaround a xnu bug on Mac OS X + */ +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte) +{ + if (nbyte > INT_MAX) + nbyte = INT_MAX; + return write(fildes, buf, nbyte); +} diff --git a/config.mak.uname b/config.mak.uname index e09af8f..e689a9a 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -95,6 +95,7 @@ ifeq ($(uname_S),Darwin) NO_MEMMEM = YesPlease USE_ST_TIMESPEC = YesPlease HAVE_DEV_TTY = YesPlease + NEEDS_CLIPPED_WRITE = YesPlease COMPAT_OBJS += compat/precompose_utf8.o BASIC_CFLAGS += -DPRECOMPOSE_UNICODE endif diff --git a/git-compat-util.h b/git-compat-util.h index b636e0d..3144b8d 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -181,6 +181,11 @@ typedef unsigned long uintptr_t; #define probe_utf8_pathname_composition(a,b) #endif +#ifdef NEEDS_CLIPPED_WRITE +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte); +#define write(x,y,z) clipped_write((x),(y),(z)) +#endif + #ifdef MKDIR_WO_TRAILING_SLASH #define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b)) extern int compat_mkdir_wo_trailing_slash(const char*, mode_t); -- 1.8.3-rc1-268-g30389da -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Due to a bug in the Darwin kernel, write() calls have a maximum size of INT_MAX bytes. This patch introduces a new compat function: clipped_write This function behaves the same as write() but will write, at most, INT_MAX characters. It may be necessary to include this function on Windows, too. Signed-off-by: Filipe Cabecinhas --- Makefile | 5 + compat/clipped-write.c | 13 + config.mak.uname | 1 + git-compat-util.h | 5 + 4 files changed, 24 insertions(+) create mode 100644 compat/clipped-write.c diff --git a/Makefile b/Makefile index 0f931a2..ccb8f3f 100644 --- a/Makefile +++ b/Makefile @@ -1466,6 +1466,11 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS MSGFMT += --check --statistics endif +ifdef NEEDS_CLIPPED_WRITE + BASIC_CFLAGS += -DNEEDS_CLIPPED_WRITE + COMPAT_OBJS += compat/clipped-write.o +endif + ifneq (,$(XDL_FAST_HASH)) BASIC_CFLAGS += -DXDL_FAST_HASH endif diff --git a/compat/clipped-write.c b/compat/clipped-write.c new file mode 100644 index 000..9183698 --- /dev/null +++ b/compat/clipped-write.c @@ -0,0 +1,13 @@ +#include +#include + +/* + * Version of write that will write at most INT_MAX bytes. + * Workaround a xnu bug on Mac OS X + */ +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte) +{ + if (nbyte > INT_MAX) + nbyte = INT_MAX; + return write(fildes, buf, nbyte); +} diff --git a/config.mak.uname b/config.mak.uname index d78fd3d..174703b 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -95,6 +95,7 @@ ifeq ($(uname_S),Darwin) NO_MEMMEM = YesPlease USE_ST_TIMESPEC = YesPlease HAVE_DEV_TTY = YesPlease + NEEDS_CLIPPED_WRITE = YesPlease COMPAT_OBJS += compat/precompose_utf8.o BASIC_CFLAGS += -DPRECOMPOSE_UNICODE endif diff --git a/git-compat-util.h b/git-compat-util.h index e955bb5..a96db23 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -185,6 +185,11 @@ int get_st_mode_bits(const char *path, int *mode); #define probe_utf8_pathname_composition(a,b) #endif +#ifdef NEEDS_CLIPPED_WRITE +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte); +#define write(x, y, z) clipped_write((x), (y), (z)) +#endif + #ifdef MKDIR_WO_TRAILING_SLASH #define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b)) extern int compat_mkdir_wo_trailing_slash(const char*, mode_t); -- 1.8.2.1.343.g13c32df -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Filipe Cabecinhas writes: > Sorry for the delay. I've updated the patch to work as you suggested (I > think). > It's attached. A few comments. First, the formalities. Please see Documentation/SubmittingPatches, notably: - Please do not send a patch as an attachment. - The attached patch does not seem to have any proposed commit log message. For this particular change, I expect it would not be more than a paragraph of several lines. Please have one. - Please sign-off your patch. Look at patches from other high-value contributors to learn the style and the tone of log message. For instance, http://article.gmane.org/gmane.comp.version-control.git/223406 is a good example (taken at random). > diff --git a/compat/write.c b/compat/write.c > new file mode 100644 > index 000..1e890aa > --- /dev/null > +++ b/compat/write.c > @@ -0,0 +1,11 @@ > +#include > +#include > + > +/* Version of write that will write at most INT_MAX bytes. > + * Workaround a xnu bug on Mac OS X */ /* * We format our multi-line comments like this. * * Nothing other than slash-asterisk/asterisk-slash * on the first and the last line of the comment block. */ > +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte) { > + if (nbyte > INT_MAX) > +return write(fildes, buf, INT_MAX); > + else > +return write(fildes, buf, nbyte); > +} Style: - opening and closing parentheses of the function body sit on lines on their own. - one level of indent is 8 places, using a tab. Perhaps it would look more like this (my MUA may clobber the tabs, though, before it gets to you): ssize_t clipped_write(int fildes, const void *buf, size_t nbyte) { if (nbyte > INT_MAX) nbyte = INT_MAX; return write(fildes, buf, nbyte); } I do not want to see this ffile called "write.c"; we will encounter a platform whose write(2) behaves a way that we do not expect but is different from this "clipped to INT_MAX" in the future. The way we will deal with such a platform is to add a workaround similar to this patch somewhere in the compat/ directory, but if you squat on "compat/write.c", it would be a problem for that platform, as it cannot call its version "compat/write.c". Perhaps call it "compat/clipped-write.c" or something. By the way, does your underlying write(2) correctly write INT_MAX bytes, or did you mean to clip at (INT_MAX-1)? Just double-checking. Other than that, the patch looks sensible to me. Thanks. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Hi Junio, Sorry for the delay. I've updated the patch to work as you suggested (I think). It's attached. Thank you, Filipe F On Tue, Apr 9, 2013 at 3:50 PM, Junio C Hamano wrote: > Filipe Cabecinhas writes: > >> >> Testing with dd bs=INT_MAX+1 count=1 also gets me an “Invalid >> argument” error, while bs=INT_MAX will do what's expected. >> >> I have a preliminary patch that fixes it, but it may not be the >> preferred way. The code is not ifdef'ed out and I'm doing the fix in >> write_in_full(), while it may be preferred to do the fix in xwrite(). >> >> A radar bug has been submitted to Apple about this, but I think git >> could tolerate the bug while it isn't fixed, by working around it. >> >> Thank you, >> >> Filipe >> >> diff --git a/wrapper.c b/wrapper.c >> index bac59d2..474d760 100644 >> --- a/wrapper.c >> +++ b/wrapper.c >> @@ -187,7 +187,12 @@ ssize_t write_in_full(int fd, const void *buf, size_t >> count) >> ssize_t total = 0; >> >> while (count > 0) { >> - ssize_t written = xwrite(fd, p, count); >> + ssize_t written = 0; >> +if (count >= INT_MAX) >> + written = xwrite(fd, p, INT_MAX-1); >> +else >> + written = xwrite(fd, p, count); > > I think it is better to fix it in much lower level of the stack, as > other codepaths would call write(2), either thru xwrite() or > directly. > > Ideally the fix should go to the lowest level, i.e. the write(2). I > do not care if it is done in the kernel or in the libc wrapping > code; the above does not belong to our code (in an ideal world, that > is). > > Otherwise you would have to patch everything in /usr/bin, no? > > But you do not live in an ideal world and neither do we. I think > the least ugly way may be to add compat/clipped-write.c that > implements a loop like the above in a helper function: > > ssize_t clipped_write(int, const void *, size_t); > > and have a > > #ifdef NEED_CLIPPED_WRITE > #define write(x,y,z) clipped_write((x),(y),(z)) > #endif > > in git-compat-util.h, or something. Makefile needs to get adjusted > to link with compat/clipped-write.o when NEED_CLIPPED_WRITE is > defined as well. git-big-write-darwin.patch Description: Binary data
Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Filipe Cabecinhas writes: > > Testing with dd bs=INT_MAX+1 count=1 also gets me an “Invalid > argument” error, while bs=INT_MAX will do what's expected. > > I have a preliminary patch that fixes it, but it may not be the > preferred way. The code is not ifdef'ed out and I'm doing the fix in > write_in_full(), while it may be preferred to do the fix in xwrite(). > > A radar bug has been submitted to Apple about this, but I think git > could tolerate the bug while it isn't fixed, by working around it. > > Thank you, > > Filipe > > diff --git a/wrapper.c b/wrapper.c > index bac59d2..474d760 100644 > --- a/wrapper.c > +++ b/wrapper.c > @@ -187,7 +187,12 @@ ssize_t write_in_full(int fd, const void *buf, size_t > count) > ssize_t total = 0; > > while (count > 0) { > - ssize_t written = xwrite(fd, p, count); > + ssize_t written = 0; > +if (count >= INT_MAX) > + written = xwrite(fd, p, INT_MAX-1); > +else > + written = xwrite(fd, p, count); I think it is better to fix it in much lower level of the stack, as other codepaths would call write(2), either thru xwrite() or directly. Ideally the fix should go to the lowest level, i.e. the write(2). I do not care if it is done in the kernel or in the libc wrapping code; the above does not belong to our code (in an ideal world, that is). Otherwise you would have to patch everything in /usr/bin, no? But you do not live in an ideal world and neither do we. I think the least ugly way may be to add compat/clipped-write.c that implements a loop like the above in a helper function: ssize_t clipped_write(int, const void *, size_t); and have a #ifdef NEED_CLIPPED_WRITE #define write(x,y,z) clipped_write((x),(y),(z)) #endif in git-compat-util.h, or something. Makefile needs to get adjusted to link with compat/clipped-write.o when NEED_CLIPPED_WRITE is defined as well. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
Hi all, While “git svn fetch”ing a subversion repository (private, sorry), I've encoutered a bug that appears in several git versions (always with the same symptoms): git from master (from 2013-04-08) git version 1.8.2.1 (compiled from homebrew) git version 1.7.12.4 (Apple Git-37) The only symptom is git blowing up with the error: fatal: write error: Invalid argument Problems showed up when this happened (in the SVN repo): rev A: File F with 110K is replaced with a 9G file (don't ask…) intermediate revs: files got added and changed, not touching file F rev B: File F finally got reverted to the state before rev A I can git svn fetch up to rev B-1, but svn fetching rev B will throw the previously mentioned error. I traced it down to write() returning <0 and setting errno to EINVAL if nbytes > INT_MAX: http://fxr.watson.org/fxr/source/bsd/kern/sys_generic.c?v=xnu-2050.18.24#L573 (the write() will eventually call dofilewrite, which has that check). Testing with dd bs=INT_MAX+1 count=1 also gets me an “Invalid argument” error, while bs=INT_MAX will do what's expected. I have a preliminary patch that fixes it, but it may not be the preferred way. The code is not ifdef'ed out and I'm doing the fix in write_in_full(), while it may be preferred to do the fix in xwrite(). A radar bug has been submitted to Apple about this, but I think git could tolerate the bug while it isn't fixed, by working around it. Thank you, Filipe git-darwin-bigwrites.patch Description: Binary data