Skip to contentSkip to conversation

lots of questions (va_list, embedded perl, cvsd, introduction - sort of)

DISCUSSION Alex Avriette 4 participants 11 messages Dec 5, 2000 1 message not in the archive

lore
Share & tools
lore
#1 lore raw
In reply to a message not in the archive

first i wanted to give everyone a brief introduction so somebody can tell me to go away if im in the wrong place. the description on lists.linuxppc.org says that its for linuxppc developers. well, im a developer, and i use linuxppc, but im not developing linuxppc. im actively participating in the development of a couple items. opennap (opennap.sourceforge.net), which is an opensource napster server. tear (tear.sourceforge.net), which is a perl script that rips and encodes cds->mp3's very easily. im also developing a much-less-public foray into artificial intelligence that covers all the bases (c, perl, lisp, and bash). somebody tell me to go away if im in the wrong place.

okay, so to the real meat of this post. ive been having some problems with the opennap server. i find that the va_list functions (primarily v*printf) are giving me segfaults and data corruption. this, however, is *not* happening on an x86 bsd machine. i have limited machines to test this on, so im not quite sure that its glibc, but i have my suspicions. the general behaviour is thus:

if i have one va_list and i use it twice, with two separate va_start-va_end clauses, the second one segfaults. i believe this is because the string in the second clause gets null'ed and strlen() segfaults. gdb falsely reports soinit.c:59, but i tracked down that issue on google. :)

i wrote a chassis to reproduce this, and have added it to the bottom of this message. the actual code which causes problems is here:

void
log (const char *fmt, ...)

{
    va_list ap;

    char buf[1024];

    va_start (ap, fmt); vsnprintf ( buf, 1022, fmt, ap ); va_end (ap);
    va_start (ap, fmt); vprintf ( fmt, ap ); va_end (ap);

    fputc ('\n', stdout);
    fflush (stdout);

    putchan ( "#log", "logd", buf );
}

in the above code, buf is null. furthermore, in the second va_start-end clause, ap is clobbered. so putchan never has anything to "put." because the chassis is so thorough, i am adding it to the bottom of the message so my next question actually gets read. but i would really love it if people would take it and run it and tell me what they get.

there is an irc server written in perl. its called pircd, and i believe its available at pircd.sourceforge.net. at any rate, the author makes the excellent observation "well, if youre going to make a server that is based on chat and text, what *better* language to write it in than perl?" so, because this napster server is so string-heavy, i have decided i'd like to embed perl into it. i have every perl book oreilly makes and a few others. _advanced_perl_programming_ has two chapters on embedded perl. the most promising part of it is the Ext::Embed module. my main difficulty here is that the code in APP is non-object oriented and monolithic. i had amazon send me a few books, notably the oreilly _make_ book and a book on c++ authoring in gnu. these should help but im looking for some nudges in the right direction. has anyone on the list used embedded perl?

okay, next question. i want to run cvs. our network is comprised of six servers at the moment, and i would like my fellow administrators to be able to sync up my current source tree. i havent found any rpms for cvsd, and i would preferr a tarball. in fact, i dont have rpm. so a tarball would be, er, necessary. :) i suppose rsync would work too, but i dont know about the server-side of that transaction.

sorry to ask so many questions at once. but i trust you all have the smarts and patience to help (or tell me to go away! heh!).

anyway, here's the chassis for va_list and v*printf (use gcc filename.c -o filename):

/* begin */
#include <stdarg.h>
#include <stdio.h>

void vsn_test ( const char *fmt, ...)
{
va_list ap; char buf [1024]; int i;

  va_start ( ap, fmt ); vsnprintf ( buf, 1022, fmt, ap ); va_end ( ap );

for (i = 1; i < 5; i++)

  { printf ( "pass [%d] %s\n", i, buf );
    va_start ( ap, fmt ); vsnprintf ( buf, 1022, fmt, ap ); va_end ( ap ); }
}

