inputstream.ffmpegdirect icon indicating copy to clipboard operation
inputstream.ffmpegdirect copied to clipboard

Kodi crashes when a PVR stream is stopped via remote app (unhandled bad_variant_access exception)

Open David-EIPI opened this issue 9 months ago • 13 comments

Bug report

Describe the bug

Here is a clear and concise description of what the problem is:

Kodi crashes when playing a PVR stream via "inputstream.ffmpegdirect" plugin and using remote control app, Yatse, to start and stop the stream. Playing starts normally. Stopping results in crash. Kodi does not crash when playing files from the disk. Also it does not crash when playing PVR streams via "inputstream.adaptive" plugin. I have identified crash place and suggested a patch to fix, see below.

Expected Behavior

Here is a clear and concise description of what was expected to happen:

Kodi should not crash when stopping a PVR stream with remote control app.

Actual Behavior

Kodi crashes due to unhandled bad_variant_access exception.

Possible Fix

The crash happens when remote app makes RPC call without parameters, but webserver tries to parse the empty parameters string eventually calling the CVariant.size() in a Null constant. Catching this exception fixes the problem.

--- a/xbmc/interfaces/json-rpc/JSONServiceDescription.cpp.bak	2025-01-15 17:14:15.000000000 -0500
+++ b/xbmc/interfaces/json-rpc/JSONServiceDescription.cpp	2025-03-23 19:12:50.625726613 -0400
@@ -1387,13 +1387,15 @@
       }
 
       // Check if there were unnecessary parameters
+      try {
       if (handled < requestParameters.size())
       {
         errorData["message"] = "Too many parameters";
         outputParameters = errorData;
         return InvalidParams;
       }
-
+      } catch (std::bad_variant_access e) {
+      }
       return OK;
     }
     else

To Reproduce

Steps to reproduce the behavior:

  1. Start playing a PVR stream via iptvsimple plugin.
  2. Press Stop button in Yatse.

Debuglog

The debuglog can be found here: https://pastebin.com/Z4iq51Lk

Screenshots

Here are some links or screenshots to help explain the problem:

Additional context or screenshots (if appropriate)

Here is some additional context or explanation that might help:

Your Environment

Used Operating system:

  • [ ] Android

  • [ ] iOS

  • [ ] tvOS

  • [X] Linux

  • [ ] macOS

  • [ ] Windows

  • [ ] Windows UWP

  • Operating system version/name:

  • Kodi version: 21.2 Omega

note: Once the issue is made we require you to update it with new information or Kodi versions should that be required. Team Kodi will consider your problem report however, we will not make any promises the problem will be solved.

David-EIPI avatar Mar 25 '25 16:03 David-EIPI

Catching this exception fixes the problem.

Although this works, I don't think his is the right/best fix approach.

ksooo avatar Mar 25 '25 16:03 ksooo

The crash happens when remote app makes RPC call without parameters

In addition to make Kodi survive this scenario, Yatse should be fixed to not send invalid RPC calls.

ksooo avatar Mar 25 '25 16:03 ksooo

I have found a similar issue when starting a PVR stream play via inputstream.adaptive after another stream was played via inputstream.ffmpegdirect. Only this time bad_variant_access is thrown from CVariant.asString().

I am still trying to figure out a reliable way to reproduce this issue. But the fix could probably be similar to the one that fixes CVariant.size() on null constant.

David-EIPI avatar Mar 25 '25 17:03 David-EIPI

The problem is clearly that the CVariant::ConstNullVariant contains an empty std::variant. A std::variant being empty can happen in some situations, see https://en.cppreference.com/w/cpp/utility/variant/valueless_by_exception.

But: Non of that should affect the CVariant::ConstNullVariant because it should be immutable (e.g. operator= is a null-op, etc.). The problem is that we messed this up in at least one place, CVariant::swap(). This allows to change the CVariant::ConstNullVariant to any type and it can be modified arbitrarily afterwards. https://github.com/xbmc/xbmc/blob/71734296782076b8b5971d311efcb164738cf05c/xbmc/utils/Variant.cpp#L600-L603 I'll PR a fix for that and hopefully this also solves this issue 🙂

neo1973 avatar Mar 25 '25 21:03 neo1973

@David-EIPI, are you able to build Kodi yourself to test if xbmc/xbmc#26581 fixes the issue?

neo1973 avatar Mar 25 '25 22:03 neo1973

Yes, I have just built Kodi with https://github.com/xbmc/xbmc/pull/26581. The crash still happens, exception is thrown at the same line in CVariant.size(). I can attach the log if needed, but it is essentially the same, only line number has changed from Variant.cpp:663 to Variant.cpp:666.

David-EIPI avatar Mar 27 '25 16:03 David-EIPI

Would have been too easy... Please provide the stack trace and Kodi log output.

neo1973 avatar Mar 27 '25 17:03 neo1973

Here it is. https://pastebin.com/FcAutYGT (updated link)

David-EIPI avatar Mar 27 '25 18:03 David-EIPI

From the new log I unfortunately can't say if CVariant::ConstNullVariant being empty has been fixed or not. And therefore it's not clear if that has been the original issue or was just something that we spotted by accident.

Looks like the new build has worse debug information than the original one. If you make a debug build we should get more insight.

neo1973 avatar Mar 27 '25 18:03 neo1973

Sorry, forgot to add full dump options. Here is the full log https://pastebin.com/FcAutYGT

David-EIPI avatar Mar 27 '25 22:03 David-EIPI

Found it!

The problem is with inputstream.ffmpegdirect, it also has a CVariant class in its global name space which differs from the Kodi version. When the inputstream.ffmpegdirect shared object is loaded the initializer for their global static CVariant::ConstNullVariant is executed, but because the symbol already exists in the Kodi binary it overwrites that instance with an incompatible binary representation.

The fix is to move the CVariant in inputstream.ffmpegdirect into its own namespace.

neo1973 avatar Mar 27 '25 22:03 neo1973

That is some amazing insight, neo1973!

I have just tested it. Moved addon's CVariant into existing namespace ffmpegdirect, because many source files already use it = less edits.

Rebuilt and so far no more crashes! Thanks a lot!

David-EIPI avatar Mar 28 '25 01:03 David-EIPI

Please feel free to the PR the change the Piers branch of ffmpegdirect.

Once it’s there so can also bring it into Omega.

phunkyfish avatar Mar 28 '25 05:03 phunkyfish