edgetx icon indicating copy to clipboard operation
edgetx copied to clipboard

Lua Mixer Scripts Cont'd

Open pfeerick opened this issue 3 years ago • 22 comments

  • [ ] Lua mixer scripts are limited to 6+3 filename length, but it seems that more than 5+3 maybe a EM trigger
  • [ ] "the output value isn't correctly displayed, always 0"
  • [ ] Possibly computationally intense Lua scripts may crash or freeze the radio
  • [ ] #1318

The next problem that still remains is that the radio freezes / crashes if you use the fourth instance of this script:

abcd.zip

This is a little bit more computational intense than the other.

Maybe it helps to identify this one: the first three instances are not saved in the model. After crash and restart the model does not contain the first three instances of the script. This is reproducible.

Originally posted by @wimalopaan in https://github.com/EdgeTX/edgetx/issues/1312#issuecomment-1002897453

pfeerick avatar Dec 30 '21 09:12 pfeerick

The 6 char problem is located here:

https://github.com/EdgeTX/edgetx/blob/d37b3e40518af42b6e54b3bda1b432a8f0431427/radio/src/gui/colorlcd/model_mixer_scripts.cpp#L87

strncpy() does not copy the \0 if filename is 6 chars (or more), so the string remains unterminated.

This

           strncpy(sd->file, newValue.c_str(), LEN_SCRIPT_FILENAME);
            sd->file[LEN_SCRIPT_FILENAME - 1] = '\0';

terminates correctly, but leaves the problem, that then a file with that filename does not exist or is simply another lua-file with the same prefix-name. This misleads the user.

The best solution would to only list those files with filenames with not more than 5 +3 chars

wimalopaan avatar Dec 30 '21 11:12 wimalopaan

Look also at #1318

wimalopaan avatar Dec 30 '21 11:12 wimalopaan

Looks like this fixed it (display only files according 5 + 3 chars):

      auto fc = new FileChoice(
          window, grid.getFieldSlot(), SCRIPTS_MIXES_PATH, SCRIPTS_EXT,
          LEN_SCRIPT_FILENAME - 1,
          [=]() { return std::string(sd->file, LEN_SCRIPT_FILENAME); },
          [=](std::string newValue) {
            strncpy(sd->file, newValue.c_str(), LEN_SCRIPT_FILENAME);
            sd->file[LEN_SCRIPT_FILENAME - 1] = '\0';
            if (newValue.empty()) { memset((void*)sd, 0, sizeof(ScriptData)); }
            storageDirty(EE_MODEL);
            LUA_LOAD_MODEL_SCRIPT(idx); // async reload...
            update = true;
          }, true);

wimalopaan avatar Dec 30 '21 11:12 wimalopaan

@wimalopaan that is normal and used at many places to save a few bytes of memory. That being said, the code copying this file name to LUA on query should be aware of that and fix it before passing it to LUA.

raphaelcoeffic avatar Dec 30 '21 11:12 raphaelcoeffic

@wimalopaan that is normal and used at many places to save a few bytes of memory. That being said, the code copying this file name to LUA on query should be aware of that and fix it before passing it to LUA.

Thanks, I'm not familiar with the code base and that's the reason not to create a PR here ;-)

Ok, then the root cause maybe at other place ...

wimalopaan avatar Dec 30 '21 11:12 wimalopaan

Is it sure that the caller of this really knows about LEN_SCRIPT_FILENAME

https://github.com/EdgeTX/edgetx/blob/d37b3e40518af42b6e54b3bda1b432a8f0431427/radio/src/lua/interface.cpp#L588

https://github.com/EdgeTX/edgetx/blob/d37b3e40518af42b6e54b3bda1b432a8f0431427/radio/src/lua/interface.cpp#L603

and that is wrong at least here:

https://github.com/EdgeTX/edgetx/blob/d37b3e40518af42b6e54b3bda1b432a8f0431427/radio/src/lua/interface.cpp#L931

wimalopaan avatar Dec 30 '21 12:12 wimalopaan

Here are some other places that require \0-terminated strings (violated by the 6-char case):

https://github.com/EdgeTX/edgetx/blob/81d77684986bdbc5181945f5eb72c054e632ca8c/radio/src/strhelpers.cpp#L577-L604

wimalopaan avatar Dec 31 '21 07:12 wimalopaan

And here is a patch with some (maybe not all) corrections for review:

mixermess.patch.txt

wimalopaan avatar Dec 31 '21 08:12 wimalopaan

Well, this string-handling looks to me really weird and dangerous.

I would love really to suggest:

template<unit_8t Size>
using Cstring = std::array<char, Size>;

with some simple helper template-functions. Because there a only a few different lengths around, that should not result in code-bloat.

wimalopaan avatar Dec 31 '21 08:12 wimalopaan

@wimalopaan this uses tons of dynamically allocated memory, which is an issue on B&W targets (used only for LUA). We need to do it "old-school" for now ;-)

raphaelcoeffic avatar Dec 31 '21 10:12 raphaelcoeffic

@raphaelcoeffic std::array doesn't use dynamic allocated memory - this is not std::string nor std::vector

wimalopaan avatar Dec 31 '21 10:12 wimalopaan

std::array has no runtime-overhead compared to raw c-arrays.

There might be some code-bloat (flash, not RAM) because of different template-instantiations using different parametrizsations of std::array<>.

But I thilnk that the security argument would be of much concern. I think this dicussion shows the need for this ;-)

wimalopaan avatar Dec 31 '21 10:12 wimalopaan

Forgot something in the above patch, here is a new one: mixermess.patch.txt

wimalopaan avatar Dec 31 '21 11:12 wimalopaan

Some more things to correct:

mixermess.patch.txt

@jfrickmann please have a look at these changes.

wimalopaan avatar Jan 01 '22 09:01 wimalopaan

Some work is needed for #1330

wimalopaan avatar Jan 01 '22 09:01 wimalopaan

I will not pretend that I understand the motivation for everything you do, but I did not spot any problems, and it built w/o problems.

As for model_mixer_scripts.cpp:

  • You added some checks to clear data when necessary - it looks plausible to me.

As for interface.cpp:

  • assert(ref >= SCRIPT_MIX_FIRST); is unnecessary, as ref is unsigned and SCRIPT_MIX_FIRST is zero.
  • The part with maxlen around line 626, I have not ever messed with this code, and I do not feel qualified to assess that. But it looks to me like the existing code was rather messy, and your change looks cleaner to me FWIW. Maybe we should just remove the out-commented code lines?
  • Same thing around line 670 and 705.
  • You have added a string length argument to TRACE statements - I assume to prevent it crashing on error strings that are not NULL terminated? Looks fine to me!

As for strhelpers.cpp:

  • Looks good, please remove the out-commented code line!

All in all, it looks like you have added some sensible checks to make the code safer and cleaner, and I suggest that you make a pull request!

jfrickmann avatar Jan 01 '22 15:01 jfrickmann

Ok, but before I do that let me ask some more questions or give some remarks:

  • You added some checks to clear data when necessary - it looks plausible to me.

This prevents the mixer-script menu to display stale data, if the slot was occupied before but deleted afterwards and not one wants to insert a new script.

  • assert(ref >= SCRIPT_MIX_FIRST); is unnecessary, as ref is unsigned and SCRIPT_MIX_FIRST is zero.

Well, I think this is absolutely neccessary: at the time of writing such an assertion it looks unneccessary because the condition seems trivially true. But there is no guarantee that SCRIPT_MIX_FIRST remains 0 (that is the reason for introducing a cpp-macro anyway). So this assert checks for future modifications.

  • The part with maxlen around line 626, I have not ever messed with this code, and I do not feel qualified to assess that. But it looks to me like the existing code was rather messy, and your change looks cleaner to me FWIW. Maybe we should just remove the out-commented code lines?

Yes, we can get rid of that. But: the use of snprintf() here is a little bit overkill, since most of the string twiddling could be done at compile-time. I also wrote a TMP (template meta-programming) version instead of snprintf(). I know that most people / projects have strong concerns against TMP although it can save lots of CPU-cycles. So I don't know what to to here: stick to old-style snprintf() or use a typesafe, automatic-calculating the needed output-string-length TMP concat() version.

  • You have added a string length argument to TRACE statements - I assume to prevent it crashing on error strings that are not NULL terminated? Looks fine to me!

Yes, that was an additional clear violation of the possibly-non-terminated-maxlength-cstrings rule.

  • Looks good, please remove the out-commented code line!

Ok, I think this was the root-cause.

Please let me know your opinion.

wimalopaan avatar Jan 01 '22 18:01 wimalopaan

Looks great to me, I suggest ou submit a PR!

jfrickmann avatar Jan 01 '22 18:01 jfrickmann

Fixed in #1338

wimalopaan avatar Jan 02 '22 09:01 wimalopaan

Just realized that the project uses C++11, but for a (simple) general TMP solution of the problem one would need at least C++17.

wimalopaan avatar Jan 02 '22 09:01 wimalopaan

What that comment shows, is that you know about 15 times more about C++ than I do! I am glad that we now have you onboard as a "puller", and I hope that we will see more PRs from you addressing issues like this one. I think that there are plenty of similar cases in code base!!

jfrickmann avatar Jan 03 '22 12:01 jfrickmann

Maybe #1340 is of interest also.

wimalopaan avatar Jan 03 '22 16:01 wimalopaan