Coverage Report

Created: 2025-11-17 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tor/src/lib/encoding/cstring.c
Line
Count
Source
1
/* Copyright (c) 2001 Matej Pfajfar.
2
 * Copyright (c) 2001-2004, Roger Dingledine.
3
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4
 * Copyright (c) 2007-2021, The Tor Project, Inc. */
5
/* See LICENSE for licensing information */
6
7
/**
8
 * \file cstring.c
9
 *
10
 * \brief Decode data that has been written as a C literal.
11
 **/
12
13
#include "lib/encoding/cstring.h"
14
#include "lib/log/log.h"
15
#include "lib/log/util_bug.h"
16
#include "lib/malloc/malloc.h"
17
#include "lib/string/compat_ctype.h"
18
19
#include <string.h>
20
21
52.4M
#define TOR_ISODIGIT(c) ('0' <= (c) && (c) <= '7')
22
23
/** Given a c-style double-quoted escaped string in <b>s</b>, extract and
24
 * decode its contents into a newly allocated string.  On success, assign this
25
 * string to *<b>result</b>, assign its length to <b>size_out</b> (if
26
 * provided), and return a pointer to the position in <b>s</b> immediately
27
 * after the string.  On failure, return NULL.
28
 */
29
const char *
30
unescape_string(const char *s, char **result, size_t *size_out)
31
5.24M
{
32
5.24M
  const char *cp;
33
5.24M
  char *out;
34
5.24M
  if (s[0] != '\"')
35
1
    return NULL;
36
5.24M
  cp = s+1;
37
19.7M
  while (1) {
38
19.7M
    switch (*cp) {
39
33
      case '\0':
40
34
      case '\n':
41
34
        return NULL;
42
5.24M
      case '\"':
43
5.24M
        goto end_of_loop;
44
10.4M
      case '\\':
45
10.4M
        if (cp[1] == 'x' || cp[1] == 'X') {
46
7.54k
          if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3])))
47
17
            return NULL;
48
7.52k
          cp += 4;
49
10.4M
        } else if (TOR_ISODIGIT(cp[1])) {
50
10.4M
          cp += 2;
51
10.4M
          if (TOR_ISODIGIT(*cp)) ++cp;
52
10.4M
          if (TOR_ISODIGIT(*cp)) ++cp;
53
10.4M
        } else if (cp[1] == 'n' || cp[1] == 'r' || cp[1] == 't' || cp[1] == '"'
54
1.57k
                   || cp[1] == '\\' || cp[1] == '\'') {
55
1.57k
          cp += 2;
56
1.57k
        } else {
57
41
          return NULL;
58
41
        }
59
10.4M
        break;
60
10.4M
      default:
61
3.96M
        ++cp;
62
3.96M
        break;
63
19.7M
    }
64
19.7M
  }
65
5.24M
 end_of_loop:
66
5.24M
  out = *result = tor_malloc(cp-s + 1);
67
5.24M
  cp = s+1;
68
18.6M
  while (1) {
69
18.6M
    switch (*cp)
70
18.6M
      {
71
5.24M
      case '\"':
72
5.24M
        *out = '\0';
73
5.24M
        if (size_out) *size_out = out - *result;
74
5.24M
        return cp+1;
75
76
        /* LCOV_EXCL_START -- we caught this in parse_config_from_line. */
77
0
      case '\0':
78
0
        tor_fragile_assert();
79
0
        tor_free(*result);
80
0
        return NULL;
81
        /* LCOV_EXCL_STOP */
82
10.4M
      case '\\':
83
10.4M
        switch (cp[1])
84
10.4M
          {
85
194
          case 'n': *out++ = '\n'; cp += 2; break;
86
261
          case 'r': *out++ = '\r'; cp += 2; break;
87
258
          case 't': *out++ = '\t'; cp += 2; break;
88
6.96k
          case 'x': case 'X':
89
6.96k
            {
90
6.96k
              int x1, x2;
91
92
6.96k
              x1 = hex_decode_digit(cp[2]);
93
6.96k
              x2 = hex_decode_digit(cp[3]);
94
6.96k
              if (x1 == -1 || x2 == -1) {
95
                /* LCOV_EXCL_START */
96
                /* we caught this above in the initial loop. */
97
0
                tor_assert_nonfatal_unreached();
98
0
                tor_free(*result);
99
0
                return NULL;
100
                /* LCOV_EXCL_STOP */
101
0
              }
102
103
6.96k
              *out++ = ((x1<<4) + x2);
104
6.96k
              cp += 4;
105
6.96k
            }
106
0
            break;
107
10.4M
          case '0': case '1': case '2': case '3': case '4': case '5':
108
10.4M
          case '6': case '7':
109
10.4M
            {
110
10.4M
              int n = cp[1]-'0';
111
10.4M
              cp += 2;
112
10.4M
              if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
113
10.4M
              if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
114
10.4M
              if (n > 255) { tor_free(*result); return NULL; }
115
10.4M
              *out++ = (char)n;
116
10.4M
            }
117
0
            break;
118
323
          case '\'':
119
588
          case '\"':
120
860
          case '\\':
121
860
          case '\?':
122
860
            *out++ = cp[1];
123
860
            cp += 2;
124
860
            break;
125
126
            /* LCOV_EXCL_START */
127
0
          default:
128
            /* we caught this above in the initial loop. */
129
0
            tor_assert_nonfatal_unreached();
130
0
            tor_free(*result); return NULL;
131
            /* LCOV_EXCL_STOP */
132
10.4M
          }
133
10.4M
        break;
134
10.4M
      default:
135
2.91M
        *out++ = *cp++;
136
18.6M
      }
137
18.6M
  }
138
5.24M
}