Skip to content

Commit 0ea865c

Browse files
René ScharfeJunio C Hamano
authored andcommitted
archive-zip: don't use sizeof(struct ...)
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e945f95 commit 0ea865c

File tree

1 file changed

+18
-6
lines changed

1 file changed

+18
-6
lines changed

archive-zip.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct zip_local_header {
3535
unsigned char size[4];
3636
unsigned char filename_length[2];
3737
unsigned char extra_length[2];
38+
unsigned char _end[1];
3839
};
3940

4041
struct zip_dir_header {
@@ -55,6 +56,7 @@ struct zip_dir_header {
5556
unsigned char attr1[2];
5657
unsigned char attr2[4];
5758
unsigned char offset[4];
59+
unsigned char _end[1];
5860
};
5961

6062
struct zip_dir_trailer {
@@ -66,8 +68,18 @@ struct zip_dir_trailer {
6668
unsigned char size[4];
6769
unsigned char offset[4];
6870
unsigned char comment_length[2];
71+
unsigned char _end[1];
6972
};
7073

74+
/*
75+
* On ARM, padding is added at the end of the struct, so a simple
76+
* sizeof(struct ...) reports two bytes more than the payload size
77+
* we're interested in.
78+
*/
79+
#define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end)
80+
#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end)
81+
#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end)
82+
7183
static void copy_le16(unsigned char *dest, unsigned int n)
7284
{
7385
dest[0] = 0xff & n;
@@ -211,7 +223,7 @@ static int write_zip_entry(const unsigned char *sha1,
211223
}
212224

213225
/* make sure we have enough free space in the dictionary */
214-
direntsize = sizeof(struct zip_dir_header) + pathlen;
226+
direntsize = ZIP_DIR_HEADER_SIZE + pathlen;
215227
while (zip_dir_size < zip_dir_offset + direntsize) {
216228
zip_dir_size += ZIP_DIRECTORY_MIN_SIZE;
217229
zip_dir = xrealloc(zip_dir, zip_dir_size);
@@ -234,8 +246,8 @@ static int write_zip_entry(const unsigned char *sha1,
234246
copy_le16(dirent.attr1, 0);
235247
copy_le32(dirent.attr2, attr2);
236248
copy_le32(dirent.offset, zip_offset);
237-
memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header));
238-
zip_dir_offset += sizeof(struct zip_dir_header);
249+
memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE);
250+
zip_dir_offset += ZIP_DIR_HEADER_SIZE;
239251
memcpy(zip_dir + zip_dir_offset, path, pathlen);
240252
zip_dir_offset += pathlen;
241253
zip_dir_entries++;
@@ -251,8 +263,8 @@ static int write_zip_entry(const unsigned char *sha1,
251263
copy_le32(header.size, uncompressed_size);
252264
copy_le16(header.filename_length, pathlen);
253265
copy_le16(header.extra_length, 0);
254-
write_or_die(1, &header, sizeof(struct zip_local_header));
255-
zip_offset += sizeof(struct zip_local_header);
266+
write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
267+
zip_offset += ZIP_LOCAL_HEADER_SIZE;
256268
write_or_die(1, path, pathlen);
257269
zip_offset += pathlen;
258270
if (compressed_size > 0) {
@@ -282,7 +294,7 @@ static void write_zip_trailer(const unsigned char *sha1)
282294
copy_le16(trailer.comment_length, sha1 ? 40 : 0);
283295

284296
write_or_die(1, zip_dir, zip_dir_offset);
285-
write_or_die(1, &trailer, sizeof(struct zip_dir_trailer));
297+
write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE);
286298
if (sha1)
287299
write_or_die(1, sha1_to_hex(sha1), 40);
288300
}

0 commit comments

Comments
 (0)