* write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
@ 2013-04-09 22:31 Filipe Cabecinhas
2013-04-09 22:50 ` Junio C Hamano
0 siblings, 1 reply; 12+ messages in thread
From: Filipe Cabecinhas @ 2013-04-09 22:31 UTC (permalink / raw)
To: git
[-- Attachment #1: Type: text/plain, Size: 1500 bytes --]
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
[-- Attachment #2: git-darwin-bigwrites.patch --]
[-- Type: application/octet-stream, Size: 468 bytes --]
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);
+
if (written < 0)
return -1;
if (!written) {
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-04-09 22:31 write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX Filipe Cabecinhas
@ 2013-04-09 22:50 ` Junio C Hamano
2013-05-09 22:58 ` Filipe Cabecinhas
0 siblings, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2013-04-09 22:50 UTC (permalink / raw)
To: Filipe Cabecinhas; +Cc: git
Filipe Cabecinhas <filcab@gmail.com> 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.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-04-09 22:50 ` Junio C Hamano
@ 2013-05-09 22:58 ` Filipe Cabecinhas
2013-05-10 2:28 ` Junio C Hamano
0 siblings, 1 reply; 12+ messages in thread
From: Filipe Cabecinhas @ 2013-05-09 22:58 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
[-- Attachment #1: Type: text/plain, Size: 2339 bytes --]
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 <gitster@pobox.com> wrote:
> Filipe Cabecinhas <filcab@gmail.com> 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.
[-- Attachment #2: git-big-write-darwin.patch --]
[-- Type: application/octet-stream, Size: 1779 bytes --]
diff --git a/Makefile b/Makefile
index 0f931a2..e6aff85 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/write.o
+endif
+
ifneq (,$(XDL_FAST_HASH))
BASIC_CFLAGS += -DXDL_FAST_HASH
endif
diff --git a/compat/write.c b/compat/write.c
new file mode 100644
index 0000000..1e890aa
--- /dev/null
+++ b/compat/write.c
@@ -0,0 +1,11 @@
+#include <limits.h>
+#include <unistd.h>
+
+/* 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)
+ return write(fildes, buf, INT_MAX);
+ else
+ 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);
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-05-09 22:58 ` Filipe Cabecinhas
@ 2013-05-10 2:28 ` Junio C Hamano
2013-05-10 22:24 ` Filipe Cabecinhas
0 siblings, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2013-05-10 2:28 UTC (permalink / raw)
To: Filipe Cabecinhas; +Cc: git
Filipe Cabecinhas <filcab@gmail.com> 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 0000000..1e890aa
> --- /dev/null
> +++ b/compat/write.c
> @@ -0,0 +1,11 @@
> +#include <limits.h>
> +#include <unistd.h>
> +
> +/* 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.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-05-10 2:28 ` Junio C Hamano
@ 2013-05-10 22:24 ` Filipe Cabecinhas
2013-05-10 23:05 ` Junio C Hamano
0 siblings, 1 reply; 12+ messages in thread
From: Filipe Cabecinhas @ 2013-05-10 22:24 UTC (permalink / raw)
To: Junio C Hamano, git
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 <filcab+git@gmail.com>
---
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 0000000..9183698
--- /dev/null
+++ b/compat/clipped-write.c
@@ -0,0 +1,13 @@
+#include <limits.h>
+#include <unistd.h>
+
+/*
+ * 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
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-05-10 22:24 ` Filipe Cabecinhas
@ 2013-05-10 23:05 ` Junio C Hamano
2013-05-10 23:10 ` Junio C Hamano
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Junio C Hamano @ 2013-05-10 23:05 UTC (permalink / raw)
To: Filipe Cabecinhas; +Cc: git
Filipe Cabecinhas <filcab@gmail.com> 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 <filcab+git@gmail.com>
> ---
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 <filcab@gmail.com>
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 <filcab+git@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
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 0000000..9183698
--- /dev/null
+++ b/compat/clipped-write.c
@@ -0,0 +1,13 @@
+#include <limits.h>
+#include <unistd.h>
+
+/*
+ * 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
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-05-10 23:05 ` Junio C Hamano
@ 2013-05-10 23:10 ` Junio C Hamano
2013-05-10 23:13 ` Filipe Cabecinhas
2013-11-20 10:15 ` Erik Faye-Lund
2 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2013-05-10 23:10 UTC (permalink / raw)
To: Filipe Cabecinhas; +Cc: git
Junio C Hamano <gitster@pobox.com> 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 <limits.h>
-#include <unistd.h>
+#include "../git-compat-util.h"
+#undef write
/*
* Version of write that will write at most INT_MAX bytes.
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-05-10 23:05 ` Junio C Hamano
2013-05-10 23:10 ` Junio C Hamano
@ 2013-05-10 23:13 ` Filipe Cabecinhas
2013-05-10 23:19 ` Filipe Cabecinhas
2013-11-20 10:15 ` Erik Faye-Lund
2 siblings, 1 reply; 12+ messages in thread
From: Filipe Cabecinhas @ 2013-05-10 23:13 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
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 <gitster@pobox.com> wrote:
> Filipe Cabecinhas <filcab@gmail.com> 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 <filcab+git@gmail.com>
>> ---
>
> 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 <filcab@gmail.com>
> 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 <filcab+git@gmail.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
> 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 0000000..9183698
> --- /dev/null
> +++ b/compat/clipped-write.c
> @@ -0,0 +1,13 @@
> +#include <limits.h>
> +#include <unistd.h>
> +
> +/*
> + * 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
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-05-10 23:13 ` Filipe Cabecinhas
@ 2013-05-10 23:19 ` Filipe Cabecinhas
2013-05-10 23:36 ` Junio C Hamano
0 siblings, 1 reply; 12+ messages in thread
From: Filipe Cabecinhas @ 2013-05-10 23:19 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
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 <filcab@gmail.com> 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 <gitster@pobox.com> wrote:
>> Filipe Cabecinhas <filcab@gmail.com> 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 <filcab+git@gmail.com>
>>> ---
>>
>> 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 <filcab@gmail.com>
>> 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 <filcab+git@gmail.com>
>> Signed-off-by: Junio C Hamano <gitster@pobox.com>
>> ---
>> 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 0000000..9183698
>> --- /dev/null
>> +++ b/compat/clipped-write.c
>> @@ -0,0 +1,13 @@
>> +#include <limits.h>
>> +#include <unistd.h>
>> +
>> +/*
>> + * 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
>>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-05-10 23:19 ` Filipe Cabecinhas
@ 2013-05-10 23:36 ` Junio C Hamano
0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2013-05-10 23:36 UTC (permalink / raw)
To: Filipe Cabecinhas; +Cc: git
Filipe Cabecinhas <filcab@gmail.com> 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.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-05-10 23:05 ` Junio C Hamano
2013-05-10 23:10 ` Junio C Hamano
2013-05-10 23:13 ` Filipe Cabecinhas
@ 2013-11-20 10:15 ` Erik Faye-Lund
2013-11-20 13:03 ` Torsten Bögershausen
2 siblings, 1 reply; 12+ messages in thread
From: Erik Faye-Lund @ 2013-11-20 10:15 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Filipe Cabecinhas, GIT Mailing-list
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 <gitster@pobox.com> wrote:
> Filipe Cabecinhas <filcab@gmail.com> 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 0000000..9183698
> --- /dev/null
> +++ b/compat/clipped-write.c
> @@ -0,0 +1,13 @@
> +#include <limits.h>
> +#include <unistd.h>
> +
> +/*
> + * 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.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX
2013-11-20 10:15 ` Erik Faye-Lund
@ 2013-11-20 13:03 ` Torsten Bögershausen
0 siblings, 0 replies; 12+ messages in thread
From: Torsten Bögershausen @ 2013-11-20 13:03 UTC (permalink / raw)
To: kusmabite, Junio C Hamano; +Cc: Filipe Cabecinhas, GIT Mailing-list, msysGit
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 <prohaska@zib.de>
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 <gitster@pobox.com> wrote:
>> Filipe Cabecinhas <filcab@gmail.com> 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 0000000..9183698
>> --- /dev/null
>> +++ b/compat/clipped-write.c
>> @@ -0,0 +1,13 @@
>> +#include <limits.h>
>> +#include <unistd.h>
>> +
>> +/*
>> + * 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 majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
--
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.
You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en
---
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2013-11-20 13:03 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-09 22:31 write() _will_ fail on Mac OS X/XNU if nbytes > INT_MAX Filipe Cabecinhas
2013-04-09 22:50 ` Junio C Hamano
2013-05-09 22:58 ` Filipe Cabecinhas
2013-05-10 2:28 ` Junio C Hamano
2013-05-10 22:24 ` Filipe Cabecinhas
2013-05-10 23:05 ` Junio C Hamano
2013-05-10 23:10 ` Junio C Hamano
2013-05-10 23:13 ` Filipe Cabecinhas
2013-05-10 23:19 ` Filipe Cabecinhas
2013-05-10 23:36 ` Junio C Hamano
2013-11-20 10:15 ` Erik Faye-Lund
2013-11-20 13:03 ` Torsten Bögershausen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).