Skip to content

Commit

Permalink
Z: Fix atoe_vsnprintf to support null buffer
Browse files Browse the repository at this point in the history
Std vsnprintf accepts null buffer and returns an estimate
Our implementation does not support that
Updated the atoe_vsnprintf implementation

Signed-off-by: ehsan kiani far <ehsan.kianifar@gmail.com>
  • Loading branch information
ehsankianifar committed Nov 8, 2023
1 parent 01e77f6 commit 633d1e2
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 132 deletions.
82 changes: 63 additions & 19 deletions fvtest/porttest/omrstrTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1466,52 +1466,60 @@ TEST(PortStrTest, str_WinacpToMutf8)

#if defined(J9ZOS390) && !defined(OMR_EBCDIC)
/**
* Check whether a null/non-null terminated string is properly handled by fstring().
* It calls atoe_vsnprintf() to verify the functionalities.
* @param[in] portLibrary - The port library under test
* @param[in] precision - flag for precision specifier
* @param[in] buffer - pointer to the buffer intended for atoe_vsnprintf()
* @param[in] bufferLength - the buffer length
* @param[in] expectedOutput - The expected string
* @param[in] expectedCount - The expected response from atoe_vsnprintf()
* @param[in] format - The string format
*
* @return TEST_PASS on success
* TEST_FAIL on error
*/
static int
printToBuffer(struct OMRPortLibrary *portLibrary, BOOLEAN precision, char *buffer, size_t bufferLength, const char *expectedOutput, const char *format, ...)
printToBuffer(struct OMRPortLibrary *portLibrary, BOOLEAN precision, char *buffer, size_t bufferLength, const char *expectedOutput, int expectedCount, const char *format, ...)
{
OMRPORT_ACCESS_FROM_OMRPORT(portLibrary);
static const char NULLCHARSTRING[] = "[null]";
int stringLength = 0;
int expectedLength = (NULL == expectedOutput) ? 0 : strlen(expectedOutput);
int actualCount = 0;
const char *nonNullExpectedOutput = (NULL == expectedOutput) ? NULLCHARSTRING : expectedOutput;
const char *nonNullBuffer = (NULL == buffer) ? NULLCHARSTRING : buffer;
va_list args;

va_start(args, format);
stringLength = atoe_vsnprintf(buffer, bufferLength, format, args);
actualCount = atoe_vsnprintf(buffer, bufferLength, format, args);
stringLength = (NULL == buffer) ? 0 : strlen(buffer);
va_end(args);

if (stringLength >= 0) {
if (actualCount >= 0) {
if (precision) {
portTestEnv->log("\n\tFinish Testing: String in buffer is: \"%s\", length = %d\n", buffer, stringLength);
portTestEnv->log("\n\tFinish Testing: String in buffer is: \"%s\", length = %d\n", nonNullBuffer, stringLength);
} else {
portTestEnv->log("\n\tFinish Testing without precision specifier: String in buffer is: \"%s\", length = %d\n", buffer, stringLength);
portTestEnv->log("\n\tFinish Testing without precision specifier: String in buffer is: \"%s\", length = %d\n", nonNullBuffer, stringLength);
}

if ((stringLength == strlen(expectedOutput))
&& (0 == memcmp(buffer, expectedOutput, stringLength))
if ((stringLength == expectedLength)
&& (actualCount == expectedCount)
&& ((NULL == buffer) || (0 == memcmp(buffer, expectedOutput, stringLength + 1)))
) {
portTestEnv->log("\n\tComparing against the expected output: PASSED.\n");
return TEST_PASS;
} else {
portTestEnv->log(LEVEL_ERROR, "\n\tComparing against the expected output: FAILED. Expected string: \"%s\", length = %d\n", expectedOutput, strlen(expectedOutput));
portTestEnv->log(LEVEL_ERROR, "\n\tComparing against the expected output: FAILED. Expected string: \"%s\", length = %d\n", nonNullExpectedOutput, expectedLength);
return TEST_FAIL;
}
} else {
portTestEnv->log(LEVEL_ERROR, "\n\tComparing against the expected output: FAILED. stringLength < 0, Expected string: \"%s\", length = %d\n", expectedOutput, strlen(expectedOutput));
portTestEnv->log(LEVEL_ERROR, "\n\tComparing against the expected output: FAILED. stringLength < 0, Expected string: \"%s\", length = %d\n", nonNullExpectedOutput, expectedLength);
}
}

/**
* Verify that null/non-null terminated strings are properly handled in fstring().
* Verify that null/non-null terminated strings are properly handled.
* Also checks if number, long number, long long number, and float are properly handled.
* It actually calls invoke atoe_vsnprintf() to run the tests through sub-functions.
*/
TEST(PortStrTest, str_test_atoe_vsnprintf)
Expand All @@ -1538,35 +1546,71 @@ TEST(PortStrTest, str_test_atoe_vsnprintf)

/* Neither min_width nor precision is specified for a null terminated input string*/
portTestEnv->log("\n\tTesting case 1\n");
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput1, "%s", nullTerminatedString);
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput1, strlen(expectedOutput1), "%s", nullTerminatedString);

/* min_width is less than the length of inputString */
portTestEnv->log("\n\tTesting case 2\n");
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer2, bufferLength2, expectedOutput2, "%*s", 2, nonNullTerminatedString);
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer2, bufferLength2, expectedOutput2, strlen(nullTerminatedString), "%*s", 2, nullTerminatedString);

/* min_width is equal to the length of inputString (buffer length > min_width) */
portTestEnv->log("\n\tTesting case 3\n");
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer1, bufferLength1, expectedOutput1, "%*s", 4, nullTerminatedString);
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer1, bufferLength1, expectedOutput1, strlen(expectedOutput1), "%*s", 4, nullTerminatedString);

/* min_width is greater than the length of inputString (buffer length > min_width) */
portTestEnv->log("\n\tTesting case 4\n");
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer3, bufferLength3, expectedOutput3, "%*s", 10, nullTerminatedString);
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer3, bufferLength3, expectedOutput3, strlen(expectedOutput3), "%*s", 10, nullTerminatedString);

/* precision is equal to the length of inputString */
portTestEnv->log("\n\tTesting case 5\n");
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput1, "%.*s", 4, nonNullTerminatedString);
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput1, strlen(expectedOutput1), "%.*s", 4, nonNullTerminatedString);

/* precision is less than the length of inputString */
portTestEnv->log("\n\tTesting case 6\n");
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput4, "%.*s", 2, nonNullTerminatedString);
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput4, strlen(expectedOutput4), "%.*s", 2, nonNullTerminatedString);

/* both min_width and precision are equal to the length of inputString */
portTestEnv->log("\n\tTesting case 7\n");
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput1, "%*.*s", 4, 4, nonNullTerminatedString);
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput1, strlen(expectedOutput1), "%*.*s", 4, 4, nonNullTerminatedString);

/* the length of inputString is equal to precision but less than min_width */
portTestEnv->log("\n\tTesting case 8\n");
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput3, "%*.*s", 10, 4, nonNullTerminatedString);
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, expectedOutput3, strlen(expectedOutput3), "%*.*s", 10, 4, nonNullTerminatedString);

/* the buffer is NULL. expect to estimate the length */
portTestEnv->log("\n\tTesting case 9\n");
rc |= printToBuffer(OMRPORTLIB, FALSE, NULL, 0, NULL, strlen(nullTerminatedString), "%s", nullTerminatedString);

/* number with min_width */
portTestEnv->log("\n\tTesting case 10\n");
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer0, bufferLength0, " -123", 6, "%*d", 6, -123);

/* number with precision */
portTestEnv->log("\n\tTesting case 11\n");
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, "-000123", 7, "%.*d", 6, -123);

/* long number with min_width */
portTestEnv->log("\n\tTesting case 12\n");
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer0, bufferLength0, " -1234", 7, "%*ld", 7, -1234L);

/* long number with precision */
portTestEnv->log("\n\tTesting case 13\n");
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, "-0001234", 8, "%.*ld", 7, -1234L);

/* long long number with min_width */
portTestEnv->log("\n\tTesting case 14\n");
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer0, bufferLength0, " -12345", 8, "%*lld", 8, -12345LL);

/* long long number with precision */
portTestEnv->log("\n\tTesting case 15\n");
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, "-00012345", 9, "%.*lld", 8, -12345LL);

/* float number with no precision */
portTestEnv->log("\n\tTesting case 16\n");
rc |= printToBuffer(OMRPORTLIB, FALSE, buffer0, bufferLength0, "-123.456000", 11, "%f", -123.456);

/* float number with precision */
portTestEnv->log("\n\tTesting case 17\n");
rc |= printToBuffer(OMRPORTLIB, TRUE, buffer0, bufferLength0, "-123.46", 7, "%.2f", -123.456);

if (TEST_PASS != rc) {
outputErrorMessage(PORTTEST_ERROR_ARGS, "\n\tTEST FAILED.\n");
Expand Down
Loading

0 comments on commit 633d1e2

Please sign in to comment.