this repo has no description
at trunk 275 lines 9.9 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include <ffi.h> 3 4#include "cpython-data.h" 5 6#include "builtins.h" 7#include "bytes-builtins.h" 8#include "frame.h" 9#include "globals.h" 10#include "module-builtins.h" 11#include "modules.h" 12#include "objects.h" 13#include "os.h" 14#include "thread.h" 15#include "type-builtins.h" 16 17namespace py { 18 19// a table entry describing a predefined ctypes type 20struct FieldDesc { 21 char code; 22 ffi_type* pffi_type; 23}; 24 25static_assert(sizeof(long long) == 8, "expected sizof(long long) == 8"); 26static_assert(sizeof(wchar_t) == 4, "expected sizeof(wchar) == 4"); 27static_assert(sizeof(bool) == 1, "expected sizeof(bool) == 1"); 28 29// clang-format off 30static FieldDesc format_table[] = { 31 {'s', &ffi_type_pointer}, 32 {'b', &ffi_type_schar}, 33 {'B', &ffi_type_uchar}, 34 {'c', &ffi_type_schar}, 35 {'d', &ffi_type_double}, 36 {'g', &ffi_type_longdouble}, 37 {'f', &ffi_type_float}, 38 {'h', &ffi_type_sshort}, 39 {'H', &ffi_type_ushort}, 40 {'i', &ffi_type_sint}, 41 {'I', &ffi_type_uint}, 42 {'l', &ffi_type_slong}, 43 {'L', &ffi_type_ulong}, 44 {'q', &ffi_type_sint64}, // 'q' and 'Q' are `long long` 45 {'Q', &ffi_type_uint64}, 46 {'P', &ffi_type_pointer}, 47 {'z', &ffi_type_pointer}, 48 {'u', &ffi_type_sint32}, // 'u' and 'U' are `wchar_t` 49 {'U', &ffi_type_pointer}, 50 {'Z', &ffi_type_pointer}, 51 {'?', &ffi_type_uint8}, // '?' is `bool` 52 {'O', &ffi_type_pointer}, 53 {0, nullptr}, 54}; 55// clang-format on 56 57static FieldDesc* fieldDesc(const char fmt) { 58 for (FieldDesc* entry = format_table; entry->code != 0; ++entry) { 59 if (entry->code == fmt) return entry; 60 } 61 return nullptr; 62} 63 64static PyObject* cast(void* /* ptr */, PyObject* /* src */, 65 PyObject* /* ctype */) { 66 UNIMPLEMENTED("_ctypes cast"); 67} 68 69static PyObject* stringAt(const char* /* ptr */, int /* size */) { 70 UNIMPLEMENTED("_ctypes stringAt"); 71} 72 73static PyObject* wstringAt(const wchar_t* /* ptr */, int /* size */) { 74 UNIMPLEMENTED("_ctypes wstringAt"); 75} 76 77void FUNC(_ctypes, __init_module__)(Thread* thread, const Module& module, 78 View<byte> bytecode) { 79 executeFrozenModule(thread, module, bytecode); 80 81 HandleScope scope(thread); 82 Runtime* runtime = thread->runtime(); 83 84 Object rtld_local_name(&scope, runtime->symbols()->at(ID(RTLD_LOCAL))); 85 Object rtld_local(&scope, runtime->newInt(OS::kRtldLocal)); 86 Object rtld_global_name(&scope, runtime->symbols()->at(ID(RTLD_GLOBAL))); 87 Object rtld_global(&scope, runtime->newInt(OS::kRtldGlobal)); 88 moduleAtPut(thread, module, rtld_local_name, rtld_local); 89 moduleAtPut(thread, module, rtld_global_name, rtld_global); 90 91 Object cast_addr_name(&scope, runtime->symbols()->at(ID(_cast_addr))); 92 Object cast_addr(&scope, runtime->newIntFromCPtr(bit_cast<void*>(&cast))); 93 moduleAtPut(thread, module, cast_addr_name, cast_addr); 94 95 Object memmove_addr_name(&scope, runtime->symbols()->at(ID(_memmove_addr))); 96 Object memmove_addr(&scope, 97 runtime->newIntFromCPtr(bit_cast<void*>(&memmove))); 98 moduleAtPut(thread, module, memmove_addr_name, memmove_addr); 99 100 Object memset_addr_name(&scope, runtime->symbols()->at(ID(_memset_addr))); 101 Object memset_addr(&scope, runtime->newIntFromCPtr(bit_cast<void*>(&memset))); 102 moduleAtPut(thread, module, memset_addr_name, memset_addr); 103 104 Object string_at_addr_name(&scope, 105 runtime->symbols()->at(ID(_string_at_addr))); 106 Object string_at_addr(&scope, 107 runtime->newIntFromCPtr(bit_cast<void*>(&stringAt))); 108 moduleAtPut(thread, module, string_at_addr_name, string_at_addr); 109 110 Object wstring_at_addr_name(&scope, 111 runtime->symbols()->at(ID(_wstring_at_addr))); 112 Object wstring_at_addr(&scope, 113 runtime->newIntFromCPtr(bit_cast<void*>(&wstringAt))); 114 moduleAtPut(thread, module, wstring_at_addr_name, wstring_at_addr); 115} 116 117RawObject FUNC(_ctypes, _CharArray_value_to_bytes)(Thread* thread, 118 Arguments args) { 119 HandleScope scope(thread); 120 Object value(&scope, args.get(0)); 121 word length = intUnderlying(args.get(1)).asWord(); 122 if (value.isMmap()) { 123 Pointer value_ptr(&scope, Mmap::cast(*value).data()); 124 DCHECK(value_ptr.length() >= length, "Mmap shorter than ctypes.Array"); 125 byte* cptr = reinterpret_cast<byte*>(value_ptr.cptr()); 126 word first_nul = Utils::memoryFindChar(cptr, length, '\0'); 127 return thread->runtime()->newBytesWithAll( 128 {cptr, first_nul == -1 ? length : first_nul}); 129 } 130 CHECK(value.isBytearray(), "unexpected ctypes.Array._value type"); 131 Bytes value_bytes(&scope, Bytearray::cast(*value).items()); 132 word first_nul = value_bytes.findByte(0, '\0', length); 133 return bytesSubseq(thread, value_bytes, 0, 134 first_nul == -1 ? length : first_nul); 135} 136 137RawObject FUNC(_ctypes, _call_cfuncptr)(Thread* thread, Arguments args) { 138 HandleScope scope(thread); 139 140 void* addr = Int::cast(args.get(0)).asCPtr(); 141 Str type(&scope, args.get(1)); 142 switch (type.byteAt(0)) { 143 case 'i': { 144 int int_result = reinterpret_cast<int (*)()>(addr)(); 145 return thread->runtime()->newInt(int_result); 146 } 147 case 'z': { 148 char* bytes_result = reinterpret_cast<char* (*)()>(addr)(); 149 return thread->runtime()->newBytesWithAll(View<byte>( 150 reinterpret_cast<byte*>(bytes_result), std::strlen(bytes_result))); 151 } 152 default: { 153 UNIMPLEMENTED("Not yet supported return value type"); 154 } 155 } 156} 157 158RawObject FUNC(_ctypes, _memset)(Thread*, Arguments args) { 159 void* addr = Int::cast(args.get(0)).asCPtr(); 160 OptInt<int> val = Int::cast(args.get(1)).asInt<int>(); 161 if (val.error != CastError::None) { 162 UNIMPLEMENTED("ctypes.memset called with non-integer value"); 163 } 164 OptInt<size_t> size = Int::cast(args.get(2)).asInt<size_t>(); 165 if (size.error != CastError::None) { 166 UNIMPLEMENTED("ctypes.memset called with non-size_t size"); 167 } 168 std::memset(addr, val.value, size.value); 169 return args.get(0); 170} 171 172RawObject FUNC(_ctypes, _shared_object_symbol_address)(Thread* thread, 173 Arguments args) { 174 HandleScope scope(thread); 175 Int handle(&scope, args.get(0)); 176 Str name(&scope, args.get(1)); 177 unique_c_ptr<char> name_cstr(name.toCStr()); 178 const char* error_msg = nullptr; 179 void* address = OS::sharedObjectSymbolAddress(handle.asCPtr(), 180 name_cstr.get(), &error_msg); 181 if (address == nullptr) { 182 return thread->raiseWithFmt(LayoutId::kAttributeError, "%s", 183 error_msg != nullptr ? error_msg : ""); 184 } 185 return thread->runtime()->newIntFromCPtr(address); 186} 187 188RawObject FUNC(_ctypes, _addressof)(Thread* thread, Arguments args) { 189 HandleScope scope(thread); 190 Object value(&scope, args.get(0)); 191 if (value.isMmap()) { 192 Object buf(&scope, Mmap::cast(*value).data()); 193 Pointer pointer(&scope, *buf); 194 return thread->runtime()->newIntFromCPtr(pointer.cptr()); 195 } 196 UNIMPLEMENTED("Cannot construct pointer from non-mmap yet"); 197} 198 199RawObject FUNC(_ctypes, _SimpleCData_value_to_type)(Thread* thread, 200 Arguments args) { 201 HandleScope scope(thread); 202 Runtime* runtime = thread->runtime(); 203 Object value(&scope, args.get(0)); 204 Str type(&scope, args.get(1)); 205 Int offset(&scope, args.get(2)); 206 switch (type.byteAt(0)) { 207 case 'H': 208 if (value.isMmap()) { 209 Pointer value_ptr(&scope, Mmap::cast(*value).data()); 210 CHECK(value_ptr.length() >= 2, "Not enough memory"); 211 uint16_t* cptr = reinterpret_cast<uint16_t*>(value_ptr.cptr()); 212 return runtime->newInt(cptr[offset.asWord()]); 213 } 214 if (value.isUnbound()) { 215 return SmallInt::fromWord(0); 216 } 217 return *value; 218 case 'L': 219 if (value.isMmap()) { 220 Pointer value_ptr(&scope, Mmap::cast(*value).data()); 221 CHECK(static_cast<uword>(value_ptr.length()) >= sizeof(unsigned long), 222 "Not enough memory"); 223 long* cptr = reinterpret_cast<long*>(value_ptr.cptr()); 224 return runtime->newInt(cptr[offset.asWord()]); 225 } 226 if (value.isUnbound()) { 227 return SmallInt::fromWord(0); 228 } 229 return *value; 230 default: 231 UNIMPLEMENTED("Cannot get values of non-uint16 objects yet"); 232 } 233} 234 235RawObject FUNC(_ctypes, dlopen)(Thread* thread, Arguments args) { 236 HandleScope scope(thread); 237 Runtime* runtime = thread->runtime(); 238 239 Object mode_obj(&scope, args.get(1)); 240 if (!mode_obj.isInt()) { 241 return thread->raiseRequiresType(mode_obj, ID(int)); 242 } 243 OptInt<int> mode_opt = Int::cast(*mode_obj).asInt<int>(); 244 if (mode_opt.error != CastError::None) { 245 return thread->raiseWithFmt(LayoutId::kOverflowError, 246 "Python int too large to convert to C long"); 247 } 248 int mode = mode_opt.value | OS::kRtldNow; 249 unique_c_ptr<char> name_cstr; 250 Object name_obj(&scope, args.get(0)); 251 if (name_obj.isNoneType()) { 252 name_cstr.reset(nullptr); 253 } else if (name_obj.isStr()) { 254 name_cstr.reset(Str::cast(*name_obj).toCStr()); 255 } else { 256 return thread->raiseRequiresType(name_obj, ID(str)); 257 } 258 259 const char* error_msg = nullptr; 260 void* handle = OS::openSharedObject(name_cstr.get(), mode, &error_msg); 261 if (handle == nullptr) { 262 return thread->raiseWithFmt(LayoutId::kOSError, "%s", 263 error_msg != nullptr ? error_msg : ""); 264 } 265 return runtime->newIntFromCPtr(handle); 266} 267 268RawObject FUNC(_ctypes, _sizeof_typeclass)(Thread*, Arguments args) { 269 DCHECK(args.get(0).isStr(), "bad internal call"); 270 FieldDesc* field_desc = fieldDesc(Str::cast(args.get(0)).byteAt(0)); 271 size_t size = field_desc->pffi_type->size; 272 return SmallInt::fromWord(size); 273} 274 275} // namespace py