@@ -150,10 +150,10 @@ void MunmapSegment(void* context, void* data, size_t size) {
150150}
151151} // namespace
152152
153- Result<FreeableBuffer> MmapDataLoader::load (
154- size_t offset,
155- size_t size,
156- ET_UNUSED const DataLoader::SegmentInfo& segment_info ) const {
153+ /* *
154+ * Validates that file read range is within bounds.
155+ */
156+ Error MmapDataLoader::validate_input ( size_t offset, size_t size ) const {
157157 ET_CHECK_OR_RETURN_ERROR (
158158 // Probably had its value moved to another instance.
159159 fd_ >= 0 ,
@@ -173,6 +173,18 @@ Result<FreeableBuffer> MmapDataLoader::load(
173173 InvalidArgument,
174174 " Offset %zu too large for off_t" ,
175175 offset);
176+ return Error::Ok;
177+ }
178+
179+ Result<FreeableBuffer> MmapDataLoader::load (
180+ size_t offset,
181+ size_t size,
182+ ET_UNUSED const DataLoader::SegmentInfo& segment_info) const {
183+ // Ensure read range is valid.
184+ auto validation_err = validate_input (offset, size);
185+ if (validation_err != Error::Ok) {
186+ return validation_err;
187+ }
176188
177189 // mmap() will fail if the size is zero.
178190 if (size == 0 ) {
@@ -267,5 +279,69 @@ Result<size_t> MmapDataLoader::size() const {
267279 return file_size_;
268280}
269281
282+ Error MmapDataLoader::load_into (
283+ size_t offset,
284+ size_t size,
285+ ET_UNUSED const SegmentInfo& segment_info,
286+ void * buffer) const {
287+ ET_CHECK_OR_RETURN_ERROR (
288+ buffer != nullptr , InvalidArgument, " Buffer is null" );
289+
290+ // Ensure read range is valid.
291+ auto err = validate_input (offset, size);
292+ if (err != Error::Ok) {
293+ return err;
294+ }
295+
296+ // Nothing to copy.
297+ if (size == 0 ) {
298+ return Error::Ok;
299+ }
300+
301+ // Find the range of pages that covers the requested region.
302+ Range range =
303+ get_overlapping_pages (static_cast <uintptr_t >(offset), size, page_size_);
304+
305+ size_t map_size = range.size ;
306+ if (range.start + map_size > file_size_) {
307+ // Clamp to the end of the file.
308+ //
309+ // The Windows implementation of mmap uses CreateFileMapping which returns
310+ // error STATUS_SECTION_TOO_BIG (0xc0000040) if we try to map past the end
311+ // of the last page of a file mapped in as read-only.
312+ map_size = file_size_ - range.start ;
313+ }
314+
315+ // Map the pages read-only. MAP_PRIVATE vs. MAP_SHARED doesn't matter since
316+ // the data is read-only, but use PRIVATE just to further avoid accidentally
317+ // modifying the file.
318+ void * pages = ::mmap (
319+ nullptr ,
320+ map_size,
321+ PROT_READ,
322+ MAP_PRIVATE,
323+ fd_,
324+ static_cast <off_t >(range.start ));
325+ ET_CHECK_OR_RETURN_ERROR (
326+ pages != MAP_FAILED,
327+ AccessFailed,
328+ " Failed to map %s: mmap(..., size=%zd, ..., fd=%d, offset=0x%zx)" ,
329+ file_name_,
330+ range.size ,
331+ fd_,
332+ range.start );
333+
334+ // Offset into mapped region.
335+ const size_t map_delta = offset - range.start ;
336+
337+ // Copy data into caller's buffer.
338+ std::memcpy (buffer, static_cast <uint8_t *>(pages) + map_delta, size);
339+
340+ // Unmap mapped region.
341+ ::munmap (pages, map_size);
342+
343+ return Error::Ok;
344+ }
345+
270346} // namespace extension
271347} // namespace executorch
0 commit comments