Skip to content

Commit e3e115b

Browse files
committed
fix(plugin): Use UTF-8 paths on Windows
Document that plugin paths should be UTF-8 on Windows, and convert them to UTF-16 internally. In sinsp-example, make sure our command line arguments (including the plugin path) are UTF-8 on Windows. Signed-off-by: Gerald Combs <gerald@wireshark.org>
1 parent 174f14d commit e3e115b

4 files changed

Lines changed: 59 additions & 2 deletions

File tree

userspace/libsinsp/examples/test.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ limitations under the License.
3535
#include <thread>
3636
#include <json/json.h>
3737

38-
#ifndef _WIN32
38+
#ifdef _WIN32
39+
#include <Windows.h>
40+
#include <shellapi.h>
41+
#else
3942
extern "C" {
4043
#include <sys/syscall.h>
4144
#include <sys/stat.h>
@@ -688,13 +691,46 @@ static void print_perftest_table_data(const uint64_t num_events_diff,
688691
<< std::setw(14) << curr_vm_rss_in_mebibytes << '\r' << std::flush;
689692
}
690693

694+
#ifdef _WIN32
695+
char* utf16_to_utf8(const LPWSTR utf16_str) {
696+
int utf8_str_len = WideCharToMultiByte(CP_UTF8, 0, utf16_str, -1, NULL, 0, NULL, NULL);
697+
if(utf8_str_len <= 0) {
698+
return NULL;
699+
}
700+
char* utf8_str = (char*)malloc(utf8_str_len * sizeof(char));
701+
if(WideCharToMultiByte(CP_UTF8, 0, utf16_str, -1, utf8_str, utf8_str_len, NULL, NULL) <= 0) {
702+
free(utf8_str);
703+
return NULL;
704+
}
705+
return utf8_str;
706+
}
707+
#endif
708+
691709
//
692710
// Sample filters:
693711
// "evt.category=process or evt.category=net"
694712
// "evt.category=net or (evt.type=execveat or evt.type=execve or evt.type=clone or evt.type=fork
695713
// or evt.type=vfork)"
696714
//
697715
int main(int argc, char** argv) {
716+
#ifdef _WIN32
717+
// main+argv uses the system encoding, which may not be able to handle all
718+
// filesystem paths. Fetch the wide command line arguments and convert them
719+
// to UTF-8.
720+
int wide_argc;
721+
LPWSTR* wide_argv = CommandLineToArgvW(GetCommandLineW(), &wide_argc);
722+
723+
if(wide_argv && wide_argc == argc) {
724+
char** new_argv = (char**)malloc((argc + 1) * sizeof(char*));
725+
for(int idx = 0; idx < argc; idx++) {
726+
new_argv[idx] = utf16_to_utf8(wide_argv[idx]);
727+
}
728+
new_argv[argc] = NULL;
729+
argv = new_argv;
730+
}
731+
SetConsoleOutputCP(CP_UTF8);
732+
#endif
733+
698734
sinsp inspector;
699735

700736
filter_list.reset(new sinsp_filter_check_list());

userspace/libsinsp/sinsp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,8 @@ class SINSP_PUBLIC sinsp : public capture_stats_source {
734734
// Create and register a plugin from a shared library pointed
735735
// to by filepath, and add it to the inspector.
736736
// The created sinsp_plugin is returned.
737+
// filepath must be encoded as UTF-8 on Windows.
738+
737739
std::shared_ptr<sinsp_plugin> register_plugin(const std::string& filepath);
738740

739741
// Create and register a plugin given a custom API vtable.

userspace/plugin/plugin_loader.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,24 @@ plugin_handle_t* plugin_load(const char* path, char* err) {
7171

7272
// open dynamic library
7373
#ifdef _WIN32
74-
ret->handle = LoadLibrary(path);
74+
// Using LoadLibraryW ensures that we have a valid path independent
75+
// of the system or application code page.
76+
int wpath_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, NULL, 0);
77+
if(wpath_len <= 0) {
78+
free(ret);
79+
strlcpy(err, "unable to decode plugin path", PLUGIN_MAX_ERRLEN);
80+
return NULL;
81+
}
82+
83+
WCHAR* wpath = malloc(wpath_len * sizeof(WCHAR));
84+
if(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, wpath, wpath_len) <= 0) {
85+
free(ret);
86+
free(wpath);
87+
strlcpy(err, "unable to decode plugin path", PLUGIN_MAX_ERRLEN);
88+
return NULL;
89+
}
90+
ret->handle = LoadLibraryW(wpath);
91+
free(wpath);
7592
if(ret->handle == NULL) {
7693
DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
7794
FORMAT_MESSAGE_IGNORE_INSERTS;

userspace/plugin/plugin_loader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err);
7272
\brief Loads a dynamic library from the given path and returns a
7373
plugin_handle_t* representing the loaded plugin. In case of error,
7474
returns NULL and fills the err string up to PLUGIN_MAX_ERRLEN chars.
75+
76+
The path must be encoded as UTF-8 on Windows.
7577
*/
7678
plugin_handle_t* plugin_load(const char* path, char* err);
7779

0 commit comments

Comments
 (0)