cpp

Coverage Report

Created: 2022-11-10 11:34

/home/andy/git/oilshell/oil/cpp/leaky_stdlib.cc
Line
Count
Source (jump to first uncovered line)
1
// leaky_stdlib.cc: Replacement for standard library modules
2
// and native/posixmodule.c
3
4
#include "leaky_stdlib.h"
5
6
#include <errno.h>
7
#include <fcntl.h>      // open
8
#include <signal.h>     // kill
9
#include <sys/stat.h>   // umask
10
#include <sys/types.h>  // umask
11
#include <sys/wait.h>   // WUNTRACED
12
#include <time.h>
13
#include <unistd.h>
14
15
#include "cpp/leaky_core_error.h"
16
#include "cpp/leaky_core_pyerror.h"
17
#include "mycpp/runtime.h"
18
19
namespace fcntl_ {
20
21
0
int fcntl(int fd, int cmd) {
22
0
  int result = ::fcntl(fd, cmd);
23
0
  if (result < 0) {
24
0
    throw Alloc<IOError>(errno);
25
0
  }
26
0
  return result;
27
0
}
28
29
0
int fcntl(int fd, int cmd, int arg) {
30
0
  int result = ::fcntl(fd, cmd, arg);
31
0
  if (result < 0) {
32
0
    throw Alloc<IOError>(errno);
33
0
  }
34
0
  return result;
35
0
}
36
37
}  // namespace fcntl_
38
39
namespace posix {
40
41
0
mode_t umask(mode_t mask) {
42
0
  return ::umask(mask);
43
0
}
44
45
0
int open(Str* path, int flags, int perms) {
46
0
  return ::open(path->data_, flags, perms);
47
0
}
48
49
0
void dup2(int oldfd, int newfd) {
50
0
  if (::dup2(oldfd, newfd) < 0) {
51
0
    throw Alloc<OSError>(errno);
52
0
  }
53
0
}
54
1
void putenv(Str* name, Str* value) {
55
1
  int overwrite = 1;
56
1
  int ret = ::setenv(name->data_, value->data_, overwrite);
57
1
  if (ret < 0) {
58
0
    throw Alloc<IOError>(errno);
59
0
  }
60
1
}
61
62
0
mylib::LineReader* fdopen(int fd, Str* c_mode) {
63
0
  FILE* f = ::fdopen(fd, c_mode->data_);
64
65
  // TODO: raise exception
66
0
  assert(f);
67
68
0
  return Alloc<mylib::CFileLineReader>(f);
69
0
}
70
71
0
void execve(Str* argv0, List<Str*>* argv, Dict<Str*, Str*>* environ) {
72
0
  int n_args = len(argv);
73
  // never deallocated
74
0
  char** _argv = static_cast<char**>(malloc((n_args + 1) * sizeof(char*)));
75
76
  // Annoying const_cast
77
  // https://stackoverflow.com/questions/190184/execv-and-const-ness
78
0
  for (int i = 0; i < n_args; ++i) {
79
0
    _argv[i] = const_cast<char*>(argv->index_(i)->data_);
80
0
  }
81
0
  _argv[n_args] = nullptr;
82
83
  // Convert environ into an array of pointers to strings of the form: "k=v".
84
0
  int n_env = len(environ);
85
0
  char** envp = static_cast<char**>(malloc((n_env + 1) * sizeof(char*)));
86
87
0
  int env_index = 0;
88
0
  for (DictIter<Str*, Str*> it(environ); !it.Done(); it.Next()) {
89
0
    Str* k = it.Key();
90
0
    Str* v = it.Value();
91
92
0
    int joined_len = len(k) + len(v) + 1;
93
0
    char* buf = static_cast<char*>(malloc(joined_len + 1));
94
0
    memcpy(buf, k->data_, len(k));
95
0
    buf[len(k)] = '=';
96
0
    memcpy(buf + len(k) + 1, v->data_, len(v));
97
0
    buf[joined_len] = '\0';
98
99
0
    envp[env_index++] = buf;
100
0
  }
101
0
  envp[n_env] = nullptr;
102
103
0
  int ret = ::execve(argv0->data_, _argv, envp);
104
0
  if (ret == -1) {
105
0
    throw Alloc<OSError>(errno);
106
0
  }
107
108
  // NOTE(Jesse): ::execve() is specified to never return on success.  If we
109
  // hit this assertion, it returned successfully (or at least something other
110
  // than -1) but should have overwritten our address space with the invoked
111
  // process'
112
0
  InvalidCodePath();
113
0
}
114
115
0
void kill(int pid, int sig) {
116
0
  if (::kill(pid, sig) != 0) {
117
0
    throw Alloc<OSError>(errno);
118
0
  }
119
0
}
120
121
}  // namespace posix
122
123
namespace time_ {
124
125
0
void tzset() {
126
0
  ::tzset();
127
0
}
128
129
1
time_t time() {
130
1
  return ::time(nullptr);
131
1
}
132
133
// NOTE(Jesse): time_t is specified to be an arithmetic type by C++. On most
134
// systems it's a 64-bit integer.  64 bits is used because 32 will overflow in
135
// 2038.  Someone on a comittee somewhere thought of that when moving to 64-bit
136
// architectures to prevent breaking ABI again; on 32-bit systems it's usually
137
// 32 bits.  Point being, using anything but the time_t typedef here could
138
// (unlikely, but possible) produce weird behavior.
139
0
time_t localtime(time_t ts) {
140
0
  tm* loc_time = ::localtime(&ts);
141
0
  time_t result = mktime(loc_time);
142
0
  return result;
143
0
}
144
145
0
Str* strftime(Str* s, time_t ts) {
146
  // TODO: may not work with leaky_containers.h
147
  // https://github.com/oilshell/oil/issues/1221
148
0
  tm* loc_time = ::localtime(&ts);
149
150
0
  const int max_len = 1024;
151
0
  Str* result = OverAllocatedStr(max_len);
152
0
  int n = strftime(result->data(), max_len, s->data_, loc_time);
153
0
  if (n == 0) {
154
    // bash silently truncates on large format string like
155
    //   printf '%(%Y)T'
156
    // Oil doesn't mask errors
157
    // No error location info, but leaving it out points reliably to 'printf'
158
0
    e_die(StrFromC("strftime() result exceeds 1024 bytes"));
159
0
  }
160
0
  result->SetObjLenFromStrLen(n);
161
0
  return result;
162
0
}
163
164
}  // namespace time_