Skip to content

Commit

Permalink
Merge pull request #307 from ethereum/loader_strcpy_s
Browse files Browse the repository at this point in the history
loader: Fix strcpy_s()
  • Loading branch information
chfast authored May 31, 2019
2 parents f12ea3d + 8c3b3e6 commit 0f2416d
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 7 deletions.
29 changes: 22 additions & 7 deletions lib/loader/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,33 @@
#define ATTR_FORMAT(...)
#endif

#if !_WIN32
#if _WIN32
#define strcpy_sx strcpy_s
#else
/*
* Provide strcpy_s() for GNU libc.
* Limited variant of strcpy_s().
*
* Provided for C standard libraries where strcpy_s() is not available.
* The availability check might need to adjusted for other C standard library implementations.
*/
static void strcpy_s(char* dest, size_t destsz, const char* src)
#if !defined(EVMC_LOADER_MOCK)
static
#endif
int
strcpy_sx(char* restrict dest, size_t destsz, const char* restrict src)
{
size_t len = strlen(src);
if (len > destsz - 1)
len = destsz - 1;
if (len >= destsz)
{
// The input src will not fit into the dest buffer.
// Set the first byte of the dest to null to make it effectively empty string
// and return error.
dest[0] = 0;
return 1;
}
memcpy(dest, src, len);
dest[len] = 0;
return 0;
}
#endif

Expand Down Expand Up @@ -124,7 +139,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
const char prefix[] = "evmc_create_";
const size_t prefix_length = strlen(prefix);
char prefixed_name[sizeof(prefix) + PATH_MAX_LENGTH];
strcpy_s(prefixed_name, sizeof(prefixed_name), prefix);
strcpy_sx(prefixed_name, sizeof(prefixed_name), prefix);

// Find filename in the path.
const char* sep_pos = strrchr(filename, '/');
Expand All @@ -142,7 +157,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
name_pos += lib_prefix_length;

char* base_name = prefixed_name + prefix_length;
strcpy_s(base_name, PATH_MAX_LENGTH, name_pos);
strcpy_sx(base_name, PATH_MAX_LENGTH, name_pos);

// Trim the file extension.
char* ext_pos = strrchr(prefixed_name, '.');
Expand Down
29 changes: 29 additions & 0 deletions test/unittests/test_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ static constexpr bool is_windows = false;
#endif

extern "C" {
#if _WIN32
#define strcpy_sx strcpy_s
#else
/// Declaration of internal function defined in loader.c.
int strcpy_sx(char* dest, size_t destsz, const char* src);
#endif

/// The library path expected by mocked evmc_test_load_library().
extern const char* evmc_test_library_path;

Expand Down Expand Up @@ -118,6 +125,28 @@ static evmc_instance* create_failure()
return nullptr;
}

TEST_F(loader, strcpy_sx)
{
const char input_empty[] = "";
const char input_that_fits[] = "x";
const char input_too_big[] = "12";
char buf[2] = {0x0f, 0x0f};
static_assert(sizeof(input_empty) <= sizeof(buf), "");
static_assert(sizeof(input_that_fits) <= sizeof(buf), "");
static_assert(sizeof(input_too_big) > sizeof(buf), "");

EXPECT_EQ(strcpy_sx(buf, sizeof(buf), input_empty), 0);
EXPECT_EQ(buf[0], 0);
EXPECT_EQ(buf[1], 0x0f);

EXPECT_EQ(strcpy_sx(buf, sizeof(buf), input_that_fits), 0);
EXPECT_EQ(buf[0], 'x');
EXPECT_EQ(buf[1], 0);

EXPECT_NE(strcpy_sx(buf, sizeof(buf), input_too_big), 0);
EXPECT_EQ(buf[0], 0);
}

TEST_F(loader, load_nonexistent)
{
constexpr auto path = "nonexistent";
Expand Down

0 comments on commit 0f2416d

Please sign in to comment.