[英]Why am I not able to write in the allocated memory that I created with calloc?
I'm having a problem with a C code that I'm making and I just can't find the root cause.我正在编写的 C 代码有问题,但我找不到根本原因。 What I'm trying to do is to read a text file from any directory and put all the bytes in the heap by allocating memory with calloc (to have it in 0s)
我想要做的是从任何目录中读取一个文本文件,并通过使用 calloc 分配内存(使其为 0)将所有字节放入堆中
The problem is that when the file is over a certain size (>=25 KB, could be less) I'm not able to write anything in the allocated memory but I can read the file!问题是当文件超过一定大小(> = 25 KB,可能会更小)时,我无法在分配的内存中写入任何内容,但我可以读取文件!
char* ReadBytesFromFile(string fileName[]) {
FILE* fileStream = (FILE*)fopen(fileName, "r");
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
char* bytes;
char byteFromFile = 0;
do
{
bytes = (char*)calloc((size_t)fileSizeInBytes + 1, sizeof(char));
} while (bytes == NULL);
for(long i = 0; i < fileSizeInBytes; i++)
{
byteFromFile = (char)getc(fileStream);
if (byteFromFile == EOF) break;
bytes[i] = byteFromFile;
}
fclose(fileStream);
free(fileStream);
return bytes;
}
By the way:顺便一提:
typedef const char string;
typedef signed long int fSz;
Another clue is that I'm writing this without an IDE using GCC 11.2.0 with the following flags (in a Makefile):另一个线索是,我在没有 IDE 的情况下使用 GCC 11.2.0 和以下标志(在 Makefile 中)编写此代码:
_compilerOptions = -O0 \
-pedantic \
-Wall \
-Wextra \
-Wdiscarded-qualifiers \
-Wwrite-strings \
-ggdb3 \
I know the code is not "secure" yet, but I don't know what's causing this error.我知道代码还不是“安全”的,但我不知道是什么导致了这个错误。 When I'm debugging I'm seeing each character at a time by printing byteFromFile but when I print bytes nothing is being written.
当我调试时,我通过打印byteFromFile一次看到每个字符,但是当我打印字节时没有写入任何内容。
The file size is the only clue that I have, because the code works for files around 1-5 KB but bigger than that doesn't work.文件大小是我拥有的唯一线索,因为该代码适用于 1-5 KB 左右的文件,但比这更大的文件不起作用。
Any ideas or what am I doing wrong?任何想法或我做错了什么? :(
:(
Update 1:更新 1:
I have update the code as follows:我已更新代码如下:
char* ReadBytesFromFile(string fileName[])
{
FILE* fileStream = (FILE*)fopen(fileName, "rb");
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
fSz counter = 0;
char* bytes;
int byteFromFile = 0;
do
{
bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
} while (bytes == NULL);
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
bytes[counter++] = (char)byteFromFile;
}
fclose(fileStream);
free(fileStream);
return bytes;
}
but I'm still having the same issue (I'm using GDB):但我仍然遇到同样的问题(我正在使用 GDB):
Update 2:更新 2:
The file that I'm using for test, can be created with the following code:我用于测试的文件可以使用以下代码创建:
FILE* fp = (FILE*)fopen("test.txt", "wb");
char byte = 0x0U;
for(int i = 0; i < 4095; i++)
{
(void)putc(byte, fp);
byte++;
}
fclose(fp);
What I'm expecting to see, is the content of the file in the array bytes .我期待看到的是数组bytes 中文件的内容。 Using the code to generate the file I'm using as an example I should see: "\\000\\001\\002\\003\\004\\005\\006\\007\\008\\009\\010\\011\\ ...\\255\\000\\001\\002..." depending on the debugger, GDB prints that information in octal but I wrote it in dec.
使用代码生成我用作示例的文件,我应该看到:“\\000\\001\\002\\003\\004\\005\\006\\007\\008\\009\\010\\011\\ ...\\255\\ 000\\001\\002...”取决于调试器,GDB 以八进制打印该信息,但我是在 12 月写的。
It's complicated to upload the whole code, because is split in several files.上传整个代码很复杂,因为它被分成几个文件。 But basically it should be something like this:
但基本上它应该是这样的:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "fileRW.h"
/* ****************************** Typedefs ****************************** */
// Char/strings
typedef unsigned char uchar;
typedef const char string;
// Numerical
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long uint64;
typedef signed char BYTE;
typedef signed short WORD;
typedef signed int DWORD;
typedef signed int long QWORD;
typedef unsigned char uBYTE;
typedef unsigned short uWORD;
typedef unsigned int uDWORD;
typedef unsigned int long uQWORD;
typedef signed long int fSz;
/* ****************************** Function Prototypes ****************************** */
off_t GetFileSizeInBytes(string fileName[]);
char* ReadBytesFromFile(string fileName[]);
void ConvertByteToHexFromFile(uBYTE* inputChar);
int main(int argc, char* argv[])
{
if(argc > 1)
{
for(int i = 1; i < argc; i++)
{
(void)ReadBytesFromFile(argv[i]);
}
}
return 0;
}
off_t GetFileSizeInBytes(const char fileName[])
{
struct stat st;
if(stat(fileName, &st) == 0)
{
return st.st_size;
}
else
{
return -1;
}
}
char* ReadBytesFromFile(string fileName[])
{
FILE* fileStream = (FILE*)fopen(fileName, "rb");
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName) + 1;
fSz counter = 0;
char* bytes;
int byteFromFile = 0;
do
{
bytes = (char*)malloc(fileSizeInBytes * sizeof(char));
} while (bytes == NULL);
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
bytes[counter++] = (char)byteFromFile;
}
//(void)fread(bytes, fileSizeInBytes, 1, fileStream);
fclose(fileStream);
return bytes;
}
And the output from GCC -v is: GCC -v 的输出是:
gcc main.c fileRW.c -c -std=c11 -O0 -pedantic -Wall -Wextra -Wdiscarded-qualifiers -Wwrite-strings -ggdb3 -v -D _ENABLE_DEBUG_CODE_=0
Using built-in specs.
COLLECT_GCC=gcc
Target: x86_64-pc-cygwin
Configured with: /mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-11.2.0/configure --srcdir=/mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-11.2.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --with-gcc-major-version-only --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with-tune=generic --disable-bootstrap --enable-languages=c,c++,fortran,lto,objc,obj-c++,jit --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable-libquadmath --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.2.0 (GCC)
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/cc1.exe -quiet -v -dD -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api -D _ENABLE_DEBUG_CODE_=0 main.c -quiet -dumpbase main.c -dumpbase-ext .c -mtune=generic -march=x86-64 -ggdb3 -O0 -Wpedantic -Wall -Wextra -Wdiscarded-qualifiers -Wwrite-strings -std=c11 -version -o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/include"
ignoring duplicate directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-cygwin/11/include
/usr/include
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api
End of search list.
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: befd73bee7080c4d72157ef5c760fe84
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/as.exe -v --gdwarf-5 -o main.o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU assembler version 2.37 (x86_64-pc-cygwin) using BFD version (GNU Binutils) 2.37
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/cc1.exe -quiet -v -dD -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api -idirafter /usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api -D _ENABLE_DEBUG_CODE_=0 fileRW.c -quiet -dumpbase fileRW.c -dumpbase-ext .c -mtune=generic -march=x86-64 -ggdb3 -O0 -Wpedantic -Wall -Wextra -Wdiscarded-qualifiers -Wwrite-strings -std=c11 -version -o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/include"
ignoring duplicate directory "/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/../../include/w32api"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-cygwin/11/include
/usr/include
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/../include/w32api
End of search list.
GNU C11 (GCC) version 11.2.0 (x86_64-pc-cygwin)
compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: befd73bee7080c4d72157ef5c760fe84
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/as.exe -v --gdwarf-5 -o fileRW.o /cygdrive/c/Users/Daniel/AppData/Local/Temp/ccIWuk1n.s
GNU assembler version 2.37 (x86_64-pc-cygwin) using BFD version (GNU Binutils) 2.37
COMPILER_PATH=/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/:/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/
LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-cygwin/11/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/../lib/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/lib/:/usr/lib/gcc/x86_64-pc-cygwin/11/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-c' '-std=c11' '-O0' '-Wpedantic' '-Wall' '-Wextra' '-Wdiscarded-qualifiers' '-Wwrite-strings' '-ggdb3' '-v' '-D' '_ENABLE_DEBUG_CODE_=0' '-mtune=generic' '-march=x86-64'
windres icon.rs icon.o
gcc main.o fileRW.o icon.o -o code.exe
So far, the code is just starting to take "form" so it's still quite simple.到目前为止,代码才刚刚开始采取“形式”,所以它仍然很简单。 I smashed all the SW units in a single code (just for this question), but now it's in at least 5 files.
我在一个代码中粉碎了所有 SW 单元(仅针对这个问题),但现在它至少包含在 5 个文件中。
And also, I forgot to mention that I'm using Cygwin.而且,我忘了提及我正在使用 Cygwin。 Should I change to MinGW?
我应该改成 MinGW 吗?
Update 3:更新 3:
Hello everyone, I have followed some of your recommendations and I think I have found the root cause.大家好,我已经遵循了您的一些建议,我想我已经找到了根本原因。
So what I have found is that when a binary file starts with 0x00, this is causing some issue that prevents me to write in my allocated memory.所以我发现当二进制文件以 0x00 开头时,这会导致一些问题,阻止我写入分配的内存。 If for example I open a binary file that starts with 0x1 (or >0x0) the code seems to work kind of OK.
例如,如果我打开一个以 0x1(或 >0x0)开头的二进制文件,代码似乎可以正常工作。 I've trying to read an executable file for example and for a short period of time seems to be working OK, but as soon as it finds a 0x0 it crashes and it no longer writes to the memory :/
例如,我试图读取一个可执行文件,并且在短时间内似乎工作正常,但是一旦找到 0x0,它就会崩溃并且不再写入内存:/
The workaround that I'm implementing (temporarily) is to avoid writing 0s all together.我正在实施(临时)的解决方法是避免一起写 0。 Something like this:
像这样的东西:
...
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
if(byteFromFile != '\0') bytes[counter++] = (char)byteFromFile;
}
...
This of course will cause a problem, because I will not be able to write 0s (or read them) in my binary files, and that's not very realistic.这当然会导致问题,因为我将无法在我的二进制文件中写入 0(或读取它们),这不太现实。
Update 4:更新 4:
Hello everyone, the "root cause" is the GBD.大家好,“根本原因”是GBD。 If I follow the instructions from the last answer (I can't @ my friend), the "issue" is no longer an "issue".
如果我按照上一个答案的说明(我不能@我的朋友),“问题”不再是“问题”。
Anyway, thanks everyone for your time.无论如何,感谢大家的时间。 How can I close this ticket lol?
我怎样才能关闭这张票哈哈?
Any ideas or what am I doing wrong?
任何想法或我做错了什么? :(
:(
257 257
getc()
returns 257 different values in the unsigned char
range and EOF
. getc()
在unsigned char
范围和EOF
返回 257 个不同的值。 Saving in a char
loses information and can cause a valid input byte to be misinterpreted as an EOF
signal (when char
is signed ) or byteFromFile == EOF
never to be true (when char
is unsigned ).保存在
char
会丢失信息,并可能导致有效的输入字节被误解为EOF
信号(当char
为signed 时)或byteFromFile == EOF
永远不会为真(当char
为unsigned 时)。
// char byteFromFile = 0;
int byteFromFile = 0;
...
// byteFromFile = (char)getc(fileStream);
byteFromFile = getc(fileStream);
if (byteFromFile == EOF) break;
An early exit of the loop explains "code works for files around 1-5 KB but bigger than that doesn't work."循环的早期退出解释了“代码适用于大约 1-5 KB 的文件,但大于它的文件不起作用。”
Size尺寸
Be sure the file size fileSizeInBytes + 1
does not exceed size_t
math.确保文件大小
fileSizeInBytes + 1
不超过size_t
数学。
//add
if (fileSizeInBytes < 0 || fileSizeInBytes >= SIZE_MAX) {
fprintf(stderr, "File size trouble %lld\n", (long long) fileSizeInBytes);
exit (-1);
}
Once is enough一次就够了
Repeating a failed memory allocation is not that useful.重复失败的内存分配没有那么有用。 Very unlikely to work later if it fails the first time.
如果第一次失败,以后就不太可能工作了。
// do {
// bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
// } while (bytes == NULL);
bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
if (bytes == NULL) {
fprintf(stderr, "Out of memory\n");
exit (-1);
}
Minor: Cast not needed, size to referenced object次要:不需要转换,引用对象的大小
// bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
bytes = calloc(fileSizeInBytes + 1, sizeof *bytes);
Avoid mixing types避免混合类型
Why code types fileSizeInBytes
and i
differently?为什么代码类型
fileSizeInBytes
和i
不同?
(Looks OK in OP's case as for now , fsz
is long
). (就目前而言,在 OP 的情况下看起来还可以,
fsz
很long
)。
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
...
//for(long i = 0; i < fileSizeInBytes; i++)
for(fSz i = 0; i < fileSizeInBytes; i++)
Lacking error check缺乏错误检查
Check to make sure file open was successful.检查以确保文件打开成功。
FILE* fileStream = (FILE*)fopen(fileName, "rb");
// add
if (fileStream == NULL) {
fprintf(stderr, "Fail to open <%s>\n", fileName);
exit (-1);
}
Missing null character缺少空字符
(When malloc()
is used.) (当使用
malloc()
。)
Certainly ReadBytesFromFile()
should return a pointer to a string .当然
ReadBytesFromFile()
应该返回一个指向string的指针。 So far it does not as bytes[]
lacks a certain null character .到目前为止,它并没有因为
bytes[]
缺少某个空字符。
char* ReadBytesFromFile(string fileName[]) {
...
bytes[counter] = '\0'; // add
return bytes;
}
Casts演员表
OP code is using casts ()
in various places. OP 代码在各个地方都使用了 casts
()
。 IMO, all of them are unnecessary or potentially hiding issues. IMO,所有这些都是不必要的或可能隐藏的问题。 They all need removal or re-work.
它们都需要拆除或返工。
Perhaps some other issue is also occurring也许其他一些问题也在发生
So what I have found is that when a binary file starts with 0x00, this is causing some issue that prevents me to write in my allocated memory.
所以我发现当二进制文件以 0x00 开头时,这会导致一些问题,阻止我写入分配的内存。 If for example I open a binary file that starts with 0x1 (or >0x0) the code seems to work kind of OK.
例如,如果我打开一个以 0x1(或 >0x0)开头的二进制文件,代码似乎可以正常工作。 I've trying to read an executable file for example and for a short period of time seems to be working OK, but as soon as it finds a 0x0 it crashed and it no longer writes to the memory :/
例如,我试图读取一个可执行文件,并且在短时间内似乎工作正常,但是一旦发现 0x0,它就会崩溃并且不再写入内存:/
In fact, your code is writing to memory just fine.事实上,您的代码正在写入内存就好了。 However, you are inspecting it with
print bytes
in GDB.但是,您正在使用 GDB 中的
print bytes
检查它。 Since bytes
has type char *
, GDB's default is to print it as a string, which means it only prints characters until a null byte is encountered.由于
bytes
具有char *
类型,GDB 的默认值是将其打印为字符串,这意味着它只打印字符,直到遇到空字节。 If the very first byte is null, then GDB prints it as an empty string and ignores anything after that.如果第一个字节为空,则 GDB 将其打印为空字符串并忽略之后的任何内容。
To specify how many bytes to dump, you can use the x
command instead.要指定要转储的字节数,可以改用
x
命令。 For instance, x/17xb bytes
will dump the first 17 bytes in hexadecimal;例如,
x/17xb bytes
将以十六进制转储前 17 个字节; then you should see the actual bytes from your file.那么您应该会看到文件中的实际字节数。 If you want to see them as printable characters instead, you can do
x/17cb
.如果您想将它们视为可打印字符,则可以执行
x/17cb
。 Use help x
for more information.使用
help x
获取更多信息。
(As a separate issue, if some other process should write more bytes to the file after your stat
call, then your fgetc
loop will read too many characters and overrun your buffer. You should keep track of how many bytes you have actually stored, and either quit or enlarge the buffer when it gets full.) (作为一个单独的问题,如果某个其他进程应该在您的
stat
调用后将更多字节写入文件,那么您的fgetc
循环将读取太多字符并溢出您的缓冲区。您应该跟踪您实际存储了多少字节,并且当缓冲区满时退出或扩大缓冲区。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.