Boost serialization: archive "unsupported version" exception - serialization

I've got the exception "unsupported version" when I try to deserialize through a text archive some data previously serialized with a upper version of Boost (1.46 to serialize and 1.38 to deserialize)...is there a way to downgrade (in the code) the serialization?
Something like "set_library_version"?

See the Error read binary archive, created by old Boost version mail archive post about the serialization error.
It says that the code below does the job:
void load_override(version_type & t, int version){
library_version_type lvt = this->get_library_version();
if (boost::archive::library_version_type(7) < lvt){
this->detail_common_iarchive::load_override(t, version);
}
else
if (boost::archive::library_version_type(6) < lvt){
uint_least16_t x = 0;
* this->This() >> x;
t = boost::archive::version_type(x);
}
else
if (boost::archive::library_version_type(3) == lvt ||
boost::archive::library_version_type(5) == lvt){
#pragma message("CTMS fix for serialization bug (lack of backwards compatibility) introduced by Boost 1.45.")
// Up to 255 versions
unsigned char x = 0;
* this->This() >> x;
t = version_type(x);
}
else{
unsigned int x = 0;
* this->This() >> x;
t = boost::archive::version_type(x);
}
}

Using text_archive ... I had a recent issue with this also.
I recently upgraded boost from 1.67 to 1.72 on Windows, generated some data on Windows. When I ran the data on my Linux environment which is still on Boost 1.67, it throws not supported.
The header for 1.67 looked like this
22 serialization::archive 16
and 1.72 looked like
22 serialization::archive 17
I changed 17 to 16 and it was happy for my use case.

Related

Did Vulkan-HPP developers change anything in vk::DebugUtilsMessengerEXT creation?

Recently I've updated my system and tried to recompile my Vulkan app (which uses Vulkan cpp binding) and got almost no output from vk::DebugUtilsMessengerEXT (except the string "Added messenger"). I set it up to std::cout every kind of callback, and it printed lots of information strings (before update). Does anyone know, what to do to bring back debug output?
Here is my debug messenger code:
// ...
vk::DebugUtilsMessengerCreateInfoEXT messengerInfo;
messengerInfo.setMessageSeverity(
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose);
messengerInfo.setMessageType(
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance);
messengerInfo.setPfnUserCallback(callback);
messengerInfo.setPUserData(nullptr);
if(instance.createDebugUtilsMessengerEXT(&messengerInfo, nullptr, &debugMessenger, loader) != vk::Result::eSuccess) throw std::runtime_error("Failed to create debug messenger!\n");
}
VKAPI_ATTR VkBool32 VKAPI_CALL System::callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData)
{
std::cout << pCallbackData->pMessage << '\n';
return false;
}
"loader" is vk::DispatchLoaderDynamic
Seems like the trouble is not only with Vulkan-Hpp, but also with C Vulkan.
Did some testing and the callbacks seem to be working correctly. I'm thinking the issue here might be the removal of some old INFO messages for performance reasons -- see Vulkan-ValidationLayers commits 18BF5C637 and 523D9C775. If INFORMATION_BIT messages were enabled in SDK releases previous to 1.1.108, you'd have seen a ton of spew. If expected validation errors are not making it to your callback, please create a github issue in the VVL repo and we'll address it immediately.
How I'm doing it and it works, albeit not the latest SDK:
void VulkanContext::createInstance()
{
// create the list of required extensions
uint32_t glfwExtensionCount = 0;
const char **glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char *> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
auto layers = std::vector<const char *>();
if ( enableValidationLayers )
{
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
layers.push_back("VK_LAYER_LUNARG_standard_validation");
}
vk::ApplicationInfo appInfo("Vulkan test", 1, "test", 1, VK_API_VERSION_1_1);
auto createInfo = vk::InstanceCreateInfo(
vk::InstanceCreateFlags(),
&appInfo,
static_cast<uint32_t>(layers.size()),
layers.empty() ? nullptr : layers.data(),
static_cast<uint32_t>(extensions.size()),
extensions.empty() ? nullptr : extensions.data()
);
instance = vk::createInstanceUnique(createInfo);
dispatcher = vk::DispatchLoaderDynamic(instance.get(), vkGetInstanceProcAddr);
if ( enableValidationLayers )
{
auto severityFlags = vk::DebugUtilsMessageSeverityFlagBitsEXT::eError
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo;
auto typeFlags = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral
| vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation
| vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance;
messenger = instance->createDebugUtilsMessengerEXTUnique(
{{}, severityFlags, typeFlags, debugCallback},
nullptr,
dispatcher
);
}
}
Make sure you're enabling the debug extensions and validation layers.
Check that your loader/dispatcher is initialized correctly.
Try some of the other commands for creating the messenger, not sure but maybe the API changed and the severity flags are passed in the wrong place.
Make sure the validation layers are installed correctly, don't recall dealing with that myself but saw mentions that it can be an issue.

