Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ctypes workaround to bootstrap (fixes ctypes.util.find_library() crash) #1433

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions pythonforandroid/bootstraps/sdl2/build/jni/src/start.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,38 @@ int file_exists(const char *filename) {
return 0;
}

/* Helper function to escape all occurrences of ' as \', and all
* occurances of \n and \r with \\n and \\r for inline string literals.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/occurances/occurrences/

* (Unix paths can contain line breaks, so to be super safe, we need this).
* NOTE: return value needs to be free()'d after use by the caller!!
*/
char *escape_quotes_of_inline_string(const char* inline_code_arg) {
char *result_buf = malloc(strlen(inline_code_arg) * 2 + 1);
Copy link
Member

@AndreMiras AndreMiras Oct 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see where this is freed?
Edit: never mind I found it 😄

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I should really add a note to the comment above the function that it returns something that needs to be free()'d

// (buffer size is large enough for worst case of every char escaped)
int targetoffset = 0;
int sourceoffset = 0;
while (sourceoffset <= strlen(inline_code_arg)) {
if (inline_code_arg[sourceoffset] == '\'') {
result_buf[targetoffset] = '\\';
targetoffset++;
result_buf[targetoffset] = '\'';
} else if (inline_code_arg[sourceoffset] == '\n') {
result_buf[targetoffset] = '\\';
targetoffset++;
result_buf[targetoffset] = 'n';
} else if (inline_code_arg[sourceoffset] == '\r') {
result_buf[targetoffset] = '\\';
targetoffset++;
result_buf[targetoffset] = 'r';
} else {
result_buf[targetoffset] = inline_code_arg[sourceoffset];
}
sourceoffset++;
targetoffset++;
}
return result_buf;
}

/* int main(int argc, char **argv) { */
int main(int argc, char *argv[]) {

Expand Down Expand Up @@ -212,6 +244,67 @@ int main(int argc, char *argv[]) {

LOGP("AND: Ran string");

#if PY_MAJOR_VERSION >= 3
/* Workaround crash in ctypes.find_library() which is caused by its
* internal use of /bin/sh, and looking in the wrong folders on Android.
*
* The code needs 'env_argument' as baked path, so we need to insert this:
*/
LOGP("ctypes workaround insert");
char code_with_placeholder[] = (""
"try:\n"
" import ctypes.util\n"
" orig_func = ctypes.util.find_library\n"
" def android_find_library_hack(*args):\n"
" import os\n"
" name = args[0]\n"
" \n"
" # Truncate ending for easier comparison:\n"
" if name.find('.so.') >= 0:\n"
" name = name.partition('.so.')[0]\n"
" if name.endswith('.so'):\n"
" name = name[:-len('.so')]\n"
" if not name.endswith('.'):\n"
" name += '.'\n"
" \n"
" # Helper function to check lib name:\n"
" def check_name(lib_name, search_name):\n"
" if filename.endswith('.so') and (\n"
" filename.startswith('lib' + search_name) or\n"
" filename.startswith(search_name)):\n"
" return True\n"
" if search_name.endswith('-2.0.'):\n" // PySDL2 hack
" search_name = search_name[:-len('-2.0.')] + '.'\n"
" return check_name(lib_name, search_name)\n"
" return False\n"
" \n"
" # Check the user app lib dir and system dir:\n"
" app_root = os.path.normpath(os.path.abspath(os.path.join(\n"
" '%s', '..', '..', 'lib')))\n"
" app_root_arm = os.path.join(app_root,\n"
" 'arm') # fixme: other archs?\n"
" sys_dir = '/system/lib'\n"
" for lib_search in [app_root, app_root_arm, sys_dir]:\n"
" if not os.path.exists(lib_search):\n"
" continue\n"
" for filename in os.listdir(lib_search):\n"
" if check_name(filename, name):\n"
" return os.path.join(lib_search, filename)\n"
" return orig_func(*args)\n"
" ctypes.util.find_library = android_find_library_hack\n"
"except ImportError:\n"
" pass\n");
char *escaped_path_arg = escape_quotes_of_inline_string(env_argument);
int final_code_buf_size = (strlen(code_with_placeholder) +
strlen(escaped_path_arg) + 1); // slightly too large, but good enough
char *final_ctypes_code = malloc(final_code_buf_size);
snprintf(final_ctypes_code, final_code_buf_size, code_with_placeholder,
escaped_path_arg);
free(escaped_path_arg);
PyRun_SimpleString(final_ctypes_code);
free(final_ctypes_code);
#endif

/* run it !
*/
LOGP("Run user program, change dir and execute entrypoint");
Expand Down