void v_test ( const char *fmt, ...)
{
va_list ap; int i;

for (i = 1; i != 5; i++)

  { printf ( "pass [%d] ", i );
    va_start ( ap, fmt ); vprintf ( fmt, ap ); va_end ( ap ); printf ("\n"); }
}

void vs_test ( const char *fmt, ...)
{
va_list ap; char buf[1024]; int i;

for (i = 1; i != 5; i++)

  { printf ("pass [%d] %s\n", i );
    va_start ( ap, fmt ); vsprintf ( buf, fmt, ap ); va_end ( ap ); }
}

void dual_va_test ( const char *fmt, ...)
{
va_list ap; char buf [1024]; int i;

for (i = 1; i < 5; i++)

  { va_start ( ap, fmt ); vsnprintf ( buf, 1022, fmt, ap); va_end ( ap ) ;
    printf ( "dual-run pass [%d][vsn] %s\n", i, buf );
    printf ( "dual-run pass [%d][v] ", i);
    va_start ( ap, fmt ); vprintf ( fmt, ap ); va_end ( ap ); printf ("\n"); }
}

void nested_test ( const char *fmt, ...)
{
va_list ap; char bufa [1024]; char bufb [1024]; int i;

  for (i = 1; i < 5; i++)
  { va_start ( ap, fmt );
    vsnprintf ( bufa, 1022, fmt, ap );
    vsnprintf ( bufb, 1022, fmt, ap );
    va_end ( ap );
    printf ("buffer [a] pass [%d]: %s\n", i, bufa);
    printf ("buffer [b] pass [%d]: %s\n", i, bufb); }
}

void main (void)
{
int tf = 25; char string[256] = "somestring";

  vsn_test     ( "int: %d string: %s", tf, string );
  vs_test      ( "int: %d string: %s", tf, string );
  v_test       ( "int: %d string: %s", tf, string );

dual_va_test ( "int: %d string: %s", tf, string ); nested_test ( "int: %d string: %s", tf, string );
}
/* end */

anyhow. thanks everyone.

alex

--
alex avriette [[email protected]]

"No man who uses EMACS is deserving of love."

	Tom Christiansen <[email protected]>,
	_Perl Cookbook_, pp. 653

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

#2 lore raw
Quoted 4 lines

okay, so to the real meat of this post. ive been having some problems with the opennap server. i find that the va_list functions (primarily v*printf) are giving me segfaults and data corruption. this, however, is *not*

Make sure you are using __va_copy to copy va_list arguments. Plus do not expect a va_list argument to remain unchanged in the calling routine even though you pass the va_list argument by value.

Quoted 1 line

happening on an x86 bsd machine. i have limited machines to test this on,

