Bug 1097 - strnlen and strndup broken on AIX
Summary: strnlen and strndup broken on AIX
Status: CLOSED FIXED
Alias: None
Product: Samba 3.0
Classification: Unclassified
Component: Build environment (show other bugs)
Version: 3.0.1
Hardware: All AIX
: P3 critical
Target Milestone: none
Assignee: Tim Potter
QA Contact:
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-02-18 03:28 UTC by Heinrich Mislik
Modified: 2005-08-24 10:17 UTC (History)
0 users

See Also:


Attachments
Details for strndup bug (3.70 KB, text/plain)
2004-02-19 03:57 UTC, Heinrich Mislik
no flags Details
Configure test for broken strnlen (1.73 KB, patch)
2004-02-20 15:41 UTC, Tim Potter
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Heinrich Mislik 2004-02-18 03:28:21 UTC
# cat strnlen_broken.c
#include <string.h>
#include <stdlib.h>

main()
{
   char *s1 = "01234567891";
   printf("strlen %d\n",strlen(s1));
   printf("strnlen %d\n",strnlen(s1,10));
}
# cc strnlen_broken.c
# ./a.out
strlen 11
strnlen 11

strnlen should return 10! 

I couldn't find a short example of the wrong behavior of strndup. 
When i insterted DEBUG befor and after strndup in the Samba code, I 
saw that no '\0' is put on the end. So sometimes I saw remainings of 
previously used strings after the duplicated string.
Comment 1 Tim Potter 2004-02-18 14:30:32 UTC
Hmm that doesn't look good does it?

A bit of research on the open group web site shows that strnlen() isn't part of
IEEE 1003.1 and so there is no official description of how strnlen should behave.

Are you seeing some strange errors because of this?
Comment 2 Heinrich Mislik 2004-02-19 03:57:29 UTC
Created attachment 409 [details]
Details for strndup bug
Comment 3 Tim Potter 2004-02-19 16:59:34 UTC
OK that is pretty bad.  I can code up a configure test and a replacement
strnlen() function if a broken one is detected.
Comment 4 Heinrich Mislik 2004-02-20 02:08:26 UTC
Both functions already are in lib/util_str.c
It's only a configure issue.
Comment 5 Tim Potter 2004-02-20 02:30:29 UTC
Ah OK - thanks for the tip.  That will save a bit of work.
Comment 6 Tim Potter 2004-02-20 15:41:36 UTC
Created attachment 416 [details]
Configure test for broken strnlen

Here's the first version of a configure test.  Would you be able to test it
out?  Also, if you can describe how strndup() is broken I can write a test for
it as well.  If it's broken in the same way as strnlen() then it probably
ignores the length argument.
Comment 7 Heinrich Mislik 2004-02-24 02:35:16 UTC
Looks good to me.
As already mentioned, I couldn't find a short example for strndup's failure. I
think it works like this:

char *strndup(char * in, int n)
{
    char *out = malloc(n+1);
    memcpy(out,in,n);
    /* *out = 0; is missing */
    return out;
}

If the malloced buffer contains zeros, this will work, otherwise garbage is at
the end. I tried several sequences of strndup, malloc, free but couldn't trigger
the error.

Since a search for strnlen and strndup in AIX's documntation won't find
anything, I would consider both undocumented and not existent. I suggest to not
use them at all:

if OS == AIX
undef HAVE_STRNDUP
undef HAVE_STRNLEN
endif

This could be changed to
if AIX < 5.x.x
as soon as an AIX version is known to support both offically.
Comment 8 Simo Sorce 2004-08-23 06:07:31 UTC
(In reply to comment #7)

Can you check if this test triggers the problem ?

#include <string.h>
#include <stdlib.h>

main()
{
   char *test = "0123456789";
   char *control = "01234567";
   char *verify;

   verify = strndup(test, 8);
   if (strcmp(control, verify))
       printf("strndup is broken\n");
}

Simo
Comment 9 Heinrich Mislik 2004-08-23 08:04:20 UTC
No, this does not trigger the problem, but now I think I found it:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

main()
{
   char *test1   = "abcdefghijk";
   char *test2   = "0123456789";
   char *control = "012345678";
   char *verify;
   free(strndup(test1, 10));
   verify = strndup(test2, 9); /* shorter then first strndup !!! */
   fprintf(stderr,">%s<\n",verify);
   if (strcmp(control, verify))
       printf("strndup is broken\n");
}

If compiled with -q32 This prints

>012345678j<
strndup is broken

It does not happen when anyone of the following is true:

* the free is left out
* the length of the second strndup is larger then of the first one.
* compiled with -q64 (64 bit).

Note that the strnlen bug happens regardless of 32 or 64 bit.
Comment 10 Heinrich Mislik 2004-08-23 08:42:08 UTC
(In reply to comment #9)

> * compiled with -q64 (64 bit).

Sorry! i was to fast. The following failes regardless of 32 or 64 bit:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

main()
{
   char *test1   = "abcdefghijabcdefghijabcdefghijk";
   char *test2   = "012345678901234567890123456789";
   char *control = "01234567890123456789012345678";
   char *verify;
   free(strndup(test1, 30));
   verify = strndup(test2, 29); /* shorter then first strndup !!! */
   fprintf(stderr,">%s<\n",verify);
   if (strcmp(control, verify))
       printf("strndup is broken\n");
}

Comment 11 Simo Sorce 2004-08-24 00:52:29 UTC
(In reply to comment #10)

Confirmed, with the following test I get wrong results.

int main(void)
{
  char *test = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuwxyz";
  char *control = "0123456789012345678901234567890123456789";
  char *verify;
  verify = strndup(test,45);
  printf("strndup n.1: [%s]\n", verify);
  free(verify);
  verify = strndup(control,30);
  printf("strndup n.2: [%s]\n", verify);
}

Simo.
Comment 12 Gerald (Jerry) Carter (dead mail address) 2005-02-05 07:43:22 UTC
Is this still an issue on 3.0.11 ?  Please reopen if necessary.
Comment 13 Gerald (Jerry) Carter (dead mail address) 2005-08-24 10:17:13 UTC
sorry for the same, cleaning up the database to prevent unecessary reopens of bugs.