fread()读取部分HTML文件报错(errno=14) 如何修复?
I'm trying to read files using the following C code:
Main code snippet:
#define RESPONSE_MAX_LENGTH (1024 * 1024) // Should be 1MB char file_content[RESPONSE_MAX_LEGNTH]; memset(&file_content, 0, RESPONSE_MAX_LEGNTH); request_get_file("/User/...", file_content);
Function declaration:
int request_get_file(char* requested_file_path, char* buf) { int file_size = 0; FILE* fp = NULL; if ((fp = fopen(requested_file_path, "r+")) == NULL) { return errno; } fseek(fp, 0L, SEEK_END); file_size = (int)ftell(fp); rewind(fp); errno = 0; if (fread(buf, 1, file_size, fp) == 0) { if (!feof(fp)) { if (ferror(fp)) { printf("An error occured while reading the requested file. File size: %d\n", file_size); perror("fread()"); return errno; } } } fclose(fp); }
This code works fine for .txt files, but when reading some HTML files, I get the error message: fread(): Bad address (via perror("fread()")), with errno = 14. The error only happens with specific files. Later I renamed the problematic test.html to test.txt and the error still occurred, so I confirmed it's caused by the buffer being too small. How can I fix this?
Great catch identifying the buffer size as the root cause! Let's break down the fixes step by step, including some hidden issues in your code that might be exacerbating the problem:
1. Fix the critical typo first
Look closely at your macro and variable: you defined RESPONSE_MAX_LENGTH but used RESPONSE_MAX_LEGNTH (note the missing 'L' in "LENGTH"). This typo means your buffer is being sized to an undefined macro value, which the compiler will treat as 0 (or a garbage value depending on settings). That's a direct cause of the "Bad Address" error, since you're trying to write to a buffer of invalid size.
2. Replace static buffer with dynamic allocation
A 1MB static array on the stack can cause stack overflow in some environments, and it's inflexible for files larger than 1MB. Instead, allocate memory dynamically based on the actual file size:
#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int request_get_file(char* requested_file_path, char** buf) { long file_size = 0; // Use long to handle files larger than 2GB (32-bit int limit) FILE* fp = NULL; // Open file in read-only mode (no need for "r+" since we're only reading) if ((fp = fopen(requested_file_path, "r")) == NULL) { perror("fopen()"); return errno; } // Get file size, handle potential fseek/ftell failures if (fseek(fp, 0L, SEEK_END) != 0) { perror("fseek()"); fclose(fp); return errno; } file_size = ftell(fp); if (file_size == -1) { perror("ftell()"); fclose(fp); return errno; } rewind(fp); // Allocate buffer dynamically (+1 for null terminator if using as a string) *buf = malloc(file_size + 1); if (*buf == NULL) { perror("malloc()"); fclose(fp); return ENOMEM; } memset(*buf, 0, file_size + 1); // Read file and verify all bytes were read size_t bytes_read = fread(*buf, 1, file_size, fp); if (bytes_read != file_size) { if (ferror(fp)) { printf("Failed to read file. Expected %ld bytes, read %zu bytes\n", file_size, bytes_read); perror("fread()"); free(*buf); *buf = NULL; fclose(fp); return errno; } } fclose(fp); return file_size; // Return actual file size on success }
3. Update your main code to use dynamic allocation
int main() { char* file_content = NULL; int result = request_get_file("/User/...", &file_content); if (result > 0) { // Use file_content here (e.g., print, parse, etc.) printf("Successfully read %d bytes of file content\n", result); } else { printf("Error reading file: error code %d\n", result); } // Don't forget to free the allocated buffer to avoid memory leaks if (file_content != NULL) { free(file_content); } return 0; }
4. Additional key improvements
- Use
longfor file size:inthas a maximum limit (usually 2GB on 32-bit systems), solonglets you handle larger files without overflow. - Read-only file access: Using
"r"instead of"r+"is safer and more efficient since you don't need write permissions for reading. - Full error checking: Your original code didn't handle failures from
fseekorftell, which could lead to incorrect file size calculations. - Null terminator support: Allocating an extra byte and zeroing it ensures you can safely use string functions (like
strlen,printf) on the buffer if it contains text content.
Why you saw "Bad Address"
The error errno=14 corresponds to EFAULT, meaning the kernel detected an invalid memory address being accessed. In your case:
- The typo made your static buffer size invalid (likely
0), sofreadtried to write to memory outside the valid buffer range. - Even without the typo, if the file exceeded your 1MB static buffer,
freadwould write past the end of the array, triggering an access violation.
By switching to dynamic allocation, you ensure the buffer is always exactly the right size for the file, eliminating this error entirely.
内容的提问来源于stack exchange,提问作者j3141592653589793238

