0

I've got this piece of code, where I gather device id from different types of devices supported by my game and set lua global to have value of id of current device. When I get id of the iOS device I receive a const char* from a mixed C++/Objective-C class and pass it on to the Lua stack. It all works fine. However I receive std::string from a piece of code responsible for getting Android device id. When I push deviceId.c_str() I get nil in Lua. I've tried passing const char* from the code responsible for getting the device id, but then it seems something wrong goes on with the pointer when it's returned from function [that's why I decided to return string, it works fine this way].

What should I do to allow passing const char* out of std::string without problems?

EDIT: I've tried using strcpy but it didn't work :/ still having the same problem.

So.. the code responsible for gathering deviceId from different devices looks like this:

#include "DeviceInfo.h"
#include "DeviceInfoIOS.h"
#include "DeviceInfoAndroid.h"
#include <string>


USING_NS_CC;

extern "C" {

const char *getDeviceId() {

    const char *deviceId;

    CCLog("test");

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    DeviceInfoIOS ios;
    deviceId = ios.getIOSDeviceId();
    CCLog("iOS platform %s", deviceId);

#endif  // CC_PLATFORM_IOS

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

    CCLog("Android platform");
    std::string tempId = getAndroidDeviceId();
    CCLog("Android platform test %s", tempId.c_str());
    char y[tempId.size() + 1];
    strcpy(y, tempId.c_str());
    deviceId = (const char*) y;
    CCLog("Android platform %s", deviceId);


#endif  // CC_PLATFORM_ANDROID
    CCLog("Finished platform check");
    return deviceId;
}

}

Just a small note: All the logs look ok. Devie id is passed fine.

This is how I pass device id to Lua:

//deviceInfo
CCLog("DeviceInfo load");
const char *deviceId = getDeviceId();
CCLog("DeviceInfo %s", deviceId);
lua_pushstring(d_state, deviceId);
lua_setglobal(d_state, "DEVICE_ID");

Also in here, logfile contains the device id.

Krystian
  • 3,193
  • 2
  • 33
  • 71
  • It probably does. This is a mixed environment, part of the code is within extern "C". How can I copy the value in memory to make sure pointer points to the correct place. I don't need string container, just the char. – Krystian Jan 02 '12 at 17:44
  • You probably do need a string container if you want to make sure you don't leak. But if you are sure then do a strcpy(). `strcpy(data.c_str())` The string will live until you delete it. – Martin York Jan 02 '12 at 17:49
  • Under what compiler does this compile? C++ does not allow `char y[tempId.size() + 1]`, which is a dynamically sized local array. And C doesn't allow `std::string`. So what compiler and compiler settings causes this mishmash of C99 and C++ to work? – Nicol Bolas Jan 02 '12 at 22:27
  • Hmm when it comes to iOS hm I am not sure. Whatever comes with xcode and iOS SDK 4.x. When it comes to Android I'm using Android NDK r7. To be honest I have no clue what compilers are used internally. – Krystian Jan 02 '12 at 22:43

1 Answers1

2

Your getDeviceId function is broken. Both tempId and y are stack variables. They will be destroyed once you return. Returning pointers to stack variables is always a bad idea.

Your function ought to return a std::string. Failing that, it should return a char* array that it allocates with new, and that the user is expected to deallocate with delete. That's generally why it's preferable to just return a std::string. Alternatively, you could delcare y as a static local variable using a fixed size (rather than one based on the string).

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • hmmm how come then it works fine when ran on iOS? Also.. when doing lua_pushstring value should be copied. I don't get this part. If I use new and delete, I will deallocate it after calling lua_setglobal.. just like it's done right now. – Krystian Jan 02 '12 at 21:29
  • @Krystian: Accessing a returned pointer to a stack variable is undefined behavior. That means it can *appear* to "work fine" in some cases but not others. – Nicol Bolas Jan 02 '12 at 21:43
  • @Krystian: Look at [this answer](http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope/6445794#6445794) for further details. – Nicol Bolas Jan 02 '12 at 21:55
  • Hmm I know that it might look like I'm misusing a pointer, however this two behaviors [iOS working and Android not working] is 100% reproductible all the time. On the other hand it is probably due to iOS using Objective-C and returning [NSString UTF8String]. Probably autorelease works this way when combined with C/C++ mix. I will try to change the code now and see what happens. – Krystian Jan 02 '12 at 22:18
  • 1
    @Krystian: It doesn't matter if it is reproducible; the rules of C and C++ says that it is **illegal**. I don't know what ObjectiveC says about it, since it's garbage collected and so forth. But as far as C and C++ is concerned, it is wrong. Just because code executes and does what you expect doesn't make it *right*. – Nicol Bolas Jan 02 '12 at 22:24
  • So I did change every method/function to return std::string and now it does behave the same on both platforms. Thanks Nicol :) – Krystian Jan 02 '12 at 22:55