* sizeof(struct ...) @ 2006-11-23 10:16 Gerrit Pape 2006-11-23 12:43 ` René Scharfe 0 siblings, 1 reply; 13+ messages in thread From: Gerrit Pape @ 2006-11-23 10:16 UTC (permalink / raw) To: git Hi, I don't think we can rely on sizeof(struct ...) to be the exact size of the struct as defined. As the selftests show, archive-zip doesn't work correctly on Debian/arm http://buildd.debian.org/fetch.cgi?&pkg=git-core&ver=1%3A1.4.4-1&arch=arm&stamp=1164122355&file=log It's because sizeof(struct zip_local_header) is 32, zip_dir_header 48, and zip_dir_trailer 24, breaking the zip files. Compiling with -fpack-struct seemed to break other things, so I for now I ended up with this (not so nice) workaround. Regards, Gerrit. diff --git a/archive-zip.c b/archive-zip.c index ae5572a..4fcda44 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -211,7 +211,7 @@ static int write_zip_entry(const unsigne } /* make sure we have enough free space in the dictionary */ - direntsize = sizeof(struct zip_dir_header) + pathlen; + direntsize = 46 + pathlen; while (zip_dir_size < zip_dir_offset + direntsize) { zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; zip_dir = xrealloc(zip_dir, zip_dir_size); @@ -234,8 +234,8 @@ static int write_zip_entry(const unsigne copy_le16(dirent.attr1, 0); copy_le32(dirent.attr2, attr2); copy_le32(dirent.offset, zip_offset); - memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header)); - zip_dir_offset += sizeof(struct zip_dir_header); + memcpy(zip_dir + zip_dir_offset, &dirent, 46); + zip_dir_offset += 46; memcpy(zip_dir + zip_dir_offset, path, pathlen); zip_dir_offset += pathlen; zip_dir_entries++; @@ -251,8 +251,8 @@ static int write_zip_entry(const unsigne copy_le32(header.size, uncompressed_size); copy_le16(header.filename_length, pathlen); copy_le16(header.extra_length, 0); - write_or_die(1, &header, sizeof(struct zip_local_header)); - zip_offset += sizeof(struct zip_local_header); + write_or_die(1, &header, 30); + zip_offset += 30; write_or_die(1, path, pathlen); zip_offset += pathlen; if (compressed_size > 0) { @@ -282,7 +282,7 @@ static void write_zip_trailer(const unsi copy_le16(trailer.comment_length, sha1 ? 40 : 0); write_or_die(1, zip_dir, zip_dir_offset); - write_or_die(1, &trailer, sizeof(struct zip_dir_trailer)); + write_or_die(1, &trailer, 22); if (sha1) write_or_die(1, sha1_to_hex(sha1), 40); ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 10:16 sizeof(struct ...) Gerrit Pape @ 2006-11-23 12:43 ` René Scharfe 2006-11-23 13:38 ` René Scharfe 2006-11-23 20:47 ` Junio C Hamano 0 siblings, 2 replies; 13+ messages in thread From: René Scharfe @ 2006-11-23 12:43 UTC (permalink / raw) To: Gerrit Pape; +Cc: git Gerrit Pape schrieb: > Hi, I don't think we can rely on sizeof(struct ...) to be the exact size > of the struct as defined. As the selftests show, archive-zip doesn't > work correctly on Debian/arm > > http://buildd.debian.org/fetch.cgi?&pkg=git-core&ver=1%3A1.4.4-1&arch=arm&stamp=1164122355&file=log > > It's because sizeof(struct zip_local_header) is 32, zip_dir_header 48, > and zip_dir_trailer 24, breaking the zip files. Compiling with > -fpack-struct seemed to break other things, so I for now I ended up with > this (not so nice) workaround. Hm, yes, this use sizeof() is not strictly correct. But I'd very much like to keep being lazy and let the compiler to do the summing. How about this patch instead? Does it work for you, Gerrit? Thanks, René archive-zip.c | 24 ++++++++++++++++++------ 1 files changed, 18 insertions(+), 6 deletions(-) diff --git a/archive-zip.c b/archive-zip.c index ae5572a..4caaec4 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -35,6 +35,7 @@ struct zip_local_header { unsigned char size[4]; unsigned char filename_length[2]; unsigned char extra_length[2]; + unsigned char _end[0]; }; struct zip_dir_header { @@ -55,6 +56,7 @@ struct zip_dir_header { unsigned char attr1[2]; unsigned char attr2[4]; unsigned char offset[4]; + unsigned char _end[0]; }; struct zip_dir_trailer { @@ -66,8 +68,18 @@ struct zip_dir_trailer { unsigned char size[4]; unsigned char offset[4]; unsigned char comment_length[2]; + unsigned char _end[0]; }; +/* + * On ARM, padding is added at the end of the struct, so a simple + * sizeof(struct ...) reports two bytes more than the payload size + * we're interested in. + */ +#define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end) +#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end) +#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end) + static void copy_le16(unsigned char *dest, unsigned int n) { dest[0] = 0xff & n; @@ -211,7 +223,7 @@ static int write_zip_entry(const unsigne } /* make sure we have enough free space in the dictionary */ - direntsize = sizeof(struct zip_dir_header) + pathlen; + direntsize = ZIP_DIR_HEADER_SIZE + pathlen; while (zip_dir_size < zip_dir_offset + direntsize) { zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; zip_dir = xrealloc(zip_dir, zip_dir_size); @@ -234,8 +246,8 @@ static int write_zip_entry(const unsigne copy_le16(dirent.attr1, 0); copy_le32(dirent.attr2, attr2); copy_le32(dirent.offset, zip_offset); - memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header)); - zip_dir_offset += sizeof(struct zip_dir_header); + memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE); + zip_dir_offset += ZIP_DIR_HEADER_SIZE; memcpy(zip_dir + zip_dir_offset, path, pathlen); zip_dir_offset += pathlen; zip_dir_entries++; @@ -251,8 +263,8 @@ static int write_zip_entry(const unsigne copy_le32(header.size, uncompressed_size); copy_le16(header.filename_length, pathlen); copy_le16(header.extra_length, 0); - write_or_die(1, &header, sizeof(struct zip_local_header)); - zip_offset += sizeof(struct zip_local_header); + write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE); + zip_offset += ZIP_LOCAL_HEADER_SIZE; write_or_die(1, path, pathlen); zip_offset += pathlen; if (compressed_size > 0) { @@ -282,7 +294,7 @@ static void write_zip_trailer(const unsi copy_le16(trailer.comment_length, sha1 ? 40 : 0); write_or_die(1, zip_dir, zip_dir_offset); - write_or_die(1, &trailer, sizeof(struct zip_dir_trailer)); + write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE); if (sha1) write_or_die(1, sha1_to_hex(sha1), 40); ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 12:43 ` René Scharfe @ 2006-11-23 13:38 ` René Scharfe 2006-11-23 13:55 ` Andy Whitcroft 2006-11-23 20:47 ` Junio C Hamano 1 sibling, 1 reply; 13+ messages in thread From: René Scharfe @ 2006-11-23 13:38 UTC (permalink / raw) To: Gerrit Pape; +Cc: git Oh no, whitespace damage! The major downside of getting a new machine is that Thunderbird needs to be beaten into submission again. :-( Here's the patch a second time, hopefully intact. René archive-zip.c | 24 ++++++++++++++++++------ 1 files changed, 18 insertions(+), 6 deletions(-) diff --git a/archive-zip.c b/archive-zip.c index ae5572a..4caaec4 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -35,6 +35,7 @@ struct zip_local_header { unsigned char size[4]; unsigned char filename_length[2]; unsigned char extra_length[2]; + unsigned char _end[0]; }; struct zip_dir_header { @@ -55,6 +56,7 @@ struct zip_dir_header { unsigned char attr1[2]; unsigned char attr2[4]; unsigned char offset[4]; + unsigned char _end[0]; }; struct zip_dir_trailer { @@ -66,8 +68,18 @@ struct zip_dir_trailer { unsigned char size[4]; unsigned char offset[4]; unsigned char comment_length[2]; + unsigned char _end[0]; }; +/* + * On ARM, padding is added at the end of the struct, so a simple + * sizeof(struct ...) reports two bytes more than the payload size + * we're interested in. + */ +#define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end) +#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end) +#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end) + static void copy_le16(unsigned char *dest, unsigned int n) { dest[0] = 0xff & n; @@ -211,7 +223,7 @@ static int write_zip_entry(const unsigne } /* make sure we have enough free space in the dictionary */ - direntsize = sizeof(struct zip_dir_header) + pathlen; + direntsize = ZIP_DIR_HEADER_SIZE + pathlen; while (zip_dir_size < zip_dir_offset + direntsize) { zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; zip_dir = xrealloc(zip_dir, zip_dir_size); @@ -234,8 +246,8 @@ static int write_zip_entry(const unsigne copy_le16(dirent.attr1, 0); copy_le32(dirent.attr2, attr2); copy_le32(dirent.offset, zip_offset); - memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header)); - zip_dir_offset += sizeof(struct zip_dir_header); + memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE); + zip_dir_offset += ZIP_DIR_HEADER_SIZE; memcpy(zip_dir + zip_dir_offset, path, pathlen); zip_dir_offset += pathlen; zip_dir_entries++; @@ -251,8 +263,8 @@ static int write_zip_entry(const unsigne copy_le32(header.size, uncompressed_size); copy_le16(header.filename_length, pathlen); copy_le16(header.extra_length, 0); - write_or_die(1, &header, sizeof(struct zip_local_header)); - zip_offset += sizeof(struct zip_local_header); + write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE); + zip_offset += ZIP_LOCAL_HEADER_SIZE; write_or_die(1, path, pathlen); zip_offset += pathlen; if (compressed_size > 0) { @@ -282,7 +294,7 @@ static void write_zip_trailer(const unsi copy_le16(trailer.comment_length, sha1 ? 40 : 0); write_or_die(1, zip_dir, zip_dir_offset); - write_or_die(1, &trailer, sizeof(struct zip_dir_trailer)); + write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE); if (sha1) write_or_die(1, sha1_to_hex(sha1), 40); ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 13:38 ` René Scharfe @ 2006-11-23 13:55 ` Andy Whitcroft 2006-11-23 15:45 ` René Scharfe 0 siblings, 1 reply; 13+ messages in thread From: Andy Whitcroft @ 2006-11-23 13:55 UTC (permalink / raw) To: René Scharfe; +Cc: Gerrit Pape, git René Scharfe wrote: > Oh no, whitespace damage! The major downside of getting a new > machine is that Thunderbird needs to be beaten into submission > again. :-( Here's the patch a second time, hopefully intact. > > René > This structure represents an on-disk/on-the-wire thing, should we not be specifying it in some architecture neutral way? You are going to get the length right in the case of tail padding but not in the face of any other padding internally. You see packing attributes applied to similar things in the kernel. Perhaps they are relevant here? Is there not some kind of attribute thing we can apply to this structure to prevent the padding? You see that in the kernel from time to time. struct foo { } __attribute__((packed)); -apw > > archive-zip.c | 24 ++++++++++++++++++------ > 1 files changed, 18 insertions(+), 6 deletions(-) > > diff --git a/archive-zip.c b/archive-zip.c > index ae5572a..4caaec4 100644 > --- a/archive-zip.c > +++ b/archive-zip.c > @@ -35,6 +35,7 @@ struct zip_local_header { > unsigned char size[4]; > unsigned char filename_length[2]; > unsigned char extra_length[2]; > + unsigned char _end[0]; > }; > > struct zip_dir_header { > @@ -55,6 +56,7 @@ struct zip_dir_header { > unsigned char attr1[2]; > unsigned char attr2[4]; > unsigned char offset[4]; > + unsigned char _end[0]; > }; > > struct zip_dir_trailer { > @@ -66,8 +68,18 @@ struct zip_dir_trailer { > unsigned char size[4]; > unsigned char offset[4]; > unsigned char comment_length[2]; > + unsigned char _end[0]; > }; > > +/* > + * On ARM, padding is added at the end of the struct, so a simple > + * sizeof(struct ...) reports two bytes more than the payload size > + * we're interested in. > + */ > +#define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end) > +#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end) > +#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end) > + > static void copy_le16(unsigned char *dest, unsigned int n) > { > dest[0] = 0xff & n; > @@ -211,7 +223,7 @@ static int write_zip_entry(const unsigne > } > > /* make sure we have enough free space in the dictionary */ > - direntsize = sizeof(struct zip_dir_header) + pathlen; > + direntsize = ZIP_DIR_HEADER_SIZE + pathlen; > while (zip_dir_size < zip_dir_offset + direntsize) { > zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; > zip_dir = xrealloc(zip_dir, zip_dir_size); > @@ -234,8 +246,8 @@ static int write_zip_entry(const unsigne > copy_le16(dirent.attr1, 0); > copy_le32(dirent.attr2, attr2); > copy_le32(dirent.offset, zip_offset); > - memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header)); > - zip_dir_offset += sizeof(struct zip_dir_header); > + memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE); > + zip_dir_offset += ZIP_DIR_HEADER_SIZE; > memcpy(zip_dir + zip_dir_offset, path, pathlen); > zip_dir_offset += pathlen; > zip_dir_entries++; > @@ -251,8 +263,8 @@ static int write_zip_entry(const unsigne > copy_le32(header.size, uncompressed_size); > copy_le16(header.filename_length, pathlen); > copy_le16(header.extra_length, 0); > - write_or_die(1, &header, sizeof(struct zip_local_header)); > - zip_offset += sizeof(struct zip_local_header); > + write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE); > + zip_offset += ZIP_LOCAL_HEADER_SIZE; > write_or_die(1, path, pathlen); > zip_offset += pathlen; > if (compressed_size > 0) { > @@ -282,7 +294,7 @@ static void write_zip_trailer(const unsi > copy_le16(trailer.comment_length, sha1 ? 40 : 0); > > write_or_die(1, zip_dir, zip_dir_offset); > - write_or_die(1, &trailer, sizeof(struct zip_dir_trailer)); > + write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE); > if (sha1) > write_or_die(1, sha1_to_hex(sha1), 40); > } > - > 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 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 13:55 ` Andy Whitcroft @ 2006-11-23 15:45 ` René Scharfe 2006-11-23 15:54 ` Erik Mouw 0 siblings, 1 reply; 13+ messages in thread From: René Scharfe @ 2006-11-23 15:45 UTC (permalink / raw) To: Andy Whitcroft; +Cc: Gerrit Pape, git Andy Whitcroft schrieb: > This structure represents an on-disk/on-the-wire thing, should we not be > specifying it in some architecture neutral way? You are going to get > the length right in the case of tail padding but not in the face of any > other padding internally. > > You see packing attributes applied to similar things in the kernel. > Perhaps they are relevant here? > Is there not some kind of attribute thing we can apply to this structure > to prevent the padding? You see that in the kernel from time to time. > > struct foo { > } __attribute__((packed)); Yes, that would be nice, but unfortunately __attribute__ is no standard C. Is there really a compiler that inserts padding between arrays of unsigned chars? Thanks, ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 15:45 ` René Scharfe @ 2006-11-23 15:54 ` Erik Mouw 2006-11-23 16:14 ` René Scharfe 0 siblings, 1 reply; 13+ messages in thread From: Erik Mouw @ 2006-11-23 15:54 UTC (permalink / raw) To: Ren? Scharfe; +Cc: Andy Whitcroft, Gerrit Pape, git On Thu, Nov 23, 2006 at 04:45:09PM +0100, Ren? Scharfe wrote: > Andy Whitcroft schrieb: > > You see packing attributes applied to similar things in the kernel. > > Perhaps they are relevant here? > > Is there not some kind of attribute thing we can apply to this structure > > to prevent the padding? You see that in the kernel from time to time. > > > > struct foo { > > } __attribute__((packed)); > > Yes, that would be nice, but unfortunately __attribute__ is no standard > C. There is no standard C way to pack structures. Some compilers use #pragma's, gcc uses __attribute__((packed)). > Is there really a compiler that inserts padding between arrays of > unsigned chars? Yes, that compiler is called "gcc". #include <stdio.h> struct foo { unsigned char a[3]; unsigned char b[3]; }; int main(void) { printf("%d\n", sizeof(struct foo)); return 0; } On i386 that prints 6, on ARM it prints 8. Erik -- +-- Erik Mouw -- www.harddisk-recovery.com -- +31 70 370 12 90 -- ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 15:54 ` Erik Mouw @ 2006-11-23 16:14 ` René Scharfe 2006-11-23 16:19 ` Andy Whitcroft 2006-11-23 16:42 ` Erik Mouw 0 siblings, 2 replies; 13+ messages in thread From: René Scharfe @ 2006-11-23 16:14 UTC (permalink / raw) To: Erik Mouw; +Cc: Andy Whitcroft, Gerrit Pape, git Erik Mouw schrieb: > On Thu, Nov 23, 2006 at 04:45:09PM +0100, René Scharfe wrote: >> Is there really a compiler that inserts padding between arrays of >> unsigned chars? > > Yes, that compiler is called "gcc". > > #include <stdio.h> > > struct foo { > unsigned char a[3]; > unsigned char b[3]; > }; > > int main(void) > { > printf("%d\n", sizeof(struct foo)); > return 0; > } > > On i386 that prints 6, on ARM it prints 8. Does it add 1 byte after a and and 1 after b or two after b? I suspect it's the latter case -- otherwise Gerrit's patch, which started this thread, wouldn't help solve his problem. Or the pad sizing follows complicated rules that I do not understand at the moment. Time to look for an ARM emulator, it seems. Thanks, ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 16:14 ` René Scharfe @ 2006-11-23 16:19 ` Andy Whitcroft 2006-11-23 17:57 ` René Scharfe 2006-11-23 16:42 ` Erik Mouw 1 sibling, 1 reply; 13+ messages in thread From: Andy Whitcroft @ 2006-11-23 16:19 UTC (permalink / raw) To: René Scharfe; +Cc: Erik Mouw, Gerrit Pape, git René Scharfe wrote: > Erik Mouw schrieb: >> On Thu, Nov 23, 2006 at 04:45:09PM +0100, René Scharfe wrote: >>> Is there really a compiler that inserts padding between arrays of >>> unsigned chars? >> Yes, that compiler is called "gcc". >> >> #include <stdio.h> >> >> struct foo { >> unsigned char a[3]; >> unsigned char b[3]; >> }; >> >> int main(void) >> { >> printf("%d\n", sizeof(struct foo)); >> return 0; >> } >> >> On i386 that prints 6, on ARM it prints 8. > > Does it add 1 byte after a and and 1 after b or two after b? > I suspect it's the latter case -- otherwise Gerrit's patch, > which started this thread, wouldn't help solve his problem. > Or the pad sizing follows complicated rules that I do not > understand at the moment. > > Time to look for an ARM emulator, it seems. Perhaps we can look and see what a portable application like gzip or bzip2 do in this situation. They must have the same problem. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 16:19 ` Andy Whitcroft @ 2006-11-23 17:57 ` René Scharfe 0 siblings, 0 replies; 13+ messages in thread From: René Scharfe @ 2006-11-23 17:57 UTC (permalink / raw) To: Andy Whitcroft; +Cc: Erik Mouw, Gerrit Pape, git Andy Whitcroft schrieb: > Perhaps we can look and see what a portable application like gzip or > bzip2 do in this situation. They must have the same problem. Info-ZIP's zip uses structs only for in-memory storage and has a write function for each of them that writes the members one by one. I find the structs in archive-zip.c easier to read, but I might be biased. ;-) Anyway, archive-zip.c assumes that there is no padding between unsigned char arrays and that an unsigned char is exactly one byte wide. The additional current assumption -- that sizeof(struct ...) sums up the sizes of all struct members -- is wrong on ARM, and the patches in this thread correct this error. So we're not as portable as Info-ZIP, but I think the assumptions above hold true for all interesting architectures. And we have a readable description of the on-disk ZIP file headers. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 16:14 ` René Scharfe 2006-11-23 16:19 ` Andy Whitcroft @ 2006-11-23 16:42 ` Erik Mouw 1 sibling, 0 replies; 13+ messages in thread From: Erik Mouw @ 2006-11-23 16:42 UTC (permalink / raw) To: Ren? Scharfe; +Cc: Andy Whitcroft, Gerrit Pape, git On Thu, Nov 23, 2006 at 05:14:44PM +0100, Ren? Scharfe wrote: > Erik Mouw schrieb: > > On Thu, Nov 23, 2006 at 04:45:09PM +0100, Ren? Scharfe wrote: > >> Is there really a compiler that inserts padding between arrays of > >> unsigned chars? > > > > Yes, that compiler is called "gcc". > > > > #include <stdio.h> > > > > struct foo { > > unsigned char a[3]; > > unsigned char b[3]; > > }; > > > > int main(void) > > { > > printf("%d\n", sizeof(struct foo)); > > return 0; > > } > > > > On i386 that prints 6, on ARM it prints 8. > > Does it add 1 byte after a and and 1 after b or two after b? > I suspect it's the latter case -- otherwise Gerrit's patch, > which started this thread, wouldn't help solve his problem. > Or the pad sizing follows complicated rules that I do not > understand at the moment. You're right, it adds the padding after b: #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) printf("%d %d\n", offsetof(struct foo, a), offsetof(struct foo, b)); prints "0 3" on ARM. > Time to look for an ARM emulator, it seems. objdump -D -S is your friend. I didn't have an ARM target ready, but at least I know enough ARM assembly that I can see what it will print :) Erik -- +-- Erik Mouw -- www.harddisk-recovery.com -- +31 70 370 12 90 -- ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: sizeof(struct ...) 2006-11-23 12:43 ` René Scharfe 2006-11-23 13:38 ` René Scharfe @ 2006-11-23 20:47 ` Junio C Hamano 2006-11-23 22:02 ` [PATCH] archive-zip: don't use " René Scharfe 1 sibling, 1 reply; 13+ messages in thread From: Junio C Hamano @ 2006-11-23 20:47 UTC (permalink / raw) To: René Scharfe; +Cc: git, Gerrit Pape René Scharfe <rene.scharfe@lsrfire.ath.cx> writes: > Gerrit Pape schrieb: >... >> It's because sizeof(struct zip_local_header) is 32, zip_dir_header 48, >> and zip_dir_trailer 24, breaking the zip files. Compiling with >> -fpack-struct seemed to break other things, so I for now I ended up with >> this (not so nice) workaround. > > Hm, yes, this use sizeof() is not strictly correct. But I'd very much > like to keep being lazy and let the compiler to do the summing. How > about this patch instead? Does it work for you, Gerrit? >... > @@ -35,6 +35,7 @@ struct zip_local_header { > unsigned char size[4]; > unsigned char filename_length[2]; > unsigned char extra_length[2]; > + unsigned char _end[0]; > }; While I think relying on the compiler to add no pad in the middle of the structure that has only unsigned char array members, making the compiler to sum the member length using offsetof() is a reasonable approach to avoid hardcoding the size of on-disk structure representation, zero-length member is not portable. We need to deal with tail padding in any case, and this _end[N] is essentially a manual tail padding when N > 0, so I think that the code should work even if you change these to _end[1], and that would be a reasonably clean solution to this problem. ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH] archive-zip: don't use sizeof(struct ...) 2006-11-23 20:47 ` Junio C Hamano @ 2006-11-23 22:02 ` René Scharfe 2006-11-24 8:53 ` Gerrit Pape 0 siblings, 1 reply; 13+ messages in thread From: René Scharfe @ 2006-11-23 22:02 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Gerrit Pape We can't rely on sizeof(struct zip_*) returning the sum of all struct members. At least on ARM padding is added at the end, as Gerrit Pape reported. This fixes the problem but still lets the compiler do the summing by introducing explicit padding at the end of the structs and then taking its offset as the combined size of the preceding members. As Junio correctly notes, the _end[] marker array's size must be greater than zero for compatibility with compilers other than gcc. The space wasted by the markers can safely be neglected because we only have one instance of each struct, i.e. in sum 3 wasted bytes on i386, and 0 on ARM. :) We still rely on the compiler to not add padding between the struct members, but that's reasonable given that all of them are unsigned char arrays. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> archive-zip.c | 24 ++++++++++++++++++------ 1 files changed, 18 insertions(+), 6 deletions(-) diff --git a/archive-zip.c b/archive-zip.c index ae5572a..36e922a 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -35,6 +35,7 @@ struct zip_local_header { unsigned char size[4]; unsigned char filename_length[2]; unsigned char extra_length[2]; + unsigned char _end[1]; }; struct zip_dir_header { @@ -55,6 +56,7 @@ struct zip_dir_header { unsigned char attr1[2]; unsigned char attr2[4]; unsigned char offset[4]; + unsigned char _end[1]; }; struct zip_dir_trailer { @@ -66,8 +68,18 @@ struct zip_dir_trailer { unsigned char size[4]; unsigned char offset[4]; unsigned char comment_length[2]; + unsigned char _end[1]; }; +/* + * On ARM, padding is added at the end of the struct, so a simple + * sizeof(struct ...) reports two bytes more than the payload size + * we're interested in. + */ +#define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end) +#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end) +#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end) + static void copy_le16(unsigned char *dest, unsigned int n) { dest[0] = 0xff & n; @@ -211,7 +223,7 @@ static int write_zip_entry(const unsigne } /* make sure we have enough free space in the dictionary */ - direntsize = sizeof(struct zip_dir_header) + pathlen; + direntsize = ZIP_DIR_HEADER_SIZE + pathlen; while (zip_dir_size < zip_dir_offset + direntsize) { zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; zip_dir = xrealloc(zip_dir, zip_dir_size); @@ -234,8 +246,8 @@ static int write_zip_entry(const unsigne copy_le16(dirent.attr1, 0); copy_le32(dirent.attr2, attr2); copy_le32(dirent.offset, zip_offset); - memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header)); - zip_dir_offset += sizeof(struct zip_dir_header); + memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE); + zip_dir_offset += ZIP_DIR_HEADER_SIZE; memcpy(zip_dir + zip_dir_offset, path, pathlen); zip_dir_offset += pathlen; zip_dir_entries++; @@ -251,8 +263,8 @@ static int write_zip_entry(const unsigne copy_le32(header.size, uncompressed_size); copy_le16(header.filename_length, pathlen); copy_le16(header.extra_length, 0); - write_or_die(1, &header, sizeof(struct zip_local_header)); - zip_offset += sizeof(struct zip_local_header); + write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE); + zip_offset += ZIP_LOCAL_HEADER_SIZE; write_or_die(1, path, pathlen); zip_offset += pathlen; if (compressed_size > 0) { @@ -282,7 +294,7 @@ static void write_zip_trailer(const unsi copy_le16(trailer.comment_length, sha1 ? 40 : 0); write_or_die(1, zip_dir, zip_dir_offset); - write_or_die(1, &trailer, sizeof(struct zip_dir_trailer)); + write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE); if (sha1) write_or_die(1, sha1_to_hex(sha1), 40); } ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH] archive-zip: don't use sizeof(struct ...) 2006-11-23 22:02 ` [PATCH] archive-zip: don't use " René Scharfe @ 2006-11-24 8:53 ` Gerrit Pape 0 siblings, 0 replies; 13+ messages in thread From: Gerrit Pape @ 2006-11-24 8:53 UTC (permalink / raw) To: git On Thu, Nov 23, 2006 at 11:02:37PM +0100, Ren? Scharfe wrote: > We can't rely on sizeof(struct zip_*) returning the sum of > all struct members. At least on ARM padding is added at the > end, as Gerrit Pape reported. This fixes the problem but > still lets the compiler do the summing by introducing > explicit padding at the end of the structs and then taking > its offset as the combined size of the preceding members. > > As Junio correctly notes, the _end[] marker array's size > must be greater than zero for compatibility with compilers > other than gcc. The space wasted by the markers can safely > be neglected because we only have one instance of each > struct, i.e. in sum 3 wasted bytes on i386, and 0 on ARM. :) > > We still rely on the compiler to not add padding between the > struct members, but that's reasonable given that all of them > are unsigned char arrays. > > Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2006-11-24 8:53 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-11-23 10:16 sizeof(struct ...) Gerrit Pape 2006-11-23 12:43 ` René Scharfe 2006-11-23 13:38 ` René Scharfe 2006-11-23 13:55 ` Andy Whitcroft 2006-11-23 15:45 ` René Scharfe 2006-11-23 15:54 ` Erik Mouw 2006-11-23 16:14 ` René Scharfe 2006-11-23 16:19 ` Andy Whitcroft 2006-11-23 17:57 ` René Scharfe 2006-11-23 16:42 ` Erik Mouw 2006-11-23 20:47 ` Junio C Hamano 2006-11-23 22:02 ` [PATCH] archive-zip: don't use " René Scharfe 2006-11-24 8:53 ` Gerrit Pape
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).