x86 uses a different mechanism for va_lists, which is more tolerant :-(

Quoted 1 line
    va_start (ap, fmt); vsnprintf ( buf, 1022, fmt, ap ); va_end (ap);

The va_end does nothing here...

#define va_end(AP) ((void)0)

Quoted 1 line
    va_start (ap, fmt); vprintf ( fmt, ap ); va_end (ap);

and the second va_start should just restore the initial state of ap from the stack. Looks like it should work...

Michael

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

#3 lore raw
In reply to Alex Avriette
Quoted 6 lines

in the above code, buf is null. furthermore, in the second va_start-end clause, ap is clobbered. so putchan never has anything to "put." because the chassis is so thorough, i am adding it to the bottom of the message so my next question actually gets read. but i would really love it if people would take it and run it and tell me what they get.

opal:~> ./va-test
pass [1] int: 25 string: somestring
pass [2] int: 25 string: somestring
pass [3] int: 25 string: somestring
pass [4] int: 25 string: somestring
Speicherschutzverletzung (core dumped)

is what I get. On Intel, that is. gcc version is egcs-2.91.66. Seems something's wrong with your code in general.

Michael

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

#9 lore raw
In reply to Alex Avriette
Quoted 15 lines · Alex Avriette

void
log (const char *fmt, ...)

{
    va_list ap;

    char buf[1024];

    va_start (ap, fmt); vsnprintf ( buf, 1022, fmt, ap ); va_end (ap);
    va_start (ap, fmt); vprintf ( fmt, ap ); va_end (ap);

    fputc ('\n', stdout);
    fflush (stdout);

    putchan ( "#log", "logd", buf );
}

This code looks OK. What environment? (gcc/glibc)

Quoted 7 lines

#include <stdarg.h>
#include <stdio.h>

void vsn_test ( const char *fmt, ...)
{
va_list ap; char buf [1024]; int i;

Quoted 6 lines
  va_start ( ap, fmt ); vsnprintf ( buf, 1022, fmt, ap ); va_end ( ap );

for (i = 1; i < 5; i++)

  { printf ( "pass [%d] %s\n", i, buf );
    va_start ( ap, fmt ); vsnprintf ( buf, 1022, fmt, ap ); va_end ( ap );
} }

This works as expected here.

Quoted 8 lines

void v_test ( const char *fmt, ...)
{
va_list ap; int i;

for (i = 1; i != 5; i++)
{ printf ( "pass [%d] ", i );
va_start ( ap, fmt ); vprintf ( fmt, ap ); va_end ( ap ); printf
("\n"); } }

This works as expected here.

Quoted 8 lines

void vs_test ( const char *fmt, ...)
{
va_list ap; char buf[1024]; int i;

for (i = 1; i != 5; i++)

  { printf ("pass [%d] %s\n", i );
    va_start ( ap, fmt ); vsprintf ( buf, fmt, ap ); va_end ( ap ); }
}

This testcase is buggy (look at the printf!), if fixed it behaves as expected. You would have seen that if you compiled with -W -Wall!

Quoted 10 lines

void dual_va_test ( const char *fmt, ...)
{
va_list ap; char buf [1024]; int i;

for (i = 1; i < 5; i++)

  { va_start ( ap, fmt ); vsnprintf ( buf, 1022, fmt, ap); va_end ( ap ) ;
    printf ( "dual-run pass [%d][vsn] %s\n", i, buf );
    printf ( "dual-run pass [%d][v] ", i);
    va_start ( ap, fmt ); vprintf ( fmt, ap ); va_end ( ap ); printf

("\n"); } }

This works as expected here.

Quoted 10 lines

void nested_test ( const char *fmt, ...)
{
va_list ap; char bufa [1024]; char bufb [1024]; int i;

  for (i = 1; i < 5; i++)
  { va_start ( ap, fmt );
    vsnprintf ( bufa, 1022, fmt, ap );
    vsnprintf ( bufb, 1022, fmt, ap );
    va_end ( ap );
Quoted 3 lines
    printf ("buffer [a] pass [%d]: %s\n", i, bufa);
    printf ("buffer [b] pass [%d]: %s\n", i, bufb); }
}

This testcase is bogus since you miss the required va_start/va_end pairs. It misbehaves as expected.

I've tested this both with gcc-2.95.3 and a recent gcc-2.97 snapshot. This looks a lot like your are still using egcs on PPC, don't do that, use gcc-2.95.[23] as the current distributions do.

Franz.

gcc-2.95.3 log:

[fsirl@enzo:/cvsx/bugs]$ ~/gnubin2/bin/gcc -v
Reading specs from
/home/fsirl/gnubin2/lib/gcc-lib/ppc-redhat-linux/2.95.3/specs
gcc version 2.95.3 19991130 (prerelease)
[fsirl@enzo:/cvsx/bugs]$ ~/gnubin2/bin/gcc -O2 -W -Wall va-arg-test.c
[fsirl@enzo:/cvsx/bugs]$ ./a.out
pass [1] int: 25 string: somestring
pass [2] int: 25 string: somestring
pass [3] int: 25 string: somestring
pass [4] int: 25 string: somestring
pass [1] int: 25 string: somestring
pass [2] int: 25 string: somestring
pass [3] int: 25 string: somestring
pass [4] int: 25 string: somestring
pass [1] int: 25 string: somestring
pass [2] int: 25 string: somestring
pass [3] int: 25 string: somestring
pass [4] int: 25 string: somestring
dual-run pass [1][vsn] int: 25 string: somestring
dual-run pass [1][v] int: 25 string: somestring
dual-run pass [2][vsn] int: 25 string: somestring
dual-run pass [2][v] int: 25 string: somestring
dual-run pass [3][vsn] int: 25 string: somestring
dual-run pass [3][v] int: 25 string: somestring
dual-run pass [4][vsn] int: 25 string: somestring
dual-run pass [4][v] int: 25 string: somestring
buffer [a] pass [1]: int: 25 string: somestring
buffer [b] pass [1]: int: 2147480576 string:
buffer [a] pass [2]: int: 25 string: somestring
buffer [b] pass [2]: int: 2147480576 string:
buffer [a] pass [3]: int: 25 string: somestring
buffer [b] pass [3]: int: 2147480576 string:
buffer [a] pass [4]: int: 25 string: somestring
buffer [b] pass [4]: int: 2147480576 string:
[fsirl@enzo:/cvsx/bugs]$

gcc-2.97 log:

[fsirl@enzo:/cvsx/bugs]$ gcc -v
Reading specs from /usr/lib/gcc-lib/ppc-redhat-linux/2.97/specs
Configured with:  --prefix=/usr --mandir=/usr/man --infodir=/usr/info
--enable-shared --enable-threads=posix --host=ppc-redhat-linux
gcc version 2.97 20001106 (experimental)
[fsirl@enzo:/cvsx/bugs]$ gcc -O2 -W -Wall va-arg-test.c
[fsirl@enzo:/cvsx/bugs]$ ./a.out
pass [1] int: 25 string: somestring
pass [2] int: 25 string: somestring
pass [3] int: 25 string: somestring
pass [4] int: 25 string: somestring
pass [1] int: 25 string: somestring
pass [2] int: 25 string: somestring
pass [3] int: 25 string: somestring
pass [4] int: 25 string: somestring
pass [1] int: 25 string: somestring
pass [2] int: 25 string: somestring
pass [3] int: 25 string: somestring
pass [4] int: 25 string: somestring
dual-run pass [1][vsn] int: 25 string: somestring
dual-run pass [1][v] int: 25 string: somestring
dual-run pass [2][vsn] int: 25 string: somestring
dual-run pass [2][v] int: 25 string: somestring
dual-run pass [3][vsn] int: 25 string: somestring
dual-run pass [3][v] int: 25 string: somestring
dual-run pass [4][vsn] int: 25 string: somestring
dual-run pass [4][v] int: 25 string: somestring
Segmentation fault
[fsirl@enzo:/cvsx/bugs]$

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

#4 lore raw
In reply to Michael Schmitz

And lo there was much discussion regarding:

-snip-

Quoted 5 lines

pass [4] int: 25 string: somestring
Speicherschutzverletzung (core dumped)

is what I get. On Intel, that is. gcc version is egcs-2.91.66. Seems something's wrong with your code in general.

well, thats the thing. there isnt, i dont think, wrong with my code (apart from what you said earlier (later? i get this as being 15 minutes "new"er). it doesnt segfault at all here. i get some screwed up variables, though, in the nested_va test. however, that clearly isnt the way to run it. the part that caught my attention is i cannot have *two* va_start clauses in one function in the code that im running, which, like i said, is available at opennap.sourceforge.net. i would really appreciate somebody else giving me a heads-up on this. what i get when i ask the other opennap developers is "that crazy ppc machine is just going to crash, its a *mac*." i suspect there is something deeper going on here.

i will look into the __va_copy.

alex

--
alex avriette [[email protected]]

"No man who uses EMACS is deserving of love."

	Tom Christiansen <[email protected]>,
	_Perl Cookbook_, pp. 653

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

#10 lore raw
In reply to Franz Sirl

And lo there was much discussion regarding:

Quoted 4 lines
Quoted 2 lines

void
log (const char *fmt, ...)

This code looks OK. What environment? (gcc/glibc)

from glibcbug:

Host type: powerpc-redhat-linux-gnu
System: Linux macachu 2.4.0-test11 #5 Sun Nov 26 13:51:22 EST 2000 ppc unknown
Architecture: ppc

Addons: crypt linuxthreads
Build CFLAGS: -g -O2
Build CC: gcc
Compiler version: 2.95.2 19991024 (release/franzo) Kernel headers: 2.4.0-test11
Symbol versioning: yes
Build static: yes
Build shared: yes
Build pic-default: no
Build profile: yes
Build omitfp: no
Build bounded: no
Build static-nss: no
Stdio: libio

Quoted 4 lines
Quoted 1 line

void vs_test ( const char *fmt, ...)

This testcase is buggy (look at the printf!), if fixed it behaves as expected. You would have seen that if you compiled with -W -Wall!

whoops! (blush!) gotcha.

Quoted 4 lines
Quoted 1 line

void nested_test ( const char *fmt, ...)

This testcase is bogus since you miss the required va_start/va_end pairs. It misbehaves as expected.

let me check with the bsd guy, but AIR, it runs without the two pairs. i could be wrong.

Quoted 3 lines

I've tested this both with gcc-2.95.3 and a recent gcc-2.97 snapshot. This looks a lot like your are still using egcs on PPC, don't do that, use gcc-2.95.[23] as the current distributions do.

all my experience writing c was in dos on borland c++, years ago. im actually not sure about egcs, except that i get the error in gdb. how can i be sure, and if i am, how can i switch?

thanks, franz.

alex

--
alex avriette [[email protected]]

"No man who uses EMACS is deserving of love."

	Tom Christiansen <[email protected]>,
	_Perl Cookbook_, pp. 653

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

#11 lore raw
Quoted 35 lines · Alex Avriette

And lo there was much discussion regarding:

Quoted 4 lines
Quoted 2 lines

void
log (const char *fmt, ...)

This code looks OK. What environment? (gcc/glibc)

from glibcbug:

Host type: powerpc-redhat-linux-gnu
System: Linux macachu 2.4.0-test11 #5 Sun Nov 26 13:51:22 EST 2000 ppc unknown
Architecture: ppc

Addons: crypt linuxthreads
Build CFLAGS: -g -O2
Build CC: gcc
Compiler version: 2.95.2 19991024 (release/franzo) Kernel headers: 2.4.0-test11
Symbol versioning: yes
Build static: yes
Build shared: yes
Build pic-default: no
Build profile: yes
Build omitfp: no
Build bounded: no
Build static-nss: no
Stdio: libio

Quoted 4 lines
Quoted 1 line

void vs_test ( const char *fmt, ...)

This testcase is buggy (look at the printf!), if fixed it behaves as expected. You would have seen that if you compiled with -W -Wall!

whoops! (blush!) gotcha.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

void nested_test ( const char *fmt, ...)

This testcase is bogus since you miss the required va_start/va_end pairs. It misbehaves as expected.

let me check with the bsd guy, but AIR, it runs without the two pairs. i could be wrong.

It may run on some platforms by accident, but this is simply illegal C code if you want to process the same AP 2 times without an intervening va_end()/va_start() pair.

Quoted 7 lines
Quoted 3 lines

I've tested this both with gcc-2.95.3 and a recent gcc-2.97 snapshot. This looks a lot like your are still using egcs on PPC, don't do that, use gcc-2.95.[23] as the current distributions do.

all my experience writing c was in dos on borland c++, years ago. im actually not sure about egcs, except that i get the error in gdb. how can i be sure, and if i am, how can i switch?

rpm -q binutils egcs gcc glibc

You can get current stuff at ftp://devel.linuxppc.org/users/fsirl/glibc-2.1/RPMS/ppc/

Franz.

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

#5 lore raw
In reply to Alex Avriette
Quoted 10 lines
Quoted 6 lines

pass [4] int: 25 string: somestring
Speicherschutzverletzung (core dumped)

is what I get. On Intel, that is. gcc version is egcs-2.91.66. Seems something's wrong with your code in general.

well, thats the thing. there isnt, i dont think, wrong with my code (apart from what you said earlier (later? i get this as being 15 minutes "new"er). it doesnt segfault at all here. i get some screwed up variables,

It does segfault for me, on an Intel Redhat system. So far I haven't noticed unexplained breakage compiling other programs on Intel machines, though there's been a number of obscure programming errors that show only occasional segfaults. The fact that it doesn't segfault for you does not constiute proof that it's correct code.

Anyway, this is what happens on PPC:

pass [1] int: 25 string: somestring
pass [2] int: 25 string: somestring
pass [3] int: 25 string: somestring
pass [4] int: 25 string: somestring
pass [1] somestring
pass [2] (null)
pass [3] (null)
pass [4] (null)
pass [1] int: 25 string: somestring
pass [2] int: 25 string: somestring
pass [3] int: 25 string: somestring
pass [4] int: 25 string: somestring
dual-run pass [1][vsn] int: 25 string: somestring
dual-run pass [1][v] int: 25 string: somestring
dual-run pass [2][vsn] int: 25 string: somestring
dual-run pass [2][v] int: 25 string: somestring
dual-run pass [3][vsn] int: 25 string: somestring
dual-run pass [3][v] int: 25 string: somestring
dual-run pass [4][vsn] int: 25 string: somestring
dual-run pass [4][v] int: 25 string: somestring
buffer [a] pass [1]: int: 25 string: somestring
buffer [b] pass [1]: int: 2147480592 string:
buffer [a] pass [2]: int: 25 string: somestring
buffer [b] pass [2]: int: 2147480592 string:
buffer [a] pass [3]: int: 25 string: somestring
buffer [b] pass [3]: int: 2147480592 string:
buffer [a] pass [4]: int: 25 string: somestring
buffer [b] pass [4]: int: 2147480592 string:

No segfault. Just garbage if you use vsnprintf (which completely exhausts the va_list so there are no unprocessed arguments left after the call) twice without restoring ap in between.
Now what exactly did you expect to happen in that case? Garbage (or segfaults due to what precisely was left on the stack from previous operations) is all you will get if you call vsnprintf with a va_list argument that has its internal pointers to the next arguments set to beyond what was allocated on stack for the arguments.
Please see the definitions of the va_list type, and the va_arg macro, in va-ppc.h.

I don't care what the maintainers of opennap claim about 'it can't run on Mac because Mac is broken anyway'. Writing portable code may be tough in this special neck of the woods, but it's possible. I've seen maintainers of other free software packages act reasonably about this very issue. Send them a patch, and explain why the patch is required.

Michael

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

#7 lore raw
In reply to Alex Avriette
Quoted 10 lines
Quoted 6 lines

pass [4] int: 25 string: somestring
Speicherschutzverletzung (core dumped)

is what I get. On Intel, that is. gcc version is egcs-2.91.66. Seems something's wrong with your code in general.

well, thats the thing. there isnt, i dont think, wrong with my code (apart from what you said earlier (later? i get this as being 15 minutes "new"er). it doesnt segfault at all here. i get some screwed up variables,

I found the reason for the segfault, BTW. Please compile your test code using the -Wall option to see for yourself.

Thanks for wasting my time.

Michael

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/

#6 lore raw
In reply to Michael Schmitz

And lo there was much discussion regarding:

Quoted 3 lines

No segfault. Just garbage if you use vsnprintf (which completely exhausts the va_list so there are no unprocessed arguments left after the call) twice without restoring ap in between.

thanks, franz has explained this quite a bit.

Quoted 5 lines

I don't care what the maintainers of opennap claim about 'it can't run on Mac because Mac is broken anyway'. Writing portable code may be tough in this special neck of the woods, but it's possible. I've seen maintainers of other free software packages act reasonably about this very issue. Send them a patch, and explain why the patch is required.

thats what im doing here, trying to get everything figured out in the context of the ppc so i can submit a patch and explain why.

thanks michael.

--
alex avriette [[email protected]]

"No man who uses EMACS is deserving of love."

	Tom Christiansen <[email protected]>,
	_Perl Cookbook_, pp. 653

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/