The following app crashes with nullpointer. I am wondering whats wrong...
#include "stdio.h"
#include "string.h"
char* getFileData(char* fileName);
bool createShader( int shaderType, const char* shader, const char* shaderFile ) ;
void glShaderSource(int shader, int count, const char** string, const int* length);
int main(int argc, char* argv[])
{
char* shader = getFileData("filea.csd");
bool success = createShader(1, shader, "filea.csd");
return 0;
}
char* getFileData(char* fileName) {
if(!strcmp(fileName, "filea.csd"))
return "this is the content of the file a\0";
else if(!strcmp(fileName, "fileb.csd"))
return "this is the content of the file b\0";
else if(!strcmp(fileName, "filec.csd"))
return "this is the content of the file c\0";
else
return "";
}
bool createShader( int shaderType, const char* shader, const char* shaderFile )
{
int shaderHandle = 122;
glShaderSource( shaderHandle, 1, &shader, NULL ); ////This line is where it crashes.
return true;
}
void glShaderSource(int shader, int count, const char** string, const int* length) {
}
Since the Pointer is NULL, try passing the double pointer. Something of the form
bool createShader( GLenum shaderType, const char** shader, const char* shaderFile )//<-- change
{
GLuint shaderHandle = glCreateShader( shaderType );
glShaderSource( shaderHandle, 1, shader, NULL ); //<--change
glCompileShader( shaderHandle );
int status = 0;
glGetShaderiv( shaderHandle, GL_COMPILE_STATUS, &status );
}
void main () {
char* shader = strdup(getFileData("filea.csd"));
bool success = createShader(shaderType, &shader, "filea.csd"); //<--change
delete shader;
return success;
}
I think checking the return value from glCreateShader might be a good thing. Make sure it's non-zero.
The line
delete shader
is also wrong. It may not be crashing there but you need to use free to release memory allocated by malloc.
One bug I see is this line:
delete shader;
That line will only work correctly if the memory pointed by shader was allocated with the new operator. But if we look at your getFileData() method, we see that the character arrays it returns are not allocated by new, but rather are static data.
So the fix would be to have getFileData() return a character array that was allocated by the new operator, or better yet a std::string. Using dynamically-allocated character arrays for string handling is very error prone and not recommended.
Related
The call to ImGui::InputText() takes a char array which I need to initialise from a std::string and then transfer the contents back to the std::string. In it's simplest form:
char buf[255]{};
std::string s{"foo"};
void fn() {
strncpy( buf, s.c_str(), sizeof(buf)-1 );
ImGui::InputText( "Text", buf, sizeof(buf) );
s=buf;
}
However, it appears wasteful to have two buffers (buf and the buffer allocated within std::string) both doing much the same thing. Can I avoid the buf buffer and the copying to and from it by using just the std::string and a simple wrapper "X".
I don't care about efficiency, I just want the simplest code at the call site.
This code does work but is it safe and is there a better way?
class X {
public:
X(std::string& s) : s_{s} { s.resize(len_); }
~X() { s_.resize(strlen(s_.c_str())); }
operator char*(){ return s_.data(); }
static constexpr auto len() { return len_-1; }
private:
std::string& s_;
static constexpr auto len_=255;
};
std::string s{"foo"};
void fn() {
ImGui::InputText( "Text", X(s), X::len() );
}
If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp.
misc/cpp/imgui_stdlib.h
namespace ImGui
{
// ImGui::InputText() with std::string
// Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
}
Your first code
std::string s{"foo"};
void fn() {
ImGui::InputText( "Text", &s );
}
Reading manuals works wonders.
I am trying to compile a simple colored triangle example with OpenGL 3 (GLSL 130) but my fragment shader never compiles. The error reported is always
syntax error unexpected $end
My vertex shader compiles and shows the geometry but the fragment shader fails.
Here are the sources (very simple one):
Vertex.vs:
attribute vec3 vertex_position;
attribute vec3 vertex_color;
varying vec4 out_color;
void main(void)
{
gl_Position = vec4(vertex_position, 1.0);
out_color = vec4(vertex_color, 1.0);
}
And fragment.fs:
varying vec4 out_color;
void main(void)
{
gl_FragColor = out_color;
}
[EDIT] Here is my shader compile code:
char *loadShader(const char *fname)
{
FILE* fp = fopen(fname, "rb");
long size = 0;
if (!fp)
return NULL;
fseek(fp, 0, SEEK_END);
size = ftell(fp) + 1;
fseek(fp, 0, SEEK_SET);
char* data = (char*) malloc((sizeof(char) * size));
::fread(data, 1, size, fp);
data[size-1] = '\0';
fclose(fp);
return data;
}
Shader::Shader(const char *fname)
: m_data(NULL),
ID(0)
{
if (fname)
m_data = ilian::loadShader(fname);
}
Shader::Shader(const char *data, size_t size)
{
if (data && size >0)
{
m_data = (char*) malloc(sizeof(char) * size);
::memmove(m_data, data, size);
}
}
Shader::~Shader()
{
if (m_data)
{
free(m_data);
m_data = NULL;
}
glDeleteShader(ID);
std::cout << "~Shader()\n";
}
std::string Shader::data()
{
std::string s((char*)m_data);
return s;
}
GLuint &Shader::getID()
{
return ID;
}
void Shader::createShader(ShaderType type)
{
GLint res = -1;
switch (type)
{
case VERTEX:
ID = glCreateShader(GL_VERTEX_SHADER);
break;
case FRAGMENT:
ID = glCreateShader(GL_FRAGMENT_SHADER);
break;
default:
break;
}
const GLchar* source = (const GLchar*) data().c_str();
int shader_len = data().length();
glShaderSource(ID, 1, &source, &shader_len);
glCompileShader(ID);
glGetShaderiv(ID, GL_COMPILE_STATUS, &res);
if (res == GL_TRUE)
{
std::cout << "Shader Compile OK!\n";
}
else
{
std::cout << "Shader Compile FAIL!\n";
GLint maxLength = 0;
glGetShaderiv(ID, GL_INFO_LOG_LENGTH, &maxLength);
//The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetShaderInfoLog(ID, maxLength, &maxLength, &infoLog[0]);
std::cout << (char*)infoLog.data() << "\n";
//We don't need the shader anymore.
glDeleteShader(ID);
}
}
GLProgram::GLProgram(const char *vs_source, const char *fs_source)
: ID(0), vs(nullptr), fs(nullptr)
{
vs = new Shader(vs_source);
fs = new Shader(fs_source);
vs->createShader(VERTEX);
fs->createShader(FRAGMENT);
}
GLProgram::~GLProgram()
{
if (vs)
delete vs;
if (fs)
delete fs;
}
VAO &GLProgram::getVertexArrayObject()
{
return vao;
}
bool GLProgram::createProgram()
{
static GLint msg;
ID = glCreateProgram();
glAttachShader(ID, vs->getID());
glAttachShader(ID, fs->getID());
glLinkProgram(ID);
glGetProgramiv(ID, GL_LINK_STATUS, &msg);
std::cout << "Link status: (" <<msg
<< ")"<< std::endl;
if (!msg)
{
GLint infoLen = 0;
glGetProgramiv(ID, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = new char[infoLen];
glGetProgramInfoLog(ID, infoLen, NULL, infoLog);
printf("Error linking program:\n%s\n", infoLog);
delete [] infoLog;
}
}
}
void GLProgram::bind(int location, const char *attribyte)
{
glBindAttribLocation(ID, location, attribyte);
}
void GLProgram::useProgram()
{
glUseProgram(ID);
glBindVertexArray(vao.ID());
}
You are passing a pointer to an invalid memory address to glShaderSource. This happens because you try to get the c_str() pointer from a temporary string object in this line:
const GLchar* source = (const GLchar*) data().c_str();
Right after this line, the temporary string returned by data() gets deleted and the source pointer points to an invalid memory address.
The shortest (but ugly) fix to your code is to make sure that the string object still lives when you use the pointer by storing it:
auto data_str = data();
const GLchar* source = (const GLchar*)data_str.c_str();
But since the construction of the whole string object is completely useless in your code (and actually hurts performance because the string object creates a copy of the underlying char array), the better way is to return the char* instead of a new std::string in the data() function:
const char* Shader::data()
{
return m_data;
}
and use it with:
const GLchar* source = data();
Or even better: Do not use a char* with malloc in the first place and use the proper C++ methods to directly load a std::string from the file.
Well this is a bit of an embarrasing problem, I can't seem to load any sort of file through a program I made. My program fails everytime regardless of the file i try to load, so I'm not quite sure what's going on. Specifically, the program is supposed to be loading GLSL shaders, and it hasn't been working. Here is my code:
static inline GLuint GetProgram(const char* vert,const char* frag)
{
GLuint vertex,fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
std::string vCode,fCode;
std::ifstream vss(vert);
std::ifstream fss(frag);
if(vss.is_open())
{
std::string line;
while(std::getline(vss,line))
{
vCode += line + '\n';
}
}
else
{
OutputDebugStringA("ERROR READING VERTEX SHADER\n");
}
if(fss.is_open())
{
std::string line;
while(std::getline(fss,line))
{
fCode += line + '\n';
}
}
else
{
OutputDebugStringA("ERROR READING FRAGMENT SHADER\n");
}
vss.close();
fss.close();
char const* vsp = vCode.c_str();
char const* fsp = fCode.c_str();
glShaderSource(vertex,1,&vsp,NULL);
glShaderSource(fragment,1,&fsp,NULL);
OutputDebugStringA("Vertex Source:\n");
OutputDebugStringA(vsp + '\n');
OutputDebugStringA("Fragment Source:\n");
OutputDebugStringA(fsp + '\n');
glCompileShader(vertex);
glCompileShader(fragment);
GLuint prog = glCreateProgram();
glAttachShader(prog,vertex);
glAttachShader(prog,fragment);
glLinkProgram(prog);
char errbuf[1024];
GLsizei len;
glGetProgramInfoLog(prog,sizeof(errbuf),&len,errbuf);
OutputDebugStringA(errbuf);
glUseProgram(prog);
return prog;
}
vss.is_open() and fss.is_open() return false everytime. This problem only occurs with this program too, I have another that runs the exact same function listed and it works just fine.
How I am calling it:
GLuint program = Shader::GetProgram("v.vert","f.frag");
The directory:
Finally got it! Just had to use _getcwd(), move my files to that location and append the file names of the two shaders. Here is my code now:
static inline GLuint GetProgram(const char* vert,const char* frag)
{
GLuint vertex,fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
const char* dir = _getcwd(NULL,0);
std::string var1 = dir;
std::string vCode,fCode;
std::fstream vss;
std::fstream fss;
char* var2 = "/";
std::string vertpath = var1;
std::string fragpath = var1;
vertpath.append(var2);
fragpath.append(var2);
fragpath.append(frag);
vertpath.append(vert);
vss.open(vertpath);
fss.open(fragpath);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it a good idea to return “ const char * ” from a function?
how to return char array in c++?
What is wrong with this return? I'm trying to return the current path using the following function but it doesn't seems to be correct:
Please Not: I need an char return not string.
char* getINIfile(void)
{
char buffer[MAX_PATH];
GetModuleFileName( NULL, buffer, MAX_PATH );
string::size_type pos = string( buffer ).find_last_of( "\\/" );
string path = string( buffer ).substr( 0, pos) + "\\setup.ini";
char *ini_local= (char*)path.c_str();
printf(ini_local); // so far output OK!
return ini_local;
}
main
{
printf(getINIfile()); // output Not OK!
char mybuffer[200];
GetPrivateProfileStringA( "files","DLL","0", mybuffer,200, getINIfile());
printf(mybuffer);
}
path goes out of scope at the end of the function and you are returning an internal pointer in that out of scope object. try returning an std::string instead
std::string getINIfile(void)
{
char buffer[MAX_PATH];
GetModuleFileName( NULL, buffer, MAX_PATH );
string::size_type pos = string( buffer ).find_last_of( "\\/" );
string path = string( buffer ).substr( 0, pos) + "\\setup.ini";
char *ini_local= (char*)path.c_str();
printf(ini_local); // so far output OK!
return path;
}
You're returning an address that goes out of scope when the function exits, and so it's no longer valid: std::string path is local to the function getINIFile and so it's invalid after the function exits, as is the address that you get from path.c_str().
In this case you can just return the std::string from your function. If you really need a C string later, you can use c_str() then:
std::string getINIfile(void)
{
//...
return path;
}
int main()
{
string path = getINIFile();
// do something with path.c_str():
const char *cPath = path.c_str();
}
Given your code I can't think of any reason that you must have a char* return, but if so you'll need to allocate a buffer on the heap:
char *getINIfile(void)
{
char *buffer[MAX_PATH];
GetModuleFileName(NULL, buffer, MAX_PATH);
string::size_type pos = string(buffer).find_last_of( "\\/" );
string path = string(buffer).substr( 0, pos) + "\\setup.ini";
char *ini_local = new[path.size()];
strncpy(ini_local, path.c_str(), path.size());
printf(ini_local); // so far output OK!
return ini_local;
}
But this is a really awful mix of standard C strings and std::string: just using string to manipulate the path and passing around char* everywhere else.
Using only standard C, replacing find_last_of with strrchr - note the lack of error handling:
char *getINIfile(void)
{
char *buffer = new[MAX_PATH];
char *pos = NULL;
char *ini_local = NULL;
GetModuleFileName(NULL, buffer, MAX_PATH);
pos = strrchr(buffer, "\\/");
// check for and handle pos == NULL
buffer[pos] = '\0';
strncat(buffer, "\\setup.ini", MAX_PATH - strlen(buffer));
printf(buffer);
return buffer;
}
The function is returning a pointer to a local variable, which goes out of scope, leaving you with a dangling pointer. Why not just return an std::string by value?
std::string getINIfile() {
....
return path;
}
Then you can just use the string's underlying char* on the caller side:
const std::string s = getINIfile();
const char* c = s.c_str();
I just found an elusive bug in a program and it turned out to be because with optimization enabled, in something like the following sometimes the std::string is destroyed before processDocument() got the text out of it:
#include <stdio.h>
#include <spawn.h>
#include <string>
static void processDocument(const char* text) {
const char* const argv[] = {
"echo",
text,
NULL,
};
pid_t p;
posix_spawnp(&p, "echo", NULL, NULL, (char**) argv, environ);
}
static int mark = 'A';
static void createDocument() {
const char* vc;
std::string v = "ABCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK42";
++mark;
v[0] = mark;
vc = v.c_str();
processDocument(vc);
}
int main() {
createDocument();
createDocument();
return(0);
}
How do I safely convert a std::string to a char* for use in execvp, posix_spawnp etc ?
I found out why it really was (here the actual minimal testcase):
std::string resultString;
const char* nodeText;
const char* altText;
resultString = "......whatever1.";
nodeText = resultString.c_str();
resultString = ".....whatever2..";
altText = resultString.c_str();
printf("%s\n", nodeText); // garbage
Bad idea.