diff --git a/py/builtinimport.c b/py/builtinimport.c index c725f075b..1ef7be870 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -149,7 +149,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { const char *mod_str = (const char*)mp_obj_str_get_data(args[0], &mod_len); uint last = 0; - vstr_t *path = vstr_new(); + VSTR_FIXED(path, MICROPY_PATH_MAX) module_obj = MP_OBJ_NULL; uint i; for (i = 1; i <= mod_len; i++) { @@ -159,14 +159,14 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { // find the file corresponding to the module name mp_import_stat_t stat; - if (vstr_len(path) == 0) { + if (vstr_len(&path) == 0) { // first module in the dotted-name; search for a directory or file - stat = find_file(mod_str, i, path); + stat = find_file(mod_str, i, &path); } else { // latter module in the dotted-name; append to path - vstr_add_char(path, PATH_SEP_CHAR); - vstr_add_strn(path, mod_str + last, i - last); - stat = stat_dir_or_file(path); + vstr_add_char(&path, PATH_SEP_CHAR); + vstr_add_strn(&path, mod_str + last, i - last); + stat = stat_dir_or_file(&path); } last = i + 1; @@ -182,14 +182,14 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { module_obj = mp_obj_new_module(mod_name); if (stat == MP_IMPORT_STAT_DIR) { - vstr_add_char(path, PATH_SEP_CHAR); - vstr_add_str(path, "__init__.py"); - if (mp_import_stat(vstr_str(path)) == MP_IMPORT_STAT_FILE) { - do_load(module_obj, path); + vstr_add_char(&path, PATH_SEP_CHAR); + vstr_add_str(&path, "__init__.py"); + if (mp_import_stat(vstr_str(&path)) == MP_IMPORT_STAT_FILE) { + do_load(module_obj, &path); } - vstr_cut_tail(path, 12); // cut off /__init__.py + vstr_cut_tail(&path, 12); // cut off /__init__.py } else { // MP_IMPORT_STAT_FILE - do_load(module_obj, path); + do_load(module_obj, &path); break; } } @@ -202,8 +202,6 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { assert(0); } - vstr_free(path); - return module_obj; } diff --git a/py/misc.h b/py/misc.h index 679a14b5b..065b07089 100644 --- a/py/misc.h +++ b/py/misc.h @@ -68,10 +68,17 @@ typedef struct _vstr_t { int alloc; int len; char *buf; - bool had_error; + struct { + bool had_error : 1; + bool fixed_buf : 1; + }; } vstr_t; +// convenience macro to declare a vstr with a fixed size buffer on the stack +#define VSTR_FIXED(vstr, alloc) vstr_t vstr; char vstr##_buf[(alloc)]; vstr_init_fixed_buf(&vstr, (alloc), vstr##_buf); + void vstr_init(vstr_t *vstr, int alloc); +void vstr_init_fixed_buf(vstr_t *vstr, int alloc, char *buf); void vstr_clear(vstr_t *vstr); vstr_t *vstr_new(void); vstr_t *vstr_new_size(int alloc); @@ -81,7 +88,7 @@ bool vstr_had_error(vstr_t *vstr); char *vstr_str(vstr_t *vstr); int vstr_len(vstr_t *vstr); void vstr_hint_size(vstr_t *vstr, int size); -char *vstr_extend(vstr_t *vstr, int size); +char *vstr_extend(vstr_t *vstr, int size); bool vstr_set_size(vstr_t *vstr, int size); bool vstr_shrink(vstr_t *vstr); char *vstr_add_len(vstr_t *vstr, int len); diff --git a/py/mpconfig.h b/py/mpconfig.h index 38b74b733..799c9d8e7 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -101,6 +101,12 @@ typedef long long mp_longint_impl_t; #define MICROPY_CPYTHON_COMPAT (1) #endif +// Maximum length of a path in the filesystem +// So we can allocate a buffer on the stack for path manipulation in import +#ifndef MICROPY_PATH_MAX +#define MICROPY_PATH_MAX (512) +#endif + /*****************************************************************************/ /* Miscellaneous settings */ diff --git a/py/vstr.c b/py/vstr.c index b2e46c89f..4d10dfba8 100644 --- a/py/vstr.c +++ b/py/vstr.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "misc.h" // returned value is always at least 1 greater than argument @@ -16,10 +17,23 @@ void vstr_init(vstr_t *vstr, int alloc) { } vstr->buf[0] = 0; vstr->had_error = false; + vstr->fixed_buf = false; +} + +void vstr_init_fixed_buf(vstr_t *vstr, int alloc, char *buf) { + assert(alloc > 0); // need at least room for the null byte + vstr->alloc = alloc; + vstr->len = 0; + vstr->buf = buf; + vstr->buf[0] = 0; + vstr->had_error = false; + vstr->fixed_buf = true; } void vstr_clear(vstr_t *vstr) { - m_del(char, vstr->buf, vstr->alloc); + if (!vstr->fixed_buf) { + m_del(char, vstr->buf, vstr->alloc); + } vstr->buf = NULL; } @@ -43,7 +57,9 @@ vstr_t *vstr_new_size(int alloc) { void vstr_free(vstr_t *vstr) { if (vstr != NULL) { - m_del(char, vstr->buf, vstr->alloc); + if (!vstr->fixed_buf) { + m_del(char, vstr->buf, vstr->alloc); + } m_del_obj(vstr_t, vstr); } } @@ -73,7 +89,10 @@ int vstr_len(vstr_t *vstr) { } // Extend vstr strictly to by requested size, return pointer to newly added chunk -char *vstr_extend(vstr_t *vstr, int size) { +char *vstr_extend(vstr_t *vstr, int size) { + if (vstr->fixed_buf) { + return NULL; + } char *new_buf = m_renew(char, vstr->buf, vstr->alloc, vstr->alloc + size); if (new_buf == NULL) { vstr->had_error = true; @@ -87,6 +106,9 @@ char *vstr_extend(vstr_t *vstr, int size) { // Shrink vstr to be given size bool vstr_set_size(vstr_t *vstr, int size) { + if (vstr->fixed_buf) { + return false; + } char *new_buf = m_renew(char, vstr->buf, vstr->alloc, size); if (new_buf == NULL) { vstr->had_error = true; @@ -102,8 +124,11 @@ bool vstr_shrink(vstr_t *vstr) { return vstr_set_size(vstr, vstr->len); } -bool vstr_ensure_extra(vstr_t *vstr, int size) { +static bool vstr_ensure_extra(vstr_t *vstr, int size) { if (vstr->len + size + 1 > vstr->alloc) { + if (vstr->fixed_buf) { + return false; + } int new_alloc = ROUND_ALLOC((vstr->len + size + 1) * 2); char *new_buf = m_renew(char, vstr->buf, vstr->alloc, new_alloc); if (new_buf == NULL) { @@ -156,8 +181,15 @@ void vstr_add_str(vstr_t *vstr, const char *str) { void vstr_add_strn(vstr_t *vstr, const char *str, int len) { if (vstr->had_error || !vstr_ensure_extra(vstr, len)) { + // if buf is fixed, we got here because there isn't enough room left + // so just try to copy as much as we can, with room for null byte + if (vstr->fixed_buf && vstr->len + 1 < vstr->alloc) { + len = vstr->alloc - vstr->len - 1; + goto copy; + } return; } +copy: memmove(vstr->buf + vstr->len, str, len); vstr->len += len; vstr->buf[vstr->len] = 0; diff --git a/stm/mpconfigport.h b/stm/mpconfigport.h index d6a7f697b..fd7af29d2 100644 --- a/stm/mpconfigport.h +++ b/stm/mpconfigport.h @@ -7,6 +7,7 @@ #define MICROPY_ENABLE_GC (1) #define MICROPY_ENABLE_REPL_HELPERS (1) #define MICROPY_ENABLE_FLOAT (1) +#define MICROPY_PATH_MAX (128) // type definitions for the specific machine diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 5eba0df61..dc9297010 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -15,6 +15,7 @@ #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_ENABLE_FLOAT (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) +#define MICROPY_PATH_MAX (PATH_MAX) // type definitions for the specific machine