[英]What happens if I set a value outside of the memory allocated with calloc?
[英]Why am I not able to write in the allocated memory that I created with calloc?
我正在編寫的 C 代碼有問題,但我找不到根本原因。 我想要做的是從任何目錄中讀取一個文本文件,並通過使用 calloc 分配內存(使其為 0)將所有字節放入堆中
問題是當文件超過一定大小(> = 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;
}
順便一提:
typedef const char string;
typedef signed long int fSz;
另一個線索是,我在沒有 IDE 的情況下使用 GCC 11.2.0 和以下標志(在 Makefile 中)編寫此代碼:
_compilerOptions = -O0 \
-pedantic \
-Wall \
-Wextra \
-Wdiscarded-qualifiers \
-Wwrite-strings \
-ggdb3 \
我知道代碼還不是“安全”的,但我不知道是什么導致了這個錯誤。 當我調試時,我通過打印byteFromFile一次看到每個字符,但是當我打印字節時沒有寫入任何內容。
文件大小是我擁有的唯一線索,因為該代碼適用於 1-5 KB 左右的文件,但比這更大的文件不起作用。
任何想法或我做錯了什么? :(
更新 1:
我已更新代碼如下:
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;
}
但我仍然遇到同樣的問題(我正在使用 GDB):
更新 2:
我用於測試的文件可以使用以下代碼創建:
FILE* fp = (FILE*)fopen("test.txt", "wb");
char byte = 0x0U;
for(int i = 0; i < 4095; i++)
{
(void)putc(byte, fp);
byte++;
}
fclose(fp);
我期待看到的是數組bytes 中文件的內容。 使用代碼生成我用作示例的文件,我應該看到:“\\000\\001\\002\\003\\004\\005\\006\\007\\008\\009\\010\\011\\ ...\\255\\ 000\\001\\002...”取決於調試器,GDB 以八進制打印該信息,但我是在 12 月寫的。
上傳整個代碼很復雜,因為它被分成幾個文件。 但基本上它應該是這樣的:
#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;
}
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
到目前為止,代碼才剛剛開始采取“形式”,所以它仍然很簡單。 我在一個代碼中粉碎了所有 SW 單元(僅針對這個問題),但現在它至少包含在 5 個文件中。
而且,我忘了提及我正在使用 Cygwin。 我應該改成 MinGW 嗎?
更新 3:
大家好,我已經遵循了您的一些建議,我想我已經找到了根本原因。
所以我發現當二進制文件以 0x00 開頭時,這會導致一些問題,阻止我寫入分配的內存。 例如,如果我打開一個以 0x1(或 >0x0)開頭的二進制文件,代碼似乎可以正常工作。 例如,我試圖讀取一個可執行文件,並且在短時間內似乎工作正常,但是一旦找到 0x0,它就會崩潰並且不再寫入內存:/
我正在實施(臨時)的解決方法是避免一起寫 0。 像這樣的東西:
...
while( (byteFromFile = fgetc(fileStream)) != EOF )
{
if(byteFromFile != '\0') bytes[counter++] = (char)byteFromFile;
}
...
這當然會導致問題,因為我將無法在我的二進制文件中寫入 0(或讀取它們),這不太現實。
更新 4:
大家好,“根本原因”是GBD。 如果我按照上一個答案的說明(我不能@我的朋友),“問題”不再是“問題”。
無論如何,感謝大家的時間。 我怎樣才能關閉這張票哈哈?
任何想法或我做錯了什么? :(
257
getc()
在unsigned char
范圍和EOF
返回 257 個不同的值。 保存在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;
循環的早期退出解釋了“代碼適用於大約 1-5 KB 的文件,但大於它的文件不起作用。”
尺寸
確保文件大小fileSizeInBytes + 1
不超過size_t
數學。
//add
if (fileSizeInBytes < 0 || fileSizeInBytes >= SIZE_MAX) {
fprintf(stderr, "File size trouble %lld\n", (long long) fileSizeInBytes);
exit (-1);
}
一次就夠了
重復失敗的內存分配沒有那么有用。 如果第一次失敗,以后就不太可能工作了。
// 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);
}
次要:不需要轉換,引用對象的大小
// bytes = (char*)calloc(fileSizeInBytes + 1, sizeof(char));
bytes = calloc(fileSizeInBytes + 1, sizeof *bytes);
避免混合類型
為什么代碼類型fileSizeInBytes
和i
不同?
(就目前而言,在 OP 的情況下看起來還可以, fsz
很long
)。
const fSz fileSizeInBytes = GetFileSizeInBytes(fileName);
...
//for(long i = 0; i < fileSizeInBytes; i++)
for(fSz i = 0; i < fileSizeInBytes; i++)
缺乏錯誤檢查
檢查以確保文件打開成功。
FILE* fileStream = (FILE*)fopen(fileName, "rb");
// add
if (fileStream == NULL) {
fprintf(stderr, "Fail to open <%s>\n", fileName);
exit (-1);
}
缺少空字符
(當使用malloc()
。)
當然ReadBytesFromFile()
應該返回一個指向string的指針。 到目前為止,它並沒有因為bytes[]
缺少某個空字符。
char* ReadBytesFromFile(string fileName[]) {
...
bytes[counter] = '\0'; // add
return bytes;
}
演員表
OP 代碼在各個地方都使用了 casts ()
。 IMO,所有這些都是不必要的或可能隱藏的問題。 它們都需要拆除或返工。
也許其他一些問題也在發生
所以我發現當二進制文件以 0x00 開頭時,這會導致一些問題,阻止我寫入分配的內存。 例如,如果我打開一個以 0x1(或 >0x0)開頭的二進制文件,代碼似乎可以正常工作。 例如,我試圖讀取一個可執行文件,並且在短時間內似乎工作正常,但是一旦發現 0x0,它就會崩潰並且不再寫入內存:/
事實上,您的代碼正在寫入內存就好了。 但是,您正在使用 GDB 中的print bytes
檢查它。 由於bytes
具有char *
類型,GDB 的默認值是將其打印為字符串,這意味着它只打印字符,直到遇到空字節。 如果第一個字節為空,則 GDB 將其打印為空字符串並忽略之后的任何內容。
要指定要轉儲的字節數,可以改用x
命令。 例如, x/17xb bytes
將以十六進制轉儲前 17 個字節; 那么您應該會看到文件中的實際字節數。 如果您想將它們視為可打印字符,則可以執行x/17cb
。 使用help x
獲取更多信息。
(作為一個單獨的問題,如果某個其他進程應該在您的stat
調用后將更多字節寫入文件,那么您的fgetc
循環將讀取太多字符並溢出您的緩沖區。您應該跟蹤您實際存儲了多少字節,並且當緩沖區滿時退出或擴大緩沖區。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.