this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "mmap-module.h"
3
4#include <fcntl.h>
5#include <sys/mman.h>
6#include <sys/stat.h>
7
8#include <cerrno>
9
10#include "builtins.h"
11#include "file.h"
12#include "handles.h"
13#include "module-builtins.h"
14#include "modules.h"
15#include "objects.h"
16#include "os.h"
17#include "runtime.h"
18#include "symbols.h"
19#include "thread.h"
20#include "type-builtins.h"
21
22namespace py {
23
24void FUNC(mmap, __init_module__)(Thread* thread, const Module& module,
25 View<byte> bytecode) {
26 HandleScope scope(thread);
27 Object page_size(&scope, SmallInt::fromWord(OS::pageSize()));
28 moduleAtPutById(thread, module, ID(PAGESIZE), page_size);
29
30 Object prot_exec(&scope, SmallInt::fromWord(static_cast<word>(PROT_EXEC)));
31 moduleAtPutById(thread, module, ID(PROT_EXEC), prot_exec);
32
33 Object prot_read(&scope, SmallInt::fromWord(static_cast<word>(PROT_READ)));
34 moduleAtPutById(thread, module, ID(PROT_READ), prot_read);
35
36 Object prot_write(&scope, SmallInt::fromWord(static_cast<word>(PROT_WRITE)));
37 moduleAtPutById(thread, module, ID(PROT_WRITE), prot_write);
38
39 Object map_shared(&scope, SmallInt::fromWord(static_cast<word>(MAP_SHARED)));
40 moduleAtPutById(thread, module, ID(MAP_SHARED), map_shared);
41
42 Object map_private(&scope,
43 SmallInt::fromWord(static_cast<word>(MAP_PRIVATE)));
44 moduleAtPutById(thread, module, ID(MAP_PRIVATE), map_private);
45
46 executeFrozenModule(thread, module, bytecode);
47}
48
49RawObject FUNC(mmap, _mmap_new)(Thread* thread, Arguments args) {
50 HandleScope scope(thread);
51 Runtime* runtime = thread->runtime();
52 word fd = intUnderlying(args.get(1)).asWord();
53 word length = intUnderlying(args.get(2)).asWord();
54 word flags = intUnderlying(args.get(3)).asWord();
55 word prot = intUnderlying(args.get(4)).asWord();
56 word offset = intUnderlying(args.get(5)).asWord();
57
58 if (fd != -1) {
59 struct stat sbuf;
60 if (::fstat(fd, &sbuf) == 0 && S_ISREG(sbuf.st_mode)) {
61 if (length == 0) {
62 if (sbuf.st_size == 0) {
63 return thread->raiseWithFmt(LayoutId::kValueError,
64 "cannot mmap an empty file");
65 }
66 if (offset >= sbuf.st_size) {
67 return thread->raiseWithFmt(LayoutId::kValueError,
68 "mmap offset is greater than file size");
69 }
70 length = sbuf.st_size - offset;
71 } else if (offset > sbuf.st_size || sbuf.st_size - offset < length) {
72 return thread->raiseWithFmt(LayoutId::kValueError,
73 "mmap length is greater than file size");
74 }
75 }
76 fd = ::fcntl(fd, F_DUPFD_CLOEXEC, 0);
77 if (fd < 0) {
78 return thread->raiseOSErrorFromErrno(errno);
79 }
80 } else {
81 flags |= MAP_ANONYMOUS;
82 }
83
84 void* address = ::mmap(nullptr, length, prot, flags, fd, offset);
85 if (address == MAP_FAILED) {
86 return thread->raiseOSErrorFromErrno(errno);
87 }
88
89 Type type(&scope, args.get(0));
90 Layout layout(&scope, type.instanceLayout());
91 Mmap result(&scope, runtime->newInstance(layout));
92 result.setAccess(0);
93 if ((prot & PROT_READ) != 0) {
94 result.setReadable();
95 }
96 if ((prot & PROT_WRITE) != 0) {
97 result.setWritable();
98 }
99 if ((flags == MAP_PRIVATE) != 0) {
100 result.setCopyOnWrite();
101 }
102 result.setData(runtime->newPointer(address, length));
103 result.setFd(runtime->newInt(fd));
104 return *result;
105}
106
107RawObject METH(mmap, close)(Thread* thread, Arguments args) {
108 HandleScope scope(thread);
109 Object self(&scope, args.get(0));
110 if (!thread->runtime()->isInstanceOfMmap(*self)) {
111 return thread->raiseRequiresType(self, ID(mmap));
112 }
113 Mmap mmap_obj(&scope, *self);
114 // TODO(T64468928): Take into account exporters
115 word fd = Int::cast(mmap_obj.fd()).asWord();
116 if (fd >= 0) {
117 int close_result = File::close(fd);
118 if (close_result < 0) return thread->raiseOSErrorFromErrno(-close_result);
119 }
120 mmap_obj.setFd(SmallInt::fromWord(-1));
121 Pointer pointer(&scope, mmap_obj.data());
122 void* address = pointer.cptr();
123 if (address != nullptr) {
124 OS::freeMemory(static_cast<byte*>(address), pointer.length());
125 mmap_obj.setData(NoneType::object());
126 }
127 return NoneType::object();
128}
129
130static const BuiltinAttribute kMmapAttributes[] = {
131 {ID(_mmap__access), RawMmap::kAccessOffset, AttributeFlags::kHidden},
132 {ID(_mmap__data), RawMmap::kDataOffset, AttributeFlags::kHidden},
133 {ID(_mmap__fd), RawMmap::kFdOffset, AttributeFlags::kHidden},
134};
135
136void initializeMmapType(Thread* thread) {
137 addBuiltinType(thread, ID(mmap), LayoutId::kMmap,
138 /*superclass_id=*/LayoutId::kObject, kMmapAttributes,
139 Mmap::kSize, /*basetype=*/true);
140}
141
142} // namespace py