If I create some async perl code, but don't call SNMP::MainLoop() or e.g. exit in a callback, then perl dies with a Segmentation fault.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/usr/bin/perl -w use strict; use SNMP; # A strange thing... # # using any of many non-trivial modules seems to do the trick of making SNMP # cause a segmentation fault. At least Moo does for me. But removing the use # statement and it works in my tests so far. use Moo; my $sess = SNMP::Session->new( 'DestHost' => '1.2.3.4', 'Version' => '2c', 'Community' => 'public', ); # Setting up a callback $sess->get( [ [ 'ifInOctets', 1 ] ], sub { } ); # But not starting the MainLoop causes SNMP to segmentation fault # SNMP::MainLoop(); |
I've looked in SNMP.xs and when it dies, sess_ref
can be NULL
or ((HV*)SvRV(sess_ref))
can be NULL
.
My testing suggests that this is because during global destruction, the sess_ref
could've been destroyed first.
In the supplied patch, we test for ${^GLOBAL_PHASE} eq "DESTRUCT"
and if true, it doesn't try to call any remaining callbacks. Patch (also attached):
--- net-snmp-5.7.2.1+dfsg.orig/perl/SNMP/SNMP.xs 2018-04-24 13:17:18.495389000 +0200 +++ net-snmp-5.7.2.1+dfsg/perl/SNMP/SNMP.xs 2018-04-24 15:44:05.451389000 +0200 @@ -1199,6 +1199,20 @@ netsnmp_transport *transport = NULL; SV* cb = ((struct snmp_xs_cb_data*)cb_data)->perl_cb; + // During global destruction, + // sess_ref can be NULL or + // ((HV*)SvRV(sess_ref)) can be NULL + // So test for global destruction + // ${^GLOBAL_PHASE} starts with a CTRL-G == chr(7) + // see perldoc perlvar + SV* global_phase_sv = get_sv("\x07LOBAL_PHASE" , 0); + if (global_phase_sv != NULL) { + const char *global_phase = SvPVutf8_nolen(global_phase_sv); + if (!strcmp(global_phase, "DESTRUCT")) { + return 1; + } + } + SV* sess_ref = ((struct snmp_xs_cb_data*)cb_data)->sess_ref; SV **err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1); SV **err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
I've applied this same patch against net-snmp-5.4.4.tar.gz and net-snmp-5.8.pre2.tar.gz where it also worked. Running on debian jessie / 8.