Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_is_arrayref, _is_hashref and _is_coderef is incorrectly defined #12

Closed
pali opened this issue Nov 21, 2017 · 9 comments
Closed

_is_arrayref, _is_hashref and _is_coderef is incorrectly defined #12

pali opened this issue Nov 21, 2017 · 9 comments

Comments

@pali
Copy link

pali commented Nov 21, 2017

See implementation: https://github.com/Tux/Text-CSV_XS/blob/master/CSV_XS.xs#L60:

#define _is_arrayref(f) ( f && \
     (SvROK (f) || (SvRMAGICAL (f) && (mg_get (f), 1) && SvROK (f))) && \
      SvOK (f) && SvTYPE (SvRV (f)) == SVt_PVAV )
#define _is_hashref(f) ( f && \
     (SvROK (f) || (SvRMAGICAL (f) && (mg_get (f), 1) && SvROK (f))) && \
      SvOK (f) && SvTYPE (SvRV (f)) == SVt_PVHV )
#define _is_coderef(f) ( f && \
     (SvROK (f) || (SvRMAGICAL (f) && (mg_get (f), 1) && SvROK (f))) && \
      SvOK (f) && SvTYPE (SvRV (f)) == SVt_PVCV )

Code first checks for SvRMAGICAL() and then calls mg_get(). But SvRMAGICAL checks for SVs_RMG -- magic different from get/set, in most cases uses for clear function. So it does not make sense to call mg_get() method based on SVs_RMG result.

Instead SvRMAGICAL() there should be used SvGMAGICAL(), check for SVs_GMG that scalar has get magic which means that mg_get needs to be called.

To simplify code I would propose to use SvGETMAGIC() macro which calls mg_get() when it is needed. E.g. _is_arrayref(f) could looks like this:

static inline bool _is_arrayref(SV *sv) {
    if (!sv) return false;
    SvGETMAGICAL(sv);
    if (!SvROK(sv)) return false;
    if (SvTYPE(SvRV(sv)) != SVt_PVAV) return false;
    return true;
}
@Tux
Copy link
Owner

Tux commented Nov 21, 2017

Can you write that as a macro? As inline is not supported on all compilers, and I'd hate to make those slow just because gcc can do a better job

@Tux
Copy link
Owner

Tux commented Sep 13, 2018

@pali do you have a test case that fails under the current code?

@pali
Copy link
Author

pali commented Sep 23, 2018

For test case you need to take scalar which do not have SVs_RMG, but has SVs_GMG. Then mg_get() would never be called.

@pali
Copy link
Author

pali commented Sep 23, 2018

Can you write that as a macro?

Yes, just rewrite commands via standard boolean logic into one if statement. E.g.:

#define _is_arrayref(sv) ((sv) && (SvGETMAGICAL(sv), 1) && (SvROK(sv)) && (SvTYPE(SvRV(sv)) == SVt_PVAV))

@Tux
Copy link
Owner

Tux commented Sep 24, 2018

#define _is_reftype(f,x) \
    (f && (SvGETMAGIC (f), 1) && SvROK (f) && SvTYPE (SvRV (f)) == x)
#define _is_arrayref(f) _is_reftype (f, SVt_PVAV)
#define _is_hashref(f)  _is_reftype (f, SVt_PVHV)
#define _is_coderef(f)  _is_reftype (f, SVt_PVCV)

Still passed all tests. I could not come up with a new test in t/76_magic.t to probe the old code was wrong, but this looks cleaner anyway.
BTW it is SvGETMAGIC (sv) not SvGETMAGICAL (sv).
See 0fafcee

@pali
Copy link
Author

pali commented Sep 24, 2018

For example magic variable $$ has GMG and does not have RMG. But it is not reference. I do not know currently which internal perl variable is magic, reference and also without RMG.

@Tux
Copy link
Owner

Tux commented Sep 24, 2018

Sure, but I still could not (yet) come up with a test :)

@Tux
Copy link
Owner

Tux commented Sep 25, 2018

Change passed all tests on all 200+ perl versions I have that should be supported and all 858 modules on CPAN that directly or indirectly depend on my still pass. The speed test did not show a slowdown.
Just have to check on the other architectures, and it will be on its way to CPAN.
Thanks again for your input and feedback.

@Tux
Copy link
Owner

Tux commented Nov 11, 2018

Released in 1.37. Closing

@Tux Tux closed this as completed Nov 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants