va_list isnt working propertly

closed account (10oTURfi)
I have this function:
1
2
3
4
5
6
7
8
9
void CommandHandler::HandleAccountCreateCommand()
{
    std::string Username, Password;
    ExtractArg(Username);
    ExtractArg(Password);

    sDatabase.PExecute("INSERT INTO `players` VALUES (%u, '%s', '%s', 0, 0, 'dg_classm32.gif', 0, 0, 0, 0, 0)", Generate64BitsGUID(), Username.c_str(), Password.c_str());
    sLog.Write("Account %s successfully created.", Username.c_str()); // Nothing was thrown
}


Which calls this function:
1
2
3
4
5
6
7
8
9
10
11
12
    #define MAX_QUERY_LEN 3*1024
    void Database::PExecute(const char* sql, ...)
    {
        va_list ArgList;
        char CQuery[MAX_QUERY_LEN];

        va_start(ArgList, sql);
        secure_vsnprintf(CQuery, MAX_QUERY_LEN, sql, ArgList); // #define secure_vsnprintf vsnprintf_s
        va_end(ArgList);

        Execute(CQuery);
    }


When I step over with debugger, Username and Password are propertly extracted.
But after secure_vsnprintf CQuery contains:

CQuery = 0x02f9e46c "INSERT INTO `players` VALUES (3758096389, '(null)', 'krofna', 0, 0, 'dg_classm32.gif', 0, 0, 0, 0, 0)"

Second col should be 'krofna', not third, and third must be my password.

How can I fix this?
Last edited on
Here's an example how to use vsnprintf()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdarg.h>

std::string Format(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);

	char buffer[128];	// large enough?
	vsnprintf(
		buffer, sizeof(buffer), fmt, args);

	va_end(args);
	return buffer;
}

int main(int argc, char *argv[])
{
	std::string Username = "Krofna";
	std::string Password = "password";

	std::string str = Format(
		"INSERT INTO `players` VALUES ('%s', '%s', 0, 0, 'dg_classm32.gif', 0, 0, 0, 0, 0)",
		Username.c_str(), Password.c_str());
	std::cout << str << std::endl;

	return 0;
}
closed account (10oTURfi)
EDIT: nvm, solved, %llu
Is it possible that vnsprintf dislikes 64bit ints? This crashes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdarg.h>
#include <cstdint>

std::string Format(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);

	char buffer[128];	// large enough?
	vsnprintf(
		buffer, sizeof(buffer), fmt, args);

	va_end(args);
	return buffer;
}

int main(int argc, char *argv[])
{
	std::string Username = "Krofna";
	std::string Password = "password";

	std::string str = Format(
		"INSERT INTO `players` VALUES (%u, '%s', '%s', 0, 0, 'dg_classm32.gif', 0, 0, 0, 0, 0)",
		(uint64_t)0xFFFFFFFFFFFF, Username.c_str(), Password.c_str());
	std::cout << str << std::endl;
    std::cin.get();
	return 0;
}


Also, if you sture a value that can fit into uint32_t, it behaves like my example in first post:

1
2
3
uint64_t a = 15;
std::string str = Format( "INSERT INTO `players` VALUES (%u, '%s', '%s', 0, 0, 'dg_classm32.gif', 0, 0, 0, 0, 0)", 
a, Username.c_str(), Password.c_str());


INSERT INTO `players` VALUES (15, '(null)', 'Krofna'//...
Last edited on
Of course if you have a type mismatch, you'll have errors in processing.

You have to ensure that the format spec matches the type of the parameter. Some compilers will do the check for you, but notably, Microsoft compilers don't.
Topic archived. No new replies allowed.