wlav / cppyy

Other
384 stars 38 forks source link

Read/write past end of object of an enum type declared via a type alias if size is less than 4 bytes #215

Open huili80 opened 4 months ago

huili80 commented 4 months ago
import cppyy
code = """
using type = std::byte; // or any other enum smaller than 4 bytes
type x{};
char a[4] = {1,2,3,4};
"""
cppyy.cppdef(code)
print(hex(cppyy.gbl.x))

result is

0x3020100

The combination of

  1. using a type alias to declare a variable
  2. type being an enum smaller than 4 bytes

is required to reproduce this behavior.

wlav commented 4 months ago

Looks like Cling is unable to resolve the type, in which case cppyy defaults to int, which is too large.

huili80 commented 4 months ago

Reported to Cling, https://github.com/root-project/cling/issues/521.

Looks like it writes past the end of the object too.

import cppyy
code = """
using type = std::byte; // or any other enum smaller than 4 bytes
type x{};
std::array<char,4> a = {1,2,3,4};
"""
cppyy.cppdef(code)
cppyy.gbl.x = 0x0fffffff
print([ord(cppyy.gbl.a[i]) for i in range(4)])

result is

[255, 255, 15, 4]
wlav commented 4 months ago

To be sure, the offending code has seen a divergence between what I have in cppyy and what is in the ROOT repo...

Regardless, the problem besides the unrecognized using, is that std::byte is a char type, not an int type. I.e., if it were recognized, it's become a string type in Python, which isn't desired either. I can probably add some code that checks one level, but there's a limit to what can be done here if there are more using and/or typedefs involved.

huili80 commented 4 months ago

I picked std::byte because it keeps the example simple. But the same issue exists for any enum (scoped or not) that's 1- or 2-byte. I'd be happy with a fix that only checks one level, with or without converting char types to python string.

Additionally, could cling-1.0 help? I tried and it seems to be able to resolve the enum type through the alias. But I haven't been able to try cling-0.9.