0

I'm learning how to wrap c functions using Python's ctypes' and am able to wrap and call a function, but I can't figure out how to get theerrno` after there is an error. For this example, I'm wrapping inotify_add_watch. This isn't the full code, just an example of something that will cause an error:

import ctypes

c_lib = ctypes.cdll.LoadLibrary('libc.so.6')

inotify_add = c_lib.inotify_add_watch
inotify_add.argtypes = (ctypes.c_int, ctypes.c_char_p, ctypes.c_uint32)
inotify_add.restype = ctypes.c_int

# This will cause an EBADF error
inotify_add(32, b'/tmp', 1)  # returns -1

And the documentation I linked says this will return -1 which it does, but that it also will set errno appropriately. I cannot figure out how to access errno now. If I try ctypes.get_errno(), this just returns 0. If I try to call c_lib.errno(), this causes a segmentation error, so that isn't working either. Is there a way I can retrieve errno?

TheStrangeQuark
  • 2,257
  • 5
  • 31
  • 58
  • You might want to take a look at https://stackoverflow.com/questions/50669907/how-to-use-ctypes-errcheck/50675541#50675541 – CristiFati Sep 20 '18 at 17:00
  • I've looked at that and have my `errcheck` functions working correctly. They will see the problem and raise an error if the result is `-1`. The problem is that I cannot find the actual error that would be set my `errno` – TheStrangeQuark Sep 20 '18 at 17:06

1 Answers1

2

You have to get errno from the same CRT library that Python was built with. So for Python 3.7 on Windows. I don't have Linux handy to try, so hopefully this puts you in the right direction.

>>> dll = CDLL('ucrtbase',use_errno=True)
>>> get_errno()
0
>>> dll._access(b'nonexisting',0)
-1
>>> get_errno()
2

Errno 2 is ENOENT (No such file or directory) so it got set and looks correct.

A different CRT library has a different errno instance so it isn't captured correctly by Python for use with set_errno()/get_errno().

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251