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;
}
Asked By: maxterthrowaway

||

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.)

Answered By: rici

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'somestring'))  # 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()
Answered By: Mark Tolonen
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.