Skip to content

Conversation

@daveads
Copy link
Contributor

@daveads daveads commented Oct 25, 2025

Attends to this issue #722

close #722

Copy link
Contributor

@andychu andychu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a good start, thanks

It is possible to add a spec test for it? We could kill the child process like in spec/builtin-kill

Does this message happen in both batch mode and interactive mode?

core/process.py Outdated


_SIGNAL_MESSAGES = {
SIGSEGV: 'Segmentation fault',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm do other shells hard-code these strings?

Or is there something like strerror() for errno with these strings?

Sometimes we have to look at the C source of other shells, as for the default path

f148383

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thanks for looking it up

Although I asked Claude and it shows that Python 3 has strsignal(), which is a POSIX 2008 API

Bash predates this API -- so it has this comment:

/* siglist.c -- signal list for those machines that don't have one. */

But unforunately our Python 2 build doesn't have a binding for it

https://docs.python.org/3/library/signal.html#signal.strsignal

https://claude.ai/share/5c6e5003-67c6-46fb-989b-0db63fc8d4ce


Could you try adding a binding in libc.c and libc.pyi , and you can test it with libc_test.py ?

build/py.sh pylibc

builds it and run tests

I think the binding could be similar to the one for strerror() in pyext/posixmodule.c

i.e. it just does a bit of arg parsing and so forth

 PyDoc_STRVAR_remove(posix_strerror__doc__,
 "strerror(code) -> string\n\n\
 Translate an error code to a message string.");
                                         
 static PyObject *
 posix_strerror(PyObject *self, PyObject *args) 
 {               
     int code;
     char *message; 
     if (!PyArg_ParseTuple(args, "i:strerror", &code))
         return NULL;
     message = strerror(code);
     if (message == NULL) {
         PyErr_SetString(PyExc_ValueError,
                         "strerror() argument out of range");
         return NULL;
     }   
     return PyString_FromString(message);
 }
     

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can try that out

@andychu
Copy link
Contributor

andychu commented Oct 25, 2025

Some testing about what other shells do

$ bash -c 'sleep 1 & kill -HUP %%; wait; echo status=$?'
bash: line 1: 2674279 Hangup                  sleep 1
status=0

hm only bash does it? interesting

$ zsh -c 'sleep 1 & kill -HUP %%; wait; echo status=$?'
status=0

andy@hoover:~/git/oils-for-unix/oils$ mksh -c 'sleep 1 & kill -HUP %%; wait; echo status=$?'
status=0

And it's not just interactive

@andychu
Copy link
Contributor

andychu commented Oct 25, 2025

This is interactive bash ...

andy@hoover:~/git/oils-for-unix/oils$ sleep 1 & kill -USR1 %%; wait
[1] 2674297
[1]+  User defined signal 1   sleep 1

@andychu
Copy link
Contributor

andychu commented Oct 25, 2025

Interactive zsh

~/git/oils-for-unix/oils% sleep 1 & kill -USR1 %%; wait
[1] 2674303
[1]  + user-defined signal 1  sleep 1

So zsh only does it interactively ? But bash does it in both?

hm same with mksh, seems interactive only

$ sleep 1 & kill -USR1 %%; wait
[1] 2674315
[1] + User defined signal 1 \sleep 1

@andychu
Copy link
Contributor

andychu commented Oct 25, 2025

I guess we can do whatever is simpler - it seems simpler to do the same thing in interactive and batch

@andychu
Copy link
Contributor

andychu commented Oct 28, 2025

Also here is the binding from Python 3 in signalmodule.c

static PyObject *
 signal_strsignal_impl(PyObject *module, int signalnum)
 /*[clinic end generated code: output=44e12e1e3b666261 input=b77914b03f856c74]*/
 {
     char *res;
 
     if (signalnum < 1 || signalnum >= NSIG) {
         PyErr_SetString(PyExc_ValueError,
                 "signal number out of range");
         return NULL;
     }

...

     errno = 0;
     res = strsignal(signalnum);
 
     if (errno || res == NULL || strstr(res, "Unknown signal") != NULL)
         Py_RETURN_NONE;
 #endif
 
     return Py_BuildValue("s", res);
 }

I usually try to adapt a similar example, so between those 2 examples, we should be able to make a Python 2 binding for strsignal()

@daveads
Copy link
Contributor Author

daveads commented Oct 29, 2025

@andychu check now...

@daveads daveads requested a review from andychu October 29, 2025 15:30
Copy link
Contributor

@andychu andychu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, glad you got it working!

Now we can simplify the code

There will probably be a C++ error once that happens, because C++ also needs strsignal()

But I can help with that

# Not testing errno case

def testStrsignal(self):
self.assertEqual('Segmentation fault', libc.strsignal(11))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do signal.SIGTERM to be more readable

core/process.py Outdated
SIGABRT: 'Aborted',
SIGILL: 'Illegal instruction',
SIGFPE: 'Floating point exception',
SIGBUS: 'Bus error',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove this dict now, and use libc.strsignal()!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove this dict now, and use libc.strsignal()!

Done

@daveads daveads force-pushed the seg_fault branch 2 times, most recently from f81c044 to a0b7a56 Compare October 29, 2025 19:26
@daveads daveads requested a review from andychu October 29, 2025 21:24
@andychu
Copy link
Contributor

andychu commented Oct 30, 2025

This looks good, thanks! How about adding a spec test for it?

That will make it easier to port to C++, so we can see that it does the same thing

I think something like this should work

$ bash -c 'sleep 1 & kill -HUP %%; wait; echo status=$?'
bash: line 1: 129997 Hangup                  sleep 1
status=0

Maybe in spec/exit-status or something

@daveads
Copy link
Contributor Author

daveads commented Oct 30, 2025

This looks good, thanks! How about adding a spec test for it?

That will make it easier to port to C++, so we can see that it does the same thing

I think something like this should work

$ bash -c 'sleep 1 & kill -HUP %%; wait; echo status=$?'
bash: line 1: 129997 Hangup                  sleep 1
status=0

Maybe in spec/exit-status or something

Okay

@andychu
Copy link
Contributor

andychu commented Oct 30, 2025

The test is tickling the right behavior:

https://op.oilshell.org/uuu/github-jobs/10636/cpp-spec.wwz/_tmp/spec/osh-cpp/background.html#details-26-osh

But it needs a better assertion

It is failing with OSH in Python, and passing with OSH in C++

It should be the other way around

[osh stderr] Expected '' Got 'Hangup (core dumped)\n'

Sometimes it may be useful to redirect stderr to a file, and then grep it for a string

Using grep -o perhaps

It would be nice if the test passes with bash too

@andychu
Copy link
Contributor

andychu commented Oct 30, 2025

Hm yeah other shells don't print status=129 ? I wonder why that is

https://op.oilshell.org/uuu/github-jobs/10636/ovm-tarball.wwz/_tmp/spec/osh-py/background.html

@andychu
Copy link
Contributor

andychu commented Oct 30, 2025

Oh and if you haven't already seen it, the commands to reproduce the spec test failures are here:

https://github.com/oils-for-unix/oils/wiki/Oils-Dev-Cheat-Sheet

test/spec.sh background FLAG*
test/spec-cpp.sh run-file background FLAG*

@andychu
Copy link
Contributor

andychu commented Oct 31, 2025

Hm the spec tests should still be failing locally for you ?

e.g. test/spec.sh background should be exiting non-zero now, which is a sign it is not ready

And I think Github sends you a message when the CI fails?


Right now it is failing -- bash and OSH now pass , but the other 2 shells need to be marked N-I

https://op.oilshell.org/uuu/github-jobs/10649/ovm-tarball.wwz/_tmp/spec/osh-py/background.html

https://github.com/oils-for-unix/oils/wiki/Spec-Tests


And then also we will need to allow the C++ failure for now, like this

$ grep oils_cpp_failures */*.sh
spec/array-sparse.test.sh:## oils_cpp_failures_allowed: 2
spec/builtin-bind.test.sh:## oils_cpp_failures_allowed: 7

Sometimes the spec tests are half the problem, but they are important!

Thanks for working on this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Print message when a child seg faults, just like other shells

3 participants