Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Re^3: Inline::C and NULL pointers

by syphilis (Archbishop)
on Dec 19, 2021 at 21:42 UTC ( [id://11139743]=note: print w/replies, xml ) Need Help??


in reply to Re^2: Inline::C and NULL pointers
in thread Inline::C and NULL pointers

but I need to pass "NULL" pointers to the functions

How to do that is an interesting puzzle. I've been playing with this little Inline::C demo:
use strict; use warnings; use Inline C => Config => BUILD_NOISY => 1, ; use Inline C =><<'EOC'; unsigned char * foo(unsigned char * name) { if(name) printf("True\n"); else printf("False\n"); return(NULL); } unsigned char * bar() { return (foo(NULL)); } EOC foo(undef); bar(); __END__ Outputs: True False
The question is: "How can I call foo() directly from perl such that it will output "False" ? One way is to call bar() which then calls foo() - and I think that the OP's existing enctypex_msname function could be accessed (as is) via this technique of calling a wrapper function . But that's still not a direct call to foo().

AFAICT, the issue is the typemapping of "unsigned char *" (which can be found in perl's lib/ExtUtils/typemap file).
This default typemapping types "unsigned char *" to T_PV, but if we change that to T_PTR, then calling foo(undef) in my little demo will have it output "False" as desired. (I expect this is what SWIG, in effect, does.)

Inline::C allows us to use our own typemaps, so I wrote an alternative typemap for unsigned char * and I placed that file (named "nullmap.txt") in the same directory as the script, and pointed the script to it (in the inline configuration section). Unfortunately, the default typemapping was still used.
So ... as proof of concept, I replaced "unsigned char *" in nullmap.txt with "unmapped". It looks like this:
# plagiarised from default perl typemap unmapped T_PTR INPUT T_PTR $var = INT2PTR($type,SvIV($arg)) OUTPUT T_PTR sv_setiv($arg, PTR2IV($var));
Then, in the script, I typedeffed the "unsigned char *" to "unmapped", and replaced "unsigned char *" with "unmapped" in the function declaration:
use strict; use warnings; use Inline C => Config => TYPEMAPS => "nullmap.txt", BUILD_NOISY => 1, ; use Inline C =><<'EOC'; typedef unsigned char * unmapped; unmapped foo(unmapped name) { if(name) printf("True\n"); else printf("False\n"); return(NULL); } unsigned char * bar() { return (foo(NULL)); } EOC foo(undef); bar(); __END__ Outputs: False False
So we have 2 essentially identical scripts that output different results. One of them specifies an "unmapped" type where the other specifies "unsigned char *" - yet the two types are the same thing. The difference occurs because the two types employ different typemapping.

Note that it should not be necessary to replace *all* occurrences of "unsigned char *" with "unmapped" (or whatever replacement name is chosen) - just renaming those occurrences found in the declaration would be all that's needed.
And then there's the question of whether both the return type and the argument type should be rewritten to "unmapped". (Perhaps it's only the argument type that needs to be renamed.)
Also, when fiddling around with Inline scripts, we need to remember that a change to the Inline Config section will not trigger a recompilation of the C code unless that Config section specifies FORCE_BUILD => 1. Otherwise, it's necessary to alter the actual code section.

I'm surprised that specifying an alternative Inline::C typemap doesn't override the default typemap for any types that are specified in both.
Is that an Inline::C bug ? Or a design flaw ?
Maybe it's the way it has to be.

Cheers,
Rob

Replies are listed 'Best First'.
Re^4: Inline::C and NULL pointers ( override default xsubpp ExtUtils::ParseXS::Utilities::process_typemaps )
by Anonymous Monk on Dec 20, 2021 at 03:28 UTC

    I think I see how typemaps work (bug, skip to end)

    Digging down T_PTR is clobbered even if you don't specify the default typemap (see output of program, BROKEN_ gets replaced )

    #!/usr/bin/perl -- use strict; use warnings; use ExtUtils::ParseXS::Utilities qw/ process_typemaps /; use Data::Dump qw/ dd /; dd( process_typemaps( './mytypemap.txt', ) ); __END__

    So it makes sense or its documentation bug or behavior bug ... I dunno , I haven't used a keyboard in 6 months

      Indicates that a user-supplied typemap should take precedence over the default typemaps. This option may be used multiple times, with the last typemap having the highest precedence.

      Thanks for digging that up.
      I really do think it would be better if our user-supplied typemap took precedence over ExtUtils/typemap. (This is something that should probably be investigated further.)

      But it seems by using unmapped T_PTR you're getting the old T_PTR, not the new one, you can't redefine T_PTR, which makes sense.

      My T_PTR is the same as the original T_PTR, as there was nothing wrong with the original.
      I just had to change the typing of unsigned char* from T_PV to T_PTR. I could only make that switch for the unmapped type, which was a typedef of unsigned char*.
      Seems I won't need that typedef if I can get the two typemaps to load in the reverse order.

      I've just checked and found that I didn't need to provide the T_PTR "INPUT" and "OUTPUT" routines in my custom typemap ("nullmap.txt").
      That file needs only to consist of:
      unmapped T_PTR
      and the T_PTR "INPUT" and "OUTPUT" routines will be read from ExtUtils/typemap.
      Apologies - I did wonder about that at the time, but didn't spend the 10 seconds it takes to find out.
      'Twould have been much clearer if I had presented the one-line "nullmap.txt" instead of the multi-line version with its "INPUT" and "OUTPUT" sections.

      Cheers,
      Rob
        I really do think it would be better if our user-supplied typemap took precedence over ExtUtils/typemap.

        Turns out it does ... but only if it's named "typemap" and is in the current working directory. (Calling it something else is alone insufficient - on my Windows 7 system, at least.)
        It then turns out that there's no need for the typedeffing either.

        This is a much simpler way of ensuring that undef is passed as a NULL:
        1) Have a file named exactly "typemap" in the cwd that contains the following single line (ending in a newline):
        unsigned char * T_PTR
        2) The following demo script then passes 'undef' as a NULL to the C function foo():
        use strict; use warnings; use Inline C => Config => BUILD_NOISY => 1, # verbose build FORCE_BUILD => 1, # re-build whenever the script is run CLEAN_AFTER_BUILD => 0, # don't clean up the build directory ; use Inline C =><<'EOC'; unsigned char *foo(unsigned char *name) { if(name) printf("True\n"); else printf("False\n"); return(NULL); } EOC foo(undef); __END__ Outputs: Use of uninitialized value in subroutine entry at try2.pl line 20. False
        I don't know why naming the typemap to something other than "typemap" should be inadequate - even stranger that it then could be made to work if unsigned char* was typedeffed to something else.
        Unless I can find some documentation that explains that weirdness, then I can only think that it's an Inline::C bug.
        I'll investigate that this issue and try to come up with a patch that fixes it if it's indeed a bug.

        Note that the file named "typemap" gets found automatically if it's located in the CWD. There's no need to engage the "TYPEMAPS" configuration option.

        UPDATE: It seems that a file named "typemap" will also be found and used automatically if it's in the .. or the lib/ExtUtils directory.
        If it's not called "typemap" && it's not in lib/ExtUtils or . or .. directories, then its location will be passed on to xsubpp (which will acknowledge that it has been informed of the file's existence) if and only if the file's location is specified in the 'TYPEMAPS' Config entry.
        But then xsubpp just silently ignores it completely unless it maps a type not covered by the files named "typemap" that were automatically found. (Hence my "nullmap.txt" from a previous post was able to be used.)
        As Bill Burroughs once said, "this is *insane* ... this *is* insane ... *this* is insane".
        Where should issues/PRs for EU::ParseXS be filed ? .

        Cheers,
        Rob

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11139743]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (6)
As of 2024-04-19 10:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found