Sending null terminated string to my C code through Python
Question:
I am sending strings to my BPF C code and I am not sure if the strings passed in are null-terminated. If they are not, is there a way to make them null terminated? I am sending in my lines of code to BPF so I can count them manually using my stringCounter function but I keep hitting a forever loop sadly. Here is what my Python code looks like:
b = BPF(src_file="hello.c")
lookupTable = b["lookupTable"]
#add hello.csv to the lookupTable array
f = open("hello copy.csv","r")
contents = f.readlines()
for i in range(0,len(contents)):
string = contents[i].encode('utf-8')
lookupTable[ctypes.c_int(i)] = ctypes.create_string_buffer(string, len(string))
And here is the code I found for my null terminated string counter
int stringLength(char* txt)
{
int i=0,count=0;
while(txt[i++]!=' '){
count+=1;
}
return count;
}
Answers:
ctypes.create_string_buffer(string, len(string))
is not zero-terminated. But ctypes.create_string_buffer(string)
is. It’s easy to see that, since ctypes.create_string_buffer(string)[-1]
is b'x00'
, whereas ctypes.create_string_buffer(string, len(string))[-1]
is the last byte in string
.
In other words, if you want a zero-terminated buffer, let create_string_buffer
figure out the length. (It uses the actual length from the Python bytes object, so it doesn’t get fooled by internal NUL bytes, if you were worried about that.)
I’m unfamiliar with BPF
but for ctypes
, if your string isn’t modified by the C code you don’t need create_string_buffer
as it is used to create mutable buffers, and Python Unicode and byte strings are both always passed nul-terminated wchar_t*
or char*
, respectively, to C code. Assuming your function is in test.dll
or test.so
:
import ctypes as ct
dll = ct.CDLL('./test')
dll.stringLength.argtypes = ct.c_char_p,
dll.stringLength.restype = ct.c_int
print(dll.stringLength('somestring'.encode())) # If string is Unicode
print(dll.stringLength(b'someotherstring')) # If already a byte string
Output:
10
15
Note this doesn’t preclude having a nul in the string itself, but your count function will return a shorter value in that case:
print(dll.stringLength(b'some string')) # Output: 4
Your code could be probably be written as the following assuming there isn’t some requirement that a BPF
object have hard-coded ctypes
types as indexes and values.
with open("hello copy.csv") as file:
for i,line in enumerate(file):
lookupTable[i] = string.encode()
I am sending strings to my BPF C code and I am not sure if the strings passed in are null-terminated. If they are not, is there a way to make them null terminated? I am sending in my lines of code to BPF so I can count them manually using my stringCounter function but I keep hitting a forever loop sadly. Here is what my Python code looks like:
b = BPF(src_file="hello.c")
lookupTable = b["lookupTable"]
#add hello.csv to the lookupTable array
f = open("hello copy.csv","r")
contents = f.readlines()
for i in range(0,len(contents)):
string = contents[i].encode('utf-8')
lookupTable[ctypes.c_int(i)] = ctypes.create_string_buffer(string, len(string))
And here is the code I found for my null terminated string counter
int stringLength(char* txt)
{
int i=0,count=0;
while(txt[i++]!=' '){
count+=1;
}
return count;
}
ctypes.create_string_buffer(string, len(string))
is not zero-terminated. But ctypes.create_string_buffer(string)
is. It’s easy to see that, since ctypes.create_string_buffer(string)[-1]
is b'x00'
, whereas ctypes.create_string_buffer(string, len(string))[-1]
is the last byte in string
.
In other words, if you want a zero-terminated buffer, let create_string_buffer
figure out the length. (It uses the actual length from the Python bytes object, so it doesn’t get fooled by internal NUL bytes, if you were worried about that.)
I’m unfamiliar with BPF
but for ctypes
, if your string isn’t modified by the C code you don’t need create_string_buffer
as it is used to create mutable buffers, and Python Unicode and byte strings are both always passed nul-terminated wchar_t*
or char*
, respectively, to C code. Assuming your function is in test.dll
or test.so
:
import ctypes as ct
dll = ct.CDLL('./test')
dll.stringLength.argtypes = ct.c_char_p,
dll.stringLength.restype = ct.c_int
print(dll.stringLength('somestring'.encode())) # If string is Unicode
print(dll.stringLength(b'someotherstring')) # If already a byte string
Output:
10
15
Note this doesn’t preclude having a nul in the string itself, but your count function will return a shorter value in that case:
print(dll.stringLength(b'some string')) # Output: 4
Your code could be probably be written as the following assuming there isn’t some requirement that a BPF
object have hard-coded ctypes
types as indexes and values.
with open("hello copy.csv") as file:
for i,line in enumerate(file):
lookupTable[i] = string.encode()