Bug 14142

Summary: sendmail: mci.c: bad pointer conversion in debug print
Product: Base System Reporter: Valentin Nechayev <netch>
Component: binAssignee: Gregory Neil Shapiro <gshapiro>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 3.3-STABLE   
Hardware: Any   
OS: Any   

Description Valentin Nechayev 1999-10-05 16:50:01 UTC
The following piece of mci_dump() uses bad conversion:

        snprintf(p, SPACELEFT(buf, p), "MCI@%lx: ",
                sizeof(void *) == sizeof(u_long) ?
                (u_long)(void *)mci : (u_long)(u_int)(void *)mci);
 
On Alpha architecture, conversion from void* to u_int loses significant bits.
These conversions are FreeBSD-specific; original Allman's sendmail
does not contain them.

Fix: 

Convert to ptrdiff_t instead of u_int (?)
How-To-Repeat: 
Read and compile the code ;)
Comment 1 Bruce Evans 1999-10-06 01:59:25 UTC
> The following piece of mci_dump() uses bad conversion:
> 
>         snprintf(p, SPACELEFT(buf, p), "MCI@%lx: ",
>                 sizeof(void *) == sizeof(u_long) ?
>                 (u_long)(void *)mci : (u_long)(u_int)(void *)mci);
>  
> On Alpha architecture, conversion from void* to u_int loses significant bits.

On FreeBSD-alpha sizeof(void *) == sizeof(long), so the conversion from
void * to u_int is never executed.  Unfortunately, gcc apparently warns
about casts from pointers to integers of a different size even in dead
code.

On FreeBSD_i386-with-64-bit-longs, gcc warns about the dead code in the
other arm of the if and about 3 casts from pointers to u_longs.  All these
problems can be fixed better now by casting pointers to
(u_long)(uintptr_t)(void *) and printing them with %lx, or if the format
doesn't matter, by casting pointers to (void *) and printing them with %p.

> These conversions are FreeBSD-specific; original Allman's sendmail
> does not contain them.

The original code was broken at runtime (it shows only the low 32 bits of
pointers on FreeBSD-alpha).

Bruce
Comment 2 nn 1999-10-06 08:03:10 UTC
Bruce Evans <bde@zeta.org.au> wrote:

> On FreeBSD-alpha sizeof(void *) == sizeof(long), so the conversion from
> void * to u_int is never executed.  Unfortunately, gcc apparently warns
> about casts from pointers to integers of a different size even in dead
> code.
>
> On FreeBSD_i386-with-64-bit-longs, gcc warns about the dead code in the
> other arm of the if and about 3 casts from pointers to u_longs.  All these
> problems can be fixed better now by casting pointers to
> (u_long)(uintptr_t)(void *) and printing them with %lx, or if the format
> doesn't matter, by casting pointers to (void *) and printing them with %p.

Well, shall it be better to use only %p and casting to void*, as "the only
really right and portable way"?

> > These conversions are FreeBSD-specific; original Allman's sendmail
> > does not contain them.
>
> The original code was broken at runtime (it shows only the low 32 bits of
> pointers on FreeBSD-alpha).

Of course, original code is broken also and really. Do you know the reason
of using integral formats instead of %p in original code?
Comment 3 Bruce Evans 1999-10-06 09:46:08 UTC
On Wed, 6 Oct 1999, Valentin Nechayev wrote:

> Bruce Evans <bde@zeta.org.au> wrote:
> > ...  All these
> > problems can be fixed better now by casting pointers to
> > (u_long)(uintptr_t)(void *) and printing them with %lx, or if the format
> > doesn't matter, by casting pointers to (void *) and printing them with %p.

Except uintptr_t is not supported in RELENG_3.

> > The original code was broken at runtime (it shows only the low 32 bits of
> > pointers on FreeBSD-alpha).
> 
> Of course, original code is broken also and really. Do you know the reason
> of using integral formats instead of %p in original code?

It's probably "portability".  Some systems don't/didn't have %p.

Bruce
Comment 4 Gregory Neil Shapiro freebsd_committer freebsd_triage 2000-08-12 18:14:19 UTC
Responsible Changed
From-To: freebsd-bugs->gshapiro

Assigned to sendmail maintainer.
Comment 5 Gregory Neil Shapiro freebsd_committer freebsd_triage 2001-02-22 06:49:54 UTC
State Changed
From-To: open->analyzed

I don't understand why FreeBSD has a different version of code for that. 
The original sendmail code appears to be better for this case unless I am 
missing something.  I tried a test.  Give try.c: 

#include <sys/stat.h> 
#include <sys/types.h> 
#include <stdio.h> 

int 
main(int argc, char **argv) 
{ 
struct stat b; 
struct stat *a; 

a = &b; 
printf(" no cast: %lxn", a); 
printf("sendmail: %lxn", (u_long) a); 
printf(" FreeBSD: %lxn", 
sizeof(void *) == sizeof(u_long) ? 
(u_long)(void *)a : (u_long)(u_int)(void *)a); 
} 

Compiling on beast.freebsd.org gives a warning on the FreeBSD case: 

> cc -mcpu=ev56 -O -pipe  try.c  -o try 
try.c: In function `main': 
try.c:16: warning: cast from pointer to integer of different size 

But all three cases give the same result: 

> ./try 
no cast: 11ffb7e8 
sendmail: 11ffb7e8 
FreeBSD: 11ffb7e8 

Unless I am mistaken, the FreeBSD modifications should be removed.
Comment 6 Gregory Neil Shapiro freebsd_committer freebsd_triage 2001-02-22 17:57:14 UTC
State Changed
From-To: analyzed->feedback

Return to the code as distributed by sendmail.org.  This eliminates a 
warning on Alphas.  It is still not the perfect solution for machines 
which sizeof(u_long) != sizeof(void *) but it is as close as we are going 
to get for now and consistent with the rest of the code.  8.12 has solved 
this problem by providing a portable snprintf() which understands %p. 

Unless I hear otherwise, I'll close this PR in the near future.
Comment 7 Gregory Neil Shapiro freebsd_committer freebsd_triage 2001-02-28 02:57:37 UTC
State Changed
From-To: feedback->closed

The changes are now also in RELENG_4 (-STABLE).