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

Hi there,

I am a little lost and hope to find some help here.
I have a python script which I want to execute within a Perl-script.
The "server" is a XAMPP installation on a virtual Ubuntu machine.
I use backticks to execute the python script and get the expected output on command line which means the script is executed.
The same Perl-script called via browser leads to an error:

ImportError: /opt/lampp/lib/libstdc++.so.6: version `CXXABI_1.3.8' not found (required by /usr/local/lib/python3.7/dist-packages/tensorflow/python/_pywrap_tensorflow_internal.so)

I found some comments about path settings or missing modules but I donīt get why the command line execution works and the browser does not.
The only idea I have right now is that the "www-user" cannot access the same things as the command line user.

I would be very happy to get any hint that helps me finding the source of my problem.

Niko
  • Comment on running a backticks command behaves different in command line and browser

Replies are listed 'Best First'.
Re: running a backticks command behaves different in command line and browser
by jcb (Parson) on Aug 10, 2019 at 04:10 UTC

    Try running the env command in the script and at your shell prompt. Any variables matching m/^LD_/ are particularly interesting.

    Also try which python3 or which python in both contexts. Are they using the same Python installation?

    Also try ldd python3 or ldd python in both cases to see what libraries are being loaded. Your error suggests that the httpd is somehow running Python with a different version of the C++ runtime.

    It is very suspicious that the error mentions libstc++ under /opt/lampp/lib but a Python module under /usr/local/lib/python3.7.

    If you were having a similar issue with Perl, I would ask if you are using mod_perl, but Perl tends to have better backwards compatibility than this.

      Thank you very much jcb!

      $ENV{LD_LIBRARY_PATH} = '/opt/lampp/lib:/opt/lampp/lib';

      was the result when executed via browser and was empty on command line.

      I do not really understand what happened but probably LD_LIBRARY_PATH is checked first and is as you said pointing to a non fitting version and stops after failure.
      Not sure if the solution is the best but trying

      my $ret = `unset LD_LIBRARY_PATH && $command 2&>1`;

      did the trick. You made my day, thank you very much again!

        Glad to hear it worked out. I just wanted to add that backticks, unless properly used, can very easily introduce security holes, which I wrote about here, where I also show some alternatives. In this case, since you want to also capture STDERR, I might recommend IPC::Run3. You should also be able to unset that environment variable using delete $ENV{LD_LIBRARY_PATH} instead of the unset command, and if you want that change to only be temporary while you run the command, you can use { delete local $ENV{LD_LIBRARY_PATH}; run_command_here }.

        use IPC::Run3 'run3'; my @command = ('/path/to/python3.7','/path/to/script.py'); my $ret = do { delete local $ENV{LD_LIBRARY_PATH}; my $r; run3 \@command, undef, \$r, \$r or die "run3 failed"; die "command failed, \$?=$?" if $?; $r };

        LD_LIBRARY_PATH specifies directories that the dynamic linker searches first. It is used when testing XS extensions to pick up the newly built extension rather than whatever is installed on the system.

        haukex beat me to it, but I recommend simply putting delete $ENV{LD_LIBRARY_PATH} if $ENV{LD_LIBRARY_PATH} =~ m{/lampp/}; somewhere near the top of your script to ensure that any special values your httpd installation is using will not affect your script's subprocesses.

        I also strongly advise against using shell commands when they can be avoided, particularly in Perl scripts exposed to the Web. As an example, your solution would have made your program vulnerable to ShellShock, even though you do not actually need a shell anywhere in this application.

        How much output does this command produce? You may want to read the output incrementally rather than collecting it all. If so, also look into IPC::Open3 and possibly IO::Pty and Expect.