http://www.perlmonks.org?node_id=924529

xiaoyafeng has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks,

I wrote a simple snippet to list processes name and pid on windows. but the output returns a strange line. below is the code:

use strict; use warnings; use Inline C => DATA => LIBS => '-luser32 -lkernel32 -lpsapi'; my $a = process_list(); map { print; print get_proc_name($_);print "\n"; } @{$a}; __END__ __C__ #include <windows.h> #include <stdio.h> #include <tchar.h> #include <psapi.h> char* get_proc_name( int processID ) { TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>"); HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID ); if (NULL != hProcess ) { HMODULE hMod; DWORD cbNeeded; if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) ) { GetModuleBaseName( hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(TCHAR) ); } } CloseHandle( hProcess ); return szProcessName; } SV* process_list(){ DWORD aProcesses[1024], cbNeeded, cProcesses; unsigned int i; EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ); cProcesses = cbNeeded / sizeof(DWORD); AV* AV_procs = newAV(); for ( i = 0; i < cProcesses; i++ ) { if( aProcesses[i] != 0 ) { av_push(AV_procs, newSViv( aProcesses[i] ) ); } } return newRV_inc(AV_procs); } __OUTPUT__ C:\>perl test.pl 4P ?F > <== strange line 292<unknown> 372<unknown> 432<unknown>
I post this question on Inline and Sisyphus (many Thanks! Sisyphus) replied me and suggest me posting this question on perlmonks for help. here is his reply:
Haven't yet had a chance to take a thorough look at this. I inserted the following near the beginning of your script: use Inline C => Config => BUILD_NOISY => 1; That way you get to see any compiler warnings that are emitted during +the C compilation, and with my cc-4.5.2 build of perl-5.14 I saw: try_pl_f4a3.xs: In function 'get_proc_name': try_pl_f4a3.xs:35:1: warning: function returns address of local variab +le try_pl_f4a3.xs: In function 'process_list': try_pl_f4a3.xs:57:5: warning: passing argument 2 of 'Perl_newRV' from +incompatible pointer type C:\MinGW\perl\lib\CORE/proto.h:2567:19: note: expected 'struct SV * co +nst' but argument is of type 'struct AV *' Whether there's anything relevant there, I don't know. I get different output to you, of course. But in the middle of the out +put I also got one odd-looking line: 1348&#9508;aæ&#9787;&#8593;:ñ $ &#8593;:ñ ~&#8593;&#9787; When I switched to a gcc-3.4.5 build of perl-5.12, I found out what 13 +48 really was: 1348TomTomHOMERunner.exe But then I got a strange line at the beginning of the output: 4ð¬&#9472;w4§Å &#8593; whereas, with gcc-4.5.2, that had been: 4<unknown>

Thanks in advance!!!





I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

Replies are listed 'Best First'.
Re: odd line in windows
by BrowserUk (Patriarch) on Sep 07, 2011 at 07:52 UTC

    The likely cause is identified by

    try_pl_f4a3.xs: In function 'get_proc_name': try_pl_f4a3.xs:35:1: warning: function returns address of local variab +le

    Which is telling you that this:

    char* get_proc_name( int processID ) { TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>"); ... return szProcessName; }

    Is a fundamentally flawed piece of code. You are allocating a string on the stack, and then returning a pointer to it from the function. But when the function returns, the stack is unwound and can be reused by other parts of the code.

    The only surprising thing here is that you actually get something returned and it doesn't crash.

    You need to correct that by allocating space on the heap using Newx() or Newxc() or Newxz(). See perlapi

    That said. I wonder why you aren't using Win32::Process::Info?


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Many Thanks, BrowserUk! Returning a variable on stack is a fundamental mistake indeed. I change

      TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");

      into
      TCHAR * szProcessName = (TCHAR*) malloc( MAX_PATH * sizeof(TCHAR) );

      it looks like working well now. but sequenced question is, how free this memory I allocate in C?

      That said. I wonder why you aren't using Win32::Process::Info?

      I don't using Wi32::Process::Info is because it's running a bit slowly. it uses variable way to get Process info and return too large info to me. In my case, I just want to check process name.





      I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

        I change = TEXT("<unknown>"); into = (TCHAR*) malloc( MAX_PATH * sizeof(TCHAR) ); it looks like working well now. but sequenced question is, how free this memory I allocate in C?

        You should not be using malloc(). Did you miss my mention of Newx(), Newxc() Newxz() and the associated link?

        how free this memory I allocate in C?

        If you followed the link, you would have seen Safefree()

        In my case, I just want to check process name.

        I tend to use tasklist for that:

        perl -E"my @tasks = map[ (split)[0,1] ], `tasklist /nh`; say qq[@$_] f +or @tasks"

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        but sequenced question is, how free this memory I allocate in C?

        One way is to create a copy, free the memory, then return the copy.

        The following rewrite of get_proc_name() works for me, and frees the memory:
        SV * get_proc_name( int processID ) { char * szProcessName; SV * outsv; Newxz(szProcessName, MAX_PATH, char); HANDLE hProcess = OpenProcess ( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID ); if (NULL != hProcess ) { HMODULE hMod; DWORD cbNeeded; if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNee +ded) ) { GetModuleBaseName( hProcess, hMod, szProcessName, MAX_PATH + - 1); } else { szProcessName[0] = '#'; szProcessName[1] = 0; } } else { szProcessName[0] = '*'; szProcessName[1] = 0; } CloseHandle( hProcess ); outsv = newSVpv(szProcessName, 0); Safefree(szProcessName); return outsv; }
        Cheers,
        Rob
Re: odd line in windows
by syphilis (Archbishop) on Sep 07, 2011 at 16:06 UTC
    try_pl_f4a3.xs:57:5: warning: passing argument 2 of 'Perl_newRV' from incompatible pointer type

    This warning is in response to:
    return newRV_inc(AV_procs);
    and I think that's not quite the right thing to be doing.
    According to perlapi, newRV_inc() takes an SV* arg, but AV_procs is an AV*.

    Rewriting process_list() as follows avoids the warning, and intuitively strikes me as being a better approach:
    AV* process_list(){ DWORD aProcesses[1024], cbNeeded, cProcesses; unsigned int i; EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ); cProcesses = cbNeeded / sizeof(DWORD); AV* AV_procs = newAV(); for ( i = 0; i < cProcesses; i++ ) { if( aProcesses[i] != 0 ) { av_push(AV_procs, newSViv( aProcesses[i] ) ); } } return AV_procs; }
    Cheers,
    Rob
      new function does avoid the warning, but what does AV* mean in perl? a SV* are able to be a reference of array other than a AV*. though I'm still digging how this warning come, I insist using SV* as returning.




      I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

        The typemap automatically creates a reference to it and returns the reference. It's refcount is off by one, though.

        use strict; use warnings; use Devel::Peek qw( Dump ); use Inline C => <<'__EOI__'; AV* f() { return newAV(); } __EOI__ Dump(f());
        >perl -MInline=FORCE,NOISY,NOCLEAN a.pl ... SV = IV(0x7bbf18) at 0x7bbf1c REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x7bc05c SV = PVAV(0x7bcec8) at 0x7bc05c REFCNT = 2 <--- XXX FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL)

        Making it mortal doesn't help. So unless I'm missing something, this can only be used if you actually hold a reference to the array you return.

      and I think that's not quite the right thing to be doing. According to perlapi, newRV_inc() takes an SV* arg, but AV_procs is an AV*.

      An AV is a type of SV. That's indeed the way to create a reference to an array. You just need to cast.

      newRV_noinc(MUTABLE_SV(av))