i've run into another gotcha: the base64-decoder doesn't
work on 64-bit big-endian architectures: mhstore and co. write
files of the correct length but which consist only of \0s.

the culprit is uip/mhparse.c, which contains a pretty ugly base64
decoder (in two places). that thing allocates a "long int" as a container
for the 24 bits that you get from four base-64 chars. the container is then
accessed both as a single entity and as a byte array, which naturally 
depends on how wide the long int is and in what order things end up in there.

the code distinguishes between big- and little-endian systems but wrongly 
assumes that sizeof(long int) == 4, which isn't universally 
true (quel surprise...).

the attached patch fixes the issue, but in the long run we should
insist on posix and use a64l().

regards
az

#! /bin/sh /usr/share/dpatch/dpatch-run
## 05-base64-64bit-bigendian.dpatch by  <[email protected]>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: homegrown base64 decoder fails on all big-endian and 64-bit architectures (like s390x)

@DPATCH@
diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' nmh-1.5-release~/uip/mhparse.c nmh-1.5-release/uip/mhparse.c
--- nmh-1.5-release~/uip/mhparse.c	2012-06-14 16:35:36.000000000 +1000
+++ nmh-1.5-release/uip/mhparse.c	2012-06-14 16:36:02.322155163 +1000
@@ -1737,10 +1737,15 @@
     CE ce;
     MD5_CTX mdContext;
 
+    /* the decoder works on the least-significant three bytes of the bits integer,
+       but their position in memory depend on both endian-ness and size of 
+       long int... for little-endian architectures the size is irrelevant, for
+       big-endian archs it's crucial... ideally we'd adopt posix and use a64l instead
+       of this mess. */
     b  = (unsigned char *) &bits;
-    b1 = &b[endian > 0 ? 1 : 2];
-    b2 = &b[endian > 0 ? 2 : 1];
-    b3 = &b[endian > 0 ? 3 : 0];
+    b1 = &b[endian > 0 ? sizeof(bits)==8?5:1 : 2];
+    b2 = &b[endian > 0 ? sizeof(bits)==8?6:2 : 1];
+    b3 = &b[endian > 0 ? sizeof(bits)==8?7:3 : 0];
 
     ce = ct->c_cefile;
     if (ce->ce_fp) {
@@ -2825,10 +2830,16 @@
     unsigned char *dp, value, *ep;
     unsigned char *b, *b1, *b2, *b3;
 
-    b  = (unsigned char *) &bits,
-    b1 = &b[endian > 0 ? 1 : 2],
-    b2 = &b[endian > 0 ? 2 : 1],
-    b3 = &b[endian > 0 ? 3 : 0];
+    /* the decoder works on the least-significant three bytes of the bits integer,
+       but their position in memory depend on both endian-ness and size of 
+       long int... for little-endian architectures the size is irrelevant, for
+       big-endian archs it's crucial... ideally we'd adopt posix and use a64l instead
+       of this mess. */
+    b  = (unsigned char *) &bits;
+    b1 = &b[endian > 0 ? sizeof(bits)==8?5:1 : 2];
+    b2 = &b[endian > 0 ? sizeof(bits)==8?6:2 : 1];
+    b3 = &b[endian > 0 ? sizeof(bits)==8?7:3 : 0];
+
     bitno = 18;
     bits = 0L;
     skip = 0;
-- 
Alexander Zangerl + GnuPG Keys 0x42BD645D or 0x5B586291 + http://snafu.priv.at/
Perl is like vise grips. You can do anything with it but it is 
the wrong tool for every job. -- Bruce Eckel

Attachment: signature.asc
Description: Digital Signature

_______________________________________________
Nmh-workers mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/nmh-workers

Reply via email to