Understanding RiscV objdump

I am examining the objdump of a C file that I have compiled using the following commands:
riscv64-unknown-elf-gcc -O0 -o maxmul.o maxmul.c
riscv64-unknown-elf-objdump -d maxmul.o > maxmul.dump
strangely (or not) the addresses appear not to be aligned on 32-bit words but actually on a 16-bit boundary.
Can anyone please explain me why?
Thanks.
objdump excerpt:
00000000000101da <main>:
101da: 7155 addi sp,sp,-208
101dc: e586 sd ra,200(sp)
101de: e1a2 sd s0,192(sp)
101e0: 0980 addi s0,sp,208
...
C-code:
int main()
{
int first[3][3], second[3][3], multiply[3][3];
int golden[3][3];
int sum;
first[0][0] = 1; first[0][1] = 2; first[0][2] = 3;
first[1][0] = 4; first[1][1] = 5; first[1][2] = 6;
first[2][0] = 7; first[2][1] = 8; first[2][2] = 9;
second[0][0] = 9; second[0][1] = 8; second[0][2] = -7;
second[1][0] = -6; second[1][1] = 5; second[1][2] = 4;
second[2][0] = 3; second[2][1] = 2; second[2][2] = -1;
golden[0][0] = 6; golden[0][1] = 24; golden[0][2] = -2;
golden[1][0] = 24; golden[1][1] = 69; golden[1][2] = -14;
golden[2][0] = 42; golden[2][1] = 1140; golden[2][2] = -26;
int i, ii, iii;
for (i = 0; i < 3; i++) {
for (ii = 0; ii < 3; ii++) {
for (iii = 0; iii < 3; iii++) {
//printf("first[%d][%d] * second[%d][%d] \n", i, iii, iii, ii);
//printf("%d * %d (%d,%d)\n", first[i][ii], second[ii][i], i, ii);
sum += first[i][iii] * second[iii][ii];
}
//printf("sum = %d\n", sum);
multiply[i][ii] = sum;
sum = 0;
}
}
int c, d;
int err;
for ( c = 0; c < 3; c++) {
for ( d = 0; d < 3; d++) {
//printf("%d\t", multiply[c][d]);
if (multiply[c][d] != golden[c][d]) {
fail(golden[c][d], multiply[c][d]);
err++;
}
}
//printf("\n");
}
if (err == 0) {
pass();
}
return 0;
}
I am suspecting that your gcc compiles by default with the compressed instruction format where instructions can be 16b & 32b intermix - in such case, 16b instructions are 16b aligned as you can see in the disassembled code.
Objdump provides the address, the encoding, and the mnemonics ; the encoding in your case is always 16b, which means that the compiler have selected 16b instructions when possible.
By enabling verbose mode (-verbose), you can see that, by default,-march=rv64imafdc and -mabi=lp64d. The default targetted ISA is the compressed one, and the targetted ABI requires Double floats extension.
By setting -march=rv64imafd and letting ABI unchanged, gcc successfully compiles using instructions that are only 32b because compressed ISA is no more enabled.
The addresses of instruction are then always 32b aligned.
When compiling (or assembling) to RV64GC or RV32GC (or another target that enables the "C" Standard Extension Compressed Instructions), the compiler (or assembler) automatically replaces some instructions with compressed ones.
Non-compressed instructions are encoded in 32 bit, while compressed instructions are encoded in 16 bit.
When a compressed instruction is emitted it changes the alignment for the next instruction. Either from 32 bit to 16 bit or from 16 bit to 32 bit. That means not only 16 bit wide instructions may be aligned to a 16 bit address but also 32 bit wide ones. IOW both types of instructions (compressed and normal) are tightly packed side by side.
By default, objdump -d doesn't explicitly indicate that an instruction is compressed because it uses the same mnemonic as for the uncompressed variant. Although the number of bytes in the displayed raw instruction gives it away (4 vs. 2 bytes).
However, you can tell objdump to use separate mnemonics for compressed instructions such that they are more easily recognizable (those start with c. then), e.g.:
$ riscv64-unknown-elf-objdump -d -M no-aliases rotate
[..]
101e4: 00d66533 or a0,a2,a3
101e8: 8082 c.jr ra
00000000000101ea <rotr>:
101ea: 00b55633 srl a2,a0,a1
[..]
Note that with the switch -M no-aliases pseudo-instructions aren't displayed anymore, but the corresponding instruction(s) instead.

How to get diskutil info output in a cocoa application

Is there a way to programmatically get the same information that diskutil info / | grep "Free Space" gives you? (For obvious reasons I'd rather have a better way to do this than just parsing the result of that command.)
Currently I'm using statfs; however, it was brought to my attention that the space this reports is not always accurate, because OS X also places temporary files such as Time Machine snapshots on the drive. These files automatically get deleted if space is running out, and the OS does not report the usage of these files. In other words, statfs often gives a lower number of free space than diskutil info or looking at the disk information in Finder.
You can use popen(3):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *f;
char info[256];
f = popen("/usr/sbin/diskutil info /", "r");
if (f == NULL) {
perror("Failed to run diskutil");
exit(0);
}
while (fgets(info, sizeof(info), f) != NULL) {
printf("%s", info);
}
pclose(f);
return 0;
}
EDIT
Sorry, I didn't read the question carefully. You can also use the Disk Arbitration Framework. There's also some sample code that might be helpful (FSMegaInfo).
UPDATE
I took a look at the output from otool -L $(which diskutil) and it seems that it's using a private framework called DiskManagement.framework. After looking at the output from class-dump I saw there's a volumeFreeSpaceForDisk:error: method. So the sizes I got from diskutil -info / and FSMegaInfo FSGetVolumeInfo / and my tool were:
diskutil: 427031642112 Bytes
my tool: volumeFreeSpaceForDisk: 427031642112
FSMegaInfo: freeBytes = 427031642112 (397 GB)
I also observed that the sizes differ (with a few KB) every time I ran one of the tools and also that diskutil is dividing by 1000 and FSMegaInfo is dividing by 1024, so the size in GB will be always different (same reason as with df -h and df -H and diskutil - base 10 and base 2).
Here's my sample tool:
#import <Foundation/Foundation.h>
#import "DiskManagement.h"
#import <DiskArbitration/DADisk.h>
int main(int argc, char *argv[])
{
int err;
const char * bsdName = "disk0s2";
DASessionRef session;
DADiskRef disk;
CFDictionaryRef descDict;
session = NULL;
disk = NULL;
descDict = NULL;
if (err == 0) {session = DASessionCreate(NULL); if (session == NULL) {err = EINVAL;}}
if (err == 0) {disk = DADiskCreateFromBSDName(NULL, session, bsdName); if (disk == NULL) {err = EINVAL;}}
if (err == 0) {descDict = DADiskCopyDescription(disk); if (descDict == NULL) {err = EINVAL;}}
DMManager *dmMan = [DMManager sharedManager];
NSLog(#"blockSizeForDisk: %#", [dmMan blockSizeForDisk:disk error:nil]);
NSLog(#"totalSizeForDisk: %#", [dmMan totalSizeForDisk:disk error:nil]);
NSLog(#"volumeTotalSizeForDisk: %#", [dmMan volumeTotalSizeForDisk:disk error:nil]);
NSLog(#"volumeFreeSpaceForDisk: %#", [dmMan volumeFreeSpaceForDisk:disk error:nil]);
return 0;
}
You can obtain the DiskManagement.h by running class-dump /System/Library/PrivateFrameworks/DiskManagement.framework/Versions/Current/DiskManagement > DiskManagement.h and you can link to that framework by including the private frameworks path using -F/System/Library/PrivateFrameworks/ and add -framework.
Compile:
clang -g tool.m -F/System/Library/PrivateFrameworks/ -framework Foundation -framework DiskArbitration -framework DiskManagement -o tool
UPDATE2:
You can also take a look here and here. If the FSMegaInfo sample is not working for you, then you can just stat the /Volumes/.MobileBackups and subtract it's size from what you get from statfs("/", &stats).

How to get dylib version information which are in a directory

I wanted to get the dylib version. I've a dylib path for which I wanted to get the version number.
I've tried "otool -L" command and it's giving me the proper output but as per the requirements I can't use it, since I've 100 of dylib in a directory for which I wanted to get the version information and I can't run "otool" command for each dylib through NSTask and NSPipe.
I've also found the NSVersionOfLinkTimeLibrary() function to get the dylib version, but as per the documentation NSVersionOfLinkTimeLibrary returns the version number for linked libraries and not for other dylib.
Any help on this would be helpful.
Thanks.
Omkar
I've solved it by writing my own dylib parser. Below is the code snippet
- (int64_t)getDylibVersion :(NSString *)dylibPth
{
const char* strFilePath = [dylibPth UTF8String];
FILE* fileHandle = fopen(strFilePath, "rb");
struct mach_header mh;
if(fileHandle)
{
size_t bytesRead = fread(&mh, 1, sizeof(mh), fileHandle);
if(bytesRead == sizeof(mh))
{
if((mh.magic == MH_MAGIC_64 || mh.magic == MH_MAGIC) && mh.filetype == MH_DYLIB)
{
for(int j = 0; j < mh.ncmds; j++)
{
union
{
struct load_command lc;
struct dylib_command dc;
} load_command;
if (sizeof(load_command.lc) != fread(&load_command.lc, 1, sizeof(load_command.lc), fileHandle))
goto fail;
switch (load_command.lc.cmd)
{
case LC_SEGMENT:
break;
case LC_UUID:
break;
case LC_DYLD_INFO_ONLY:
break;
case LC_SYMTAB:
break;
case LC_LOAD_DYLIB:
break;
case LC_ID_DYLIB:
{
if (sizeof(load_command) - sizeof(load_command.lc) != fread(&load_command.lc + 1, 1, sizeof(load_command) - sizeof(load_command.lc), dylib_handle))
goto fail;
fclose(fileHandle);
return(load_command.dc.dylib.current_version);
}
default:
break;
}
if (0 != fseek(fileHandle, load_command.lc.cmdsize - sizeof(load_command.lc), SEEK_CUR))
goto fail;
}
}
}
}
fail:
fclose(fileHandle);
return (-1);
}
Note that Mach-O dylib version numbers are encoded as 32-bit unsigned integers, with the major version in the high 16 bits, the minor version in bits 8 through 15, and the patch level in the low 8 bits:
uint32_t version = …;
uint32_t major = version >> 16;
uint32_t minor = (version >> 8) & 0xff;
uint32_t revision = version & 0xff;
Note also that the above code will only work for "thin" binaries. "Fat," multi-architecture binaries start with a fat header, which you'll need to negotiate first to find the slice for your desired architecture. Moreover, the above only works with architectures of the running architecture's endianness.
The way I see it, you have 2 options.
Load each dylib into your process and lookup the Mach-O headers on each, looking for the version numbers. The documentation should be complete and thorough enough to get you started.
Open each dylib as a normal file, and read and parse the Mach-O headers yourself. This avoid having to load each dylib into the process, but it does mean you need to then either parse the Mach-O binary format yourself, or find a library that can do it for you (I don't know of any off the top of my head).

Finding dylib version using dlopen

Is there a way to find the version of a dylib using its path? I am looking for something that accepts the same arguments as dlopen. I have looked at NSVersionOfRunTimeLibrary, but from my reading of the documentation it looks like it gets the version of the current dylib, not the one specified in the path.
Thank you
Run otool -L on it, and it will show its actually version. I choose libSystem.B as it has different version in the 10.4 and 10.5 SDKs:
$ otool -L /Developer/SDKs/MacOSX10.4u.sdk/usr/lib/libSystem.B.dylib
/Developer/SDKs/MacOSX10.4u.sdk/usr/lib/libSystem.B.dylib:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 88.3.11)
/usr/lib/system/libmathCommon.A.dylib (compatibility version 1.0.0, current version 220.0.0)
$ otool -L /Developer/SDKs/MacOSX10.5.sdk/usr/lib/libSystem.B.dylib
/Developer/SDKs/MacOSX10.5.sdk/usr/lib/libSystem.B.dylib:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.4)
/usr/lib/system/libmathCommon.A.dylib (compatibility version 1.0.0, current version 292.4.0)
(see how the first one has 88.3.11 version, while the second has 111.1.4). This example also shows that not all libraries are symbolic links to files with the version number in them:
$ ll /Developer/SDKs/MacOSX10.*.sdk/usr/lib/libSystem.B.dylib
-rwxr-xr-x 1 root wheel 749K May 15 2009 /Developer/SDKs/MacOSX10.4u.sdk/usr/lib/libSystem.B.dylib
-rwxr-xr-x 1 root wheel 670K May 15 2009 /Developer/SDKs/MacOSX10.5.sdk/usr/lib/libSystem.B.dylib
-rwxr-xr-x 1 root wheel 901K Sep 25 00:21 /Developer/SDKs/MacOSX10.6.sdk/usr/lib/libSystem.B.dylib
Here, the files don't have the version number in their name.
EDIT: a second solution is to use NSVersionOfRunTimeLibrary in a test program, in which you force load the library you want to check. Create a program libversion from the following C source:
#include <stdio.h>
#include <mach-o/dyld.h>
int main (int argc, char **argv)
{
printf ("%x\n", NSVersionOfRunTimeLibrary (argv[1]));
return 0;
}
Then, you call it like that:
$ DYLD_INSERT_LIBRARIES=/usr/lib/libpam.2.dylib ./a.out libpam.2.dylib
30000
(here, the version number is printed as hexadecimal, but you can adapt to your needs.)
You can check the source code of NSVersionOfRunTimeLibrary here:
http://www.opensource.apple.com/source/dyld/dyld-132.13/src/dyldAPIsInLibSystem.cpp
Based on that you can create your own version which replaces if(names_match(install_name, libraryName) == TRUE) with if(strcmp(_dyld_get_image_name(i), libraryName) == 0)
That will fix the issue that the original expected the library name without full path, the edited version expects the full path, but it'll still search in the loaded dylibs.
#include <mach-o/dyld.h>
int32_t
library_version(const char* libraryName)
{
unsigned long i, j, n;
struct load_command *load_commands, *lc;
struct dylib_command *dl;
const struct mach_header *mh;
n = _dyld_image_count();
for(i = 0; i < n; i++){
mh = _dyld_get_image_header(i);
if(mh->filetype != MH_DYLIB)
continue;
load_commands = (struct load_command *)
#if __LP64__
((char *)mh + sizeof(struct mach_header_64));
#else
((char *)mh + sizeof(struct mach_header));
#endif
lc = load_commands;
for(j = 0; j < mh->ncmds; j++){
if(lc->cmd == LC_ID_DYLIB){
dl = (struct dylib_command *)lc;
if(strcmp(_dyld_get_image_name(i), libraryName) == 0)
return(dl->dylib.current_version);
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
return(-1);
}