Home > Blockchain >  Problems discovering glibc version in C
Problems discovering glibc version in C

Time:06-03

My application is distributed with two binaries. One which is linked to an old glibc (for example, 2.17) and another binary that targets a newer glibc (for example, 2.34). I also distribute a launcher binary (linked against glibc 2.17) which interrogates the user's libc version and then runs the correct binary.

My code to establish the user's libc looks something like the following:

std::string gnu(gnu_get_libc_version());
double g_ver = std::stod(gnu);
if(g_ver >= 2.34)
{
     return GLIBC_MAIN;
}
else
{
     return GLIBC_COMPAT;
}

This works perfectly for the best part, however, some of my users report that despite having a new glibc, the old glibc binary is actually run. I have investigated this and have discovered that double g_ver is equal to 2, not 2.34 as it should be. That is, the decimal part is missing. gnu_get_libc_version() always has the correct value so it must be a problem when converting the string to a double.

I have also tried boost::lexical_cast but this has the same effect.

std::string gnu(gnu_get_libc_version());
//double g_ver = std::stod(gnu);
double glibc = boost::lexical_cast<double>(gnu);
if(g_ver >= 2.34)
{
  return GLIBC_MAIN;
}
else
{
   return GLIBC_COMPAT;
}

Needless to say, I am unable to reproduce this behaviour on any of my computers even when running the exact same distribution / version of Linux as affected users.

Does anybody know why boost::lexical_cast or std::stod sometimes misses the decimal part of the version number? Is there an alternative approach to this?

UPDATE

Upon further tests, this problem is introduced when using a different locale. I set my locale to fr_FR.UTF-8 on a test machine and was able to reproduce this problem. However, the output of gnu_get_libc_version() seems to be correct but std::stod is unable to parse the decimal point part of the version.

Does anybody know how to correct this problem?

CodePudding user response:

Could this be the locale of the user? The decimal separator is not a '.' in all locales and stod uses the current locale?

CodePudding user response:

The fundamental problem is that the glibc version is a string and not a decimal number. So for a "proper" solution you need to parse it manually and implement your own logic to decide which version is bigger or smaller.

However, as a quick and dirty hack, try inserting the line

setlocale(LC_NUMERIC, "C");

before the strtod call. That will set the numeric locale back to the default C locale where the decimal separator is .. Don't remember to set it back afterwards if you're doing something that needs correct locales later in the program.

CodePudding user response:

gnu_get_libc_version() may return more than just X.X, It may be be 2.0.1 for example.

However strtod wont handle all of the invalid part of the number to would equate to 2.0 in this case.

You need to verify the actual value as a string returned from gnu_get_libc_version in the versions you currently do not have access to

  • Related