c-blake / cligen

Nim library to infer/generate command-line-interfaces / option / argument parsing; Docs at
https://c-blake.github.io/cligen/
ISC License
501 stars 23 forks source link

When an exception occurs within a dispatchMulti, cligen ends with a SIGABRT instead of displaying the traceback. #162

Closed kraptor closed 3 years ago

kraptor commented 3 years ago

When an exception occurs within a dispatchMulti, cligen ends with a SIGABRT instead of displaying the traceback.

The following example can be run with or without params, to demonstrate different behavior depending if cligen is within the call to cmd_start or not.

Example:

import cligen

const VERSION_META = "THIS IS VERSION 1"

proc cmd_start =
    raise newException(Exception, "Error!")

proc cmd_show_version =
    echo VERSION_META 

when isMainModule:
    if commandLineParams().len == 0:
        cmd_start()
    else:
        dispatchMulti(
            [
                "multi",
                doc = VERSION_META & "\n\n"
            ],
            [
                cmd_show_version,
                cmd_name = "version",
                doc = "display version"
            ],
            [
                cmd_start,
                cmd_name = "start",
                doc = "run the app",
            ]
        )

Expected result (executing without params) as $ app:

D:\Projects\samples\src\app.nim(13) app
D:\Projects\samples\src\app.nim(6) cmd_start Error: unhandled exception: Error! [Exception]

Current result (executing with params) as $ app start

Traceback (most recent call last) C:\Users\kraptor.nimble\pkgs\cligen-1.2.0\cligen.nim(1007) minps SIGABRT: Abnormal termination.

kraptor commented 3 years ago

Maybe I'm doing something wrong :(

kraptor commented 3 years ago

As a reference, I compiled with: -d:debug --debugger:native --debuginfo --linedir:on

Current Nim version:

Nim Compiler Version 1.2.6 [Windows: amd64]
Compiled at 2020-07-29
Copyright (c) 2006-2020 by Andreas Rumpf

git hash: bf320ed172f74f60fd274338e82bdc9ce3520dd9
active boot switches: -d:release
c-blake commented 3 years ago

Well, you neglected to copy your VERSION_META variable. So, I cannot compile it :-) Adding some dummy value for that I get similar results where no-arg invocation does not dump the help summary but tries to run start. Looking into it more..

c-blake commented 3 years ago

Oh, wait. Duh. You are doing that directly with your check of len.

c-blake commented 3 years ago

So, this relates to your other issue. https://github.com/c-blake/cligen/issues/135 where you want default activity with no subcommand. Your len == 0 check solution is an ok workaround for that (though it means CLusers will never see the brief summary table. Eh. Different priorities.).

I guess when I said "similar results" I should have been clear, "similar results to what you expected", not what you got. Sorry. I literally had just woken up. I am on Linux with Nim 1.3.5 githash 8c82144ba507244084836b38689e4925de982626 and cannot reproduce the failure.

c-blake commented 3 years ago

Specifically, when run just as app with no params I see:

app.nim(13) app
app.nim(6) cmd_start
Error: unhandled exception: Error! [Exception]

(There's a 2-line shift in line numbers from me adding a const VERSION_META = "foo".) So, maybe this has to do with a setting in your nim.cfg/config.nims? Or otherwise your build environment or specific nim version. It's really hard for me to help with a problem like this without being able to reproduce...I haven't seen it come up before.

c-blake commented 3 years ago

I can also say that I tested on nim-1.2.0 and nim-0.20.2 on Linux getting the same, expected behavior, but I doubt that's very helpful. I don't have a 1.2.6 built/around or any Windows env.

It would be worthwhile to try some newer version of Nim..or possibly try a different computer that may have different configuration..Maybe it will work there and you can 'diff' the two configs. It may be some interaction between Nim and your backend compiler, too...Anyway, I'm just guessing blindly. Sorry. Sounds like a thorny problem, but very likely not cligen-specific. :(

c-blake commented 3 years ago

I guess it may be theoretically possible that how you establish VERSION_META could play a role, though I kind of doubt it. So, if you want to be more specific about that then I may be able to help, but otherwise I cannot any more than I have. Given the essentially total lack of cligen involvement up to that point in your code (just the import, really), you may be able to just remove all the cligen stuff, reproduce, and submit a bug report to Nim core who is also more familiar with Windows build issues.

c-blake commented 3 years ago

BTW, I see you edited in the VERSION_META and as I expected that makes no difference to my output which is what you expected but are not getting. If you change the import to just import os and comment out the else: dispatchMulti I suspect you would get the same misbehavior { EDIT: on your system :-) }.

kraptor commented 3 years ago

Wop, too much information, let me process it... I'll answer asap.

kraptor commented 3 years ago

Ouch... seems this is worst than I thought... Look:

Source:

import cligen

proc cmd_test =
  raise newException(Exception, "Error!")

when isMainModule:
    dispatchMulti(
        [
            "multi",
            doc = "Test program"
        ],
        [
            cmd_test,
            cmd_name = "start",
            doc = "run the app",
        ]
    )

nim c -d:debug --debugger:native --debuginfo --linedir:on main2.nim && main2 start

Results:

C:\Users\kraptor\.nimble\pkgs\cligen-1.2.0\cligen.nim(1007) main2 C:\Users\kraptor\.nimble\pkgs\cligen-1.2.0\cligen.nim(659) multiSubs C:\Users\kraptor\.nimble\pkgs\cligen-1.2.0\cligen.nim(741) multi C:\Users\kraptor\.nimble\pkgs\cligen-1.2.0\cligen.nim(659) dispatchstart D:\Projects\nim_tests\main2.nim(4) cmd_test Error: unhandled exception: Error! [Exception]

But when compiled with the CPP backend:

nim cpp -d:debug --debugger:native --debuginfo --linedir:on main2.nim && main2 start

Results:

Traceback (most recent call last) C:\Users\kraptor\.nimble\pkgs\cligen-1.2.0\cligen.nim(1007) main2 SIGABRT: Abnormal termination.

May this be a codegen issue on Nim's side????

EDIT: escaped paths properly.

c-blake commented 3 years ago

I agree it looks like some kind of Nim codegen issue (or interaction of generated code with the backend compiler). As mentioned, I expect you can get the same misbehavior with a simpler program:

proc cmd_test =
  raise newException(Exception, "Error!")
cmd_test()

or maybe you also have to import os and check cmdLineParams().len like before, but I don't think this is cligen-related.

Now, it may have been fixed in Nim since your version. So, before filing a bug over at Nim core, you should try it against the latest devel. I now the cpp backend and c backends often have different exception handling generation. So, that also tracks.

kraptor commented 3 years ago

Uhmmm... compiling your simple test seems ok:

proc cmd_test =
  raise newException(Exception, "Error!")
cmd_test()

Results with CPP:

D:\Projects\nim_tests>nim cpp -d:debug --debugger:native --debuginfo --linedir:on main.nim && main
Hint: used config file 'C:\Users\kraptor\scoop\apps\nim\current\config\nim.cfg' [Conf]
Hint: system [Processing]
Hint: widestrs [Processing]
Hint: io [Processing]
Hint: main [Processing]
CC: stdlib_io.nim
CC: stdlib_system.nim
CC: main.nim
Hint:  [Link]
Hint: 14188 LOC; 3.319 sec; 16.125MiB peakmem; Debug build; proj: D:\Projects\nim_tests\main.nim; out: D:\Projects\nim_tests\main.exe [SuccessX]
D:\Projects\nim_tests\main.nim(3) main
D:\Projects\nim_tests\main.nim(2) cmd_test
Error: unhandled exception: Error! [Exception]

Same with C:

D:\Projects\nim_tests>nim c -d:debug --debugger:native --debuginfo --linedir:on main.nim && main
Hint: used config file 'C:\Users\kraptor\scoop\apps\nim\current\config\nim.cfg' [Conf]
Hint: system [Processing]
Hint: widestrs [Processing]
Hint: io [Processing]
Hint: main [Processing]
CC: stdlib_io.nim
CC: stdlib_system.nim
CC: main.nim
Hint:  [Link]
Hint: 14188 LOC; 2.882 sec; 16.117MiB peakmem; Debug build; proj: D:\Projects\nim_tests\main.nim; out: D:\Projects\nim_tests\main.exe [SuccessX]
D:\Projects\nim_tests\main.nim(3) main
D:\Projects\nim_tests\main.nim(2) cmd_test
Error: unhandled exception: Error! [Exception]

Not sure I can use latest version of Nim right now to check, as I don't know how to do that (installed using scoop.sh and using always stable versions)

kraptor commented 3 years ago

Note I'm using GCC on windows...

c-blake commented 3 years ago

Well, they all seem ok in my build environments and I tried 3 versions of Nim. :) Just an import cligen (with no macro call) may be another way to simplify the problem.

It was initially failing for you not via dispatchMulti, but just an if. So, it's really not about anything other than importing cligen (possibly it declaring procs/etc. tweaks things enough to trigger the problem), and I don't do anything very unusual there, Nim-package-wise.

kraptor commented 3 years ago

Ehm... forget about the if, it was an attempt to have only one example that triggers both behaviors on the same executable.

Do you mind to tell me your version of GCC?? I'm on 9.3 from feb...

kraptor commented 3 years ago

https://play.nim-lang.org/#ix=2x3G

Seems in Linux it works properly, using both backends, with 1.2.6...

c-blake commented 3 years ago

Literally none of my code was active with the if clparams.len==0. So, to me that matters. :-) I was using gcc-10.2 and those versions of Nim I mentioned.

kraptor commented 3 years ago
import cligen

proc cmd_test =
  raise newException(Exception, "Error!")

when isMainModule:
    dispatch(cmd_test)

This simple snippet causes a SIGABRT on my side, using cpp backend... but works ok using c backend... very strange, as the Linux example in playnim works

c-blake commented 3 years ago

(Also, it would matter to anyone trying to create a "minimal" reproducible failure for a bug report/question to Nim core.)

kraptor commented 3 years ago

Literally none of my code was active with the if clparams.len==0. So, to me that matters. :-) I was using gcc-10.2 and those versions of Nim I mentioned.

yeah, that branch in the if was not exhibiting the issue....

(Also, it would matter to anyone trying to create a "minimal" reproducible failure for a bug report/question to Nim core.)

This is what I'm trying to do. Asked on the channel, no answer yet

c-blake commented 3 years ago

very strange, as the Linux example in playnim works

Yeah. "thorny problem", but I don't think one I can do anything about. :(

kraptor commented 3 years ago

Yes, I know... trying to help as much as I can. I really appreciate your efforts.

c-blake commented 3 years ago

I see. I misunderstood. Since it all works for me, I thought the if one failed for you just like the cligen one. Maybe you do need some limited extra amount of call stack complexity.

c-blake commented 3 years ago

It's unrelated (with virtual certainty), but I was once doing an emit with inline C (adding that wy hash for ints to stdlib) and I used return instead of assigning to result. This messed up all the exception/call stack machinery. But I don't do anything like that in cligen. (Well, I do in cligen/strUt but that is non-imported library code present only for examples/dups.)

kraptor commented 3 years ago

Well... I try no to use emits or too advanced things... that's why I tried to make the example as simple as possible. But there are so many variables playing here: compiler, arch, os, and underlying compiler... plus all their versions... Impossible to test them all.

I'm wondering if the issue has to do with the terminate handler (https://github.com/nim-lang/Nim/issues/12573) although this one is for MSVC, not GCC... who knows.

c-blake commented 3 years ago

I generally use the Nim-devel versions and just a few old stable versions for testing. I think many people around the Nim community do. While it may seem more "stable" to use old versions, every version of Nim surely has many bugs. The bugs in the tip/head of devel are probably more well known to the devs. ;-) Since the dev team is so small, you may get better support that way. Nothing is really for certain, though. I'm just motivating my advice.

It does seem like some kind of exception escaping Nim's handling system and hitting the OS handling, but that's more or less just a re-description of your problem in other words.