<commit_before>#ifndef _RPR_0521RS_CPP
#define _RPR_0521RS_CPP

//RPR_0521RS register map
#define RPR_0521RS_REG_SYSTEM_CONTROL                 0x40
#define RPR_0521RS_REG_MODE_CONTROL                   0x41
#define RPR_0521RS_REG_ALS_PS_CONTROL                 0x42
#define RPR_0521RS_REG_PS_CONTROL                     0x43
#define RPR_0521RS_REG_PS_DATA_LSB                    0x44
#define RPR_0521RS_REG_PS_DATA_MSB                    0x45
#define RPR_0521RS_REG_ALS_DATA0_LSB                  0x46
#define RPR_0521RS_REG_ALS_DATA0_MSB                  0x47
#define RPR_0521RS_REG_ALS_DATA1_LSB                  0x48
#define RPR_0521RS_REG_ALS_DATA1_MSB                  0x49
#define RPR_0521RS_REG_INTERRUPT                      0x4A
#define RPR_0521RS_REG_PS_TH_LSB                      0x4B
#define RPR_0521RS_REG_PS_TH_MSB                      0x4C
#define RPR_0521RS_REG_PS_TL_LSB                      0x4D
#define RPR_0521RS_REG_PS_TL_MSB                      0x4E
#define RPR_0521RS_REG_ALS_DATA0_TH_LSB               0x4F
#define RPR_0521RS_REG_ALS_DATA0_TH_MSB               0x50
#define RPR_0521RS_REG_ALS_DATA0_TL_LSB               0x51
#define RPR_0521RS_REG_ALS_DATA0_TL_MSB               0x52
#define RPR_0521RS_REG_PS_OFFSET_LSB                  0x53
#define RPR_0521RS_REG_PS_OFFSET_MSB                  0x54
#define RPR_0521RS_REG_MANUFACT_ID                    0x92

//RPR_0521RS default values
#define RPR_0521RS_DEVICE_ADDRESS                     0x38
#define RPR_0521RS_PART_ID                            0x0A
#define RPR_0521RS_MANUFACT_ID                        0xE0

//RPR_0521RS settings
//RPR_0521RS_REG_MODE_CONTROL                                         MSB   LSB   DESCRIPTION
#define RPR_0521RS_ALS_OFF                            0b00000000  //  7     7     ambient light sensor (ALS) on standby
#define RPR_0521RS_ALS_ON                             0b10000000  //  7     7     ambient light sensor (ALS) enabled
#define RPR_0521RS_PS_OFF                             0b00000000  //  6     6     proximity sensor (PS) on standby
#define RPR_0521RS_PS_ON                              0b01000000  //  6     6     proximity sensor (PS) enabled
#define RPR_0521RS_PS_PULSE_200_US                    0b00000000  //  5     5     PS pulse width: 200 us (typical)
#define RPR_0521RS_PS_PULSE_330_US                    0b00100000  //  5     5                     330 us (typical)
#define RPR_0521RS_PS_NORMAL                          0b00000000  //  4     4     normal PS operating mode
#define RPR_0521RS_PS_DOUBLE                          0b00010000  //  4     4     double measurement PS operating mode
#define RPR_0521RS_MEAS_TIME_STBY_STBY                0b00000000  //  3     0     measurement time: ALS standby,  PS standby
#define RPR_0521RS_MEAS_TIME_STBY_10_MS               0b00000001  //  3     0                       ALS standby,  PS 10 ms
#define RPR_0521RS_MEAS_TIME_STBY_40_MS               0b00000010  //  3     0                       ALS standby,  PS 40 ms
#define RPR_0521RS_MEAS_TIME_STBY_100_MS              0b00000011  //  3     0                       ALS standby,  PS 100 ms
#define RPR_0521RS_MEAS_TIME_STBY_400_MS              0b00000100  //  3     0                       ALS standby,  PS 400 ms
#define RPR_0521RS_MEAS_TIME_100_MS_50_MS             0b00000101  //  3     0                       ALS 100 ms,   PS 50 ms
#define RPR_0521RS_MEAS_TIME_100_MS_100_MS            0b00000110  //  3     0                       ALS 100 ms,   PS 100 ms
#define RPR_0521RS_MEAS_TIME_100_MS_400_MS            0b00000111  //  3     0                       ALS 100 ms,   PS 400 ms
#define RPR_0521RS_MEAS_TIME_400_MS_50_MS             0b00001000  //  3     0                       ALS 400 ms,   PS 50 ms
#define RPR_0521RS_MEAS_TIME_400_MS_100_MS            0b00001001  //  3     0                       ALS 400 ms,   PS 100 ms
#define RPR_0521RS_MEAS_TIME_400_MS_STBY              0b00001010  //  3     0                       ALS 400 ms,   PS standby
#define RPR_0521RS_MEAS_TIME_400_MS_400_MS            0b00001011  //  3     0                       ALS 400 ms,   PS 400 ms
#define RPR_0521RS_MEAS_TIME_50_MS_50_MS              0b00001100  //  3     0                       ALS 50 ms,   PS 50 ms
//RPR_0521RS_REG_ALS_PS_CONTROL
#define RPR_0521RS_ALS_DATA0_GAIN_1                   0b00000000  //  5     4     ALS DATA0 gain: x1
#define RPR_0521RS_ALS_DATA0_GAIN_2                   0b00010000  //  5     4                     x2
#define RPR_0521RS_ALS_DATA0_GAIN_64                  0b00100000  //  5     4                     x64
#define RPR_0521RS_ALS_DATA0_GAIN_128                 0b00110000  //  5     4                     x128
#define RPR_0521RS_ALS_DATA1_GAIN_1                   0b00000000  //  3     2     ALS DATA1 gain: x1
#define RPR_0521RS_ALS_DATA1_GAIN_2                   0b00000100  //  3     2                     x2
#define RPR_0521RS_ALS_DATA1_GAIN_64                  0b00001000  //  3     2                     x64
#define RPR_0521RS_ALS_DATA1_GAIN_128                 0b00001100  //  3     2                     x128
#define RPR_0521RS_LED_CURRENT_25_MA                  0b00000000  //  1     0     LED current:  25 mA
#define RPR_0521RS_LED_CURRENT_50_MA                  0b00000001  //  1     0                   50 mA
#define RPR_0521RS_LED_CURRENT_100_MA                 0b00000010  //  1     0                   100 mA
#define RPR_0521RS_LED_CURRENT_200_MA                 0b00000011  //  1     0                   200 mA
//RPR_0521RS_REG_PS_CONTROL
#define RPR_0521RS_PS_GAIN_1                          0b00000000  //  5     4     PS gain:  x1
#define RPR_0521RS_PS_GAIN_2                          0b00010000  //  5     4               x2
#define RPR_0521RS_PS_GAIN_4                          0b00100000  //  5     4               x4

class RPR_0521RS {
  public:
    //Measurement variables
    uint16_t ps = 0; //proximity value
    float als = 0; //ambient light value in lx

    //Default constructor
    RPR_0521RS(uint8_t address = RPR_0521RS_DEVICE_ADDRESS) {
      _address = address;
    }

    //Initialization function
    uint8_t init(uint8_t measurementTime = RPR_0521RS_MEAS_TIME_100_MS_100_MS, uint8_t ledCurrent = RPR_0521RS_LED_CURRENT_100_MA) {
      //check manufacturer and part ID
      if((_utils.getRegValue(_address, RPR_0521RS_REG_SYSTEM_CONTROL, 5, 0) != RPR_0521RS_PART_ID) || (_utils.getRegValue(_address, RPR_0521RS_REG_MANUFACT_ID) != RPR_0521RS_MANUFACT_ID)) {
        //if the IDs do not match cancel initialization
        return(1);
      }

      //set control registers according to datasheet and user settings
      _utils.setRegValue(_address, RPR_0521RS_REG_ALS_PS_CONTROL, RPR_0521RS_ALS_DATA0_GAIN_1 | RPR_0521RS_ALS_DATA1_GAIN_1 | ledCurrent);
      _utils.setRegValue(_address, RPR_0521RS_REG_PS_CONTROL, RPR_0521RS_PS_GAIN_1, 5, 4);
      _utils.setRegValue(_address, RPR_0521RS_REG_MODE_CONTROL, RPR_0521RS_ALS_ON | RPR_0521RS_PS_ON | measurementTime);

      //TODO: implement gain and measurement time selection
      //gain and measurement time arrays
      uint8_t alsGainTable[4] = {1, 2, 64, 128};
      uint8_t psGainTable[3] = {1, 2, 4};
      uint16_t alsMeasureTimeTable[13] = {0, 0, 0, 0, 0, 100, 100, 100, 400, 400, 400, 400, 50};
      uint16_t psMeasureTimeTable[13] = {0, 10, 40, 100, 400, 50, 100, 400, 50, 100, 0, 400, 50};

      //set gain and measurement time
      _alsData0Gain = alsGainTable[0];
      _alsData1Gain = alsGainTable[0];
      _alsMeasurementTime = alsMeasureTimeTable[measurementTime];

      return(0);
    }

    //Measurement function
    uint8_t measure(void) {
      //TODO: implement interrupt

      //ambient light measurement
      uint16_t rawValue[2];
      float data0, data1, data1_0;

      //read raw 2-byte integer values
      rawValue[0] = ((uint16_t)_utils.getRegValue(_address, RPR_0521RS_REG_ALS_DATA0_MSB) << 8) | _utils.getRegValue(_address, RPR_0521RS_REG_ALS_DATA0_LSB);
      rawValue[1] = ((uint16_t)_utils.getRegValue(_address, RPR_0521RS_REG_ALS_DATA1_MSB) << 8) | _utils.getRegValue(_address, RPR_0521RS_REG_ALS_DATA1_LSB);

      //intermediate calculations
      data0 = (float)rawValue[0] * (100 / _alsMeasurementTime) / _alsData0Gain;
      data1 = (float)rawValue[1] * (100 / _alsMeasurementTime) / _alsData1Gain;

      //zero division check
      if(data0 == 0) {
        als = 0;
      }

      data1_0 = data1 / data0;

      //return real value in lx
      if (data1_0 < 0.595) {
        als = 1.682 * data0 - 1.877 * data1;
      } else if (data1_0 < 1.015) {
        als = 0.644 * data0 - 0.132 * data1;
      } else if (data1_0 < 1.352) {
        als = 0.756 * data0 - 0.243 * data1;
      } else if (data1_0 < 3.053) {
        als = 0.766 * data0 - 0.250 * data1;
      }

      //proximity measurement
      //read the proximity value (does not have a real unit, this will only tell you whether an object is closer than e.g. a few centimiters)
      ps = ((uint16_t)_utils.getRegValue(_address, RPR_0521RS_REG_PS_DATA_MSB) << 8) | _utils.getRegValue(_address, RPR_0521RS_REG_PS_DATA_LSB);

      return(0);
    }

  private:
    utilities _utils;
    uint8_t _address,
    uint8_t _alsData0Gain = 1;
    uint8_t _alsData1Gain = 1;
    uint8_t _alsMeasurementTime = 0;

};

#endif
<commit_msg>Fixed bug in RPR_5021<commit_after>#ifndef _RPR_0521RS_CPP
#define _RPR_0521RS_CPP

//RPR_0521RS register map
#define RPR_0521RS_REG_SYSTEM_CONTROL                 0x40
#define RPR_0521RS_REG_MODE_CONTROL                   0x41
#define RPR_0521RS_REG_ALS_PS_CONTROL                 0x42
#define RPR_0521RS_REG_PS_CONTROL                     0x43
#define RPR_0521RS_REG_PS_DATA_LSB                    0x44
#define RPR_0521RS_REG_PS_DATA_MSB                    0x45
#define RPR_0521RS_REG_ALS_DATA0_LSB                  0x46
#define RPR_0521RS_REG_ALS_DATA0_MSB                  0x47
#define RPR_0521RS_REG_ALS_DATA1_LSB                  0x48
#define RPR_0521RS_REG_ALS_DATA1_MSB                  0x49
#define RPR_0521RS_REG_INTERRUPT                      0x4A
#define RPR_0521RS_REG_PS_TH_LSB                      0x4B
#define RPR_0521RS_REG_PS_TH_MSB                      0x4C
#define RPR_0521RS_REG_PS_TL_LSB                      0x4D
#define RPR_0521RS_REG_PS_TL_MSB                      0x4E
#define RPR_0521RS_REG_ALS_DATA0_TH_LSB               0x4F
#define RPR_0521RS_REG_ALS_DATA0_TH_MSB               0x50
#define RPR_0521RS_REG_ALS_DATA0_TL_LSB               0x51
#define RPR_0521RS_REG_ALS_DATA0_TL_MSB               0x52
#define RPR_0521RS_REG_PS_OFFSET_LSB                  0x53
#define RPR_0521RS_REG_PS_OFFSET_MSB                  0x54
#define RPR_0521RS_REG_MANUFACT_ID                    0x92

//RPR_0521RS default values
#define RPR_0521RS_DEVICE_ADDRESS                     0x38
#define RPR_0521RS_PART_ID                            0x0A
#define RPR_0521RS_MANUFACT_ID                        0xE0

//RPR_0521RS settings
//RPR_0521RS_REG_MODE_CONTROL                                         MSB   LSB   DESCRIPTION
#define RPR_0521RS_ALS_OFF                            0b00000000  //  7     7     ambient light sensor (ALS) on standby
#define RPR_0521RS_ALS_ON                             0b10000000  //  7     7     ambient light sensor (ALS) enabled
#define RPR_0521RS_PS_OFF                             0b00000000  //  6     6     proximity sensor (PS) on standby
#define RPR_0521RS_PS_ON                              0b01000000  //  6     6     proximity sensor (PS) enabled
#define RPR_0521RS_PS_PULSE_200_US                    0b00000000  //  5     5     PS pulse width: 200 us (typical)
#define RPR_0521RS_PS_PULSE_330_US                    0b00100000  //  5     5                     330 us (typical)
#define RPR_0521RS_PS_NORMAL                          0b00000000  //  4     4     normal PS operating mode
#define RPR_0521RS_PS_DOUBLE                          0b00010000  //  4     4     double measurement PS operating mode
#define RPR_0521RS_MEAS_TIME_STBY_STBY                0b00000000  //  3     0     measurement time: ALS standby,  PS standby
#define RPR_0521RS_MEAS_TIME_STBY_10_MS               0b00000001  //  3     0                       ALS standby,  PS 10 ms
#define RPR_0521RS_MEAS_TIME_STBY_40_MS               0b00000010  //  3     0                       ALS standby,  PS 40 ms
#define RPR_0521RS_MEAS_TIME_STBY_100_MS              0b00000011  //  3     0                       ALS standby,  PS 100 ms
#define RPR_0521RS_MEAS_TIME_STBY_400_MS              0b00000100  //  3     0                       ALS standby,  PS 400 ms
#define RPR_0521RS_MEAS_TIME_100_MS_50_MS             0b00000101  //  3     0                       ALS 100 ms,   PS 50 ms
#define RPR_0521RS_MEAS_TIME_100_MS_100_MS            0b00000110  //  3     0                       ALS 100 ms,   PS 100 ms
#define RPR_0521RS_MEAS_TIME_100_MS_400_MS            0b00000111  //  3     0                       ALS 100 ms,   PS 400 ms
#define RPR_0521RS_MEAS_TIME_400_MS_50_MS             0b00001000  //  3     0                       ALS 400 ms,   PS 50 ms
#define RPR_0521RS_MEAS_TIME_400_MS_100_MS            0b00001001  //  3     0                       ALS 400 ms,   PS 100 ms
#define RPR_0521RS_MEAS_TIME_400_MS_STBY              0b00001010  //  3     0                       ALS 400 ms,   PS standby
#define RPR_0521RS_MEAS_TIME_400_MS_400_MS            0b00001011  //  3     0                       ALS 400 ms,   PS 400 ms
#define RPR_0521RS_MEAS_TIME_50_MS_50_MS              0b00001100  //  3     0                       ALS 50 ms,   PS 50 ms
//RPR_0521RS_REG_ALS_PS_CONTROL
#define RPR_0521RS_ALS_DATA0_GAIN_1                   0b00000000  //  5     4     ALS DATA0 gain: x1
#define RPR_0521RS_ALS_DATA0_GAIN_2                   0b00010000  //  5     4                     x2
#define RPR_0521RS_ALS_DATA0_GAIN_64                  0b00100000  //  5     4                     x64
#define RPR_0521RS_ALS_DATA0_GAIN_128                 0b00110000  //  5     4                     x128
#define RPR_0521RS_ALS_DATA1_GAIN_1                   0b00000000  //  3     2     ALS DATA1 gain: x1
#define RPR_0521RS_ALS_DATA1_GAIN_2                   0b00000100  //  3     2                     x2
#define RPR_0521RS_ALS_DATA1_GAIN_64                  0b00001000  //  3     2                     x64
#define RPR_0521RS_ALS_DATA1_GAIN_128                 0b00001100  //  3     2                     x128
#define RPR_0521RS_LED_CURRENT_25_MA                  0b00000000  //  1     0     LED current:  25 mA
#define RPR_0521RS_LED_CURRENT_50_MA                  0b00000001  //  1     0                   50 mA
#define RPR_0521RS_LED_CURRENT_100_MA                 0b00000010  //  1     0                   100 mA
#define RPR_0521RS_LED_CURRENT_200_MA                 0b00000011  //  1     0                   200 mA
//RPR_0521RS_REG_PS_CONTROL
#define RPR_0521RS_PS_GAIN_1                          0b00000000  //  5     4     PS gain:  x1
#define RPR_0521RS_PS_GAIN_2                          0b00010000  //  5     4               x2
#define RPR_0521RS_PS_GAIN_4                          0b00100000  //  5     4               x4

class RPR_0521RS {
  public:
    //Measurement variables
    uint16_t ps = 0; //proximity value
    float als = 0; //ambient light value in lx

    //Default constructor
    RPR_0521RS(uint8_t address = RPR_0521RS_DEVICE_ADDRESS) {
      _address = address;
    }

    //Initialization function
    uint8_t init(uint8_t measurementTime = RPR_0521RS_MEAS_TIME_100_MS_100_MS, uint8_t ledCurrent = RPR_0521RS_LED_CURRENT_100_MA) {
      //check manufacturer and part ID
      if((_utils.getRegValue(_address, RPR_0521RS_REG_SYSTEM_CONTROL, 5, 0) != RPR_0521RS_PART_ID) || (_utils.getRegValue(_address, RPR_0521RS_REG_MANUFACT_ID) != RPR_0521RS_MANUFACT_ID)) {
        //if the IDs do not match cancel initialization
        return(1);
      }

      //set control registers according to datasheet and user settings
      _utils.setRegValue(_address, RPR_0521RS_REG_ALS_PS_CONTROL, RPR_0521RS_ALS_DATA0_GAIN_1 | RPR_0521RS_ALS_DATA1_GAIN_1 | ledCurrent);
      _utils.setRegValue(_address, RPR_0521RS_REG_PS_CONTROL, RPR_0521RS_PS_GAIN_1, 5, 4);
      _utils.setRegValue(_address, RPR_0521RS_REG_MODE_CONTROL, RPR_0521RS_ALS_ON | RPR_0521RS_PS_ON | measurementTime);

      //TODO: implement gain and measurement time selection
      //gain and measurement time arrays
      uint8_t alsGainTable[4] = {1, 2, 64, 128};
      uint8_t psGainTable[3] = {1, 2, 4};
      uint16_t alsMeasureTimeTable[13] = {0, 0, 0, 0, 0, 100, 100, 100, 400, 400, 400, 400, 50};
      uint16_t psMeasureTimeTable[13] = {0, 10, 40, 100, 400, 50, 100, 400, 50, 100, 0, 400, 50};

      //set gain and measurement time
      _alsData0Gain = alsGainTable[0];
      _alsData1Gain = alsGainTable[0];
      _alsMeasurementTime = alsMeasureTimeTable[measurementTime];

      return(0);
    }

    //Measurement function
    uint8_t measure(void) {
      //TODO: implement interrupt

      //ambient light measurement
      uint16_t rawValue[2];
      float data0, data1, data1_0;

      //read raw 2-byte integer values
      rawValue[0] = ((uint16_t)_utils.getRegValue(_address, RPR_0521RS_REG_ALS_DATA0_MSB) << 8) | _utils.getRegValue(_address, RPR_0521RS_REG_ALS_DATA0_LSB);
      rawValue[1] = ((uint16_t)_utils.getRegValue(_address, RPR_0521RS_REG_ALS_DATA1_MSB) << 8) | _utils.getRegValue(_address, RPR_0521RS_REG_ALS_DATA1_LSB);

      //intermediate calculations
      data0 = (float)rawValue[0] * (100 / _alsMeasurementTime) / _alsData0Gain;
      data1 = (float)rawValue[1] * (100 / _alsMeasurementTime) / _alsData1Gain;

      //zero division check
      if(data0 == 0) {
        als = 0;
      }

      data1_0 = data1 / data0;

      //return real value in lx
      if (data1_0 < 0.595) {
        als = 1.682 * data0 - 1.877 * data1;
      } else if (data1_0 < 1.015) {
        als = 0.644 * data0 - 0.132 * data1;
      } else if (data1_0 < 1.352) {
        als = 0.756 * data0 - 0.243 * data1;
      } else if (data1_0 < 3.053) {
        als = 0.766 * data0 - 0.250 * data1;
      }

      //proximity measurement
      //read the proximity value (does not have a real unit, this will only tell you whether an object is closer than e.g. a few centimiters)
      ps = ((uint16_t)_utils.getRegValue(_address, RPR_0521RS_REG_PS_DATA_MSB) << 8) | _utils.getRegValue(_address, RPR_0521RS_REG_PS_DATA_LSB);

      return(0);
    }

  private:
    utilities _utils;
    uint8_t _address;
    uint8_t _alsData0Gain = 1;
    uint8_t _alsData1Gain = 1;
    uint8_t _alsMeasurementTime = 0;

};

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: javaldx.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: hr $ $Date: 2005-10-25 11:35:01 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sal/main.h"
#include "sal/types.h"
#include "osl/thread.h"
#include "rtl/ustring.hxx"
#include "rtl/byteseq.hxx"
#include "jvmfwk/framework.h"

using namespace rtl;

#define OUSTR(x) OUString(RTL_CONSTASCII_USTRINGPARAM( x ))

static sal_Bool hasOption(char* szOption, int argc, char** argv);
static rtl::OString getLD_LIBRARY_PATH(const rtl::ByteSequence & vendorData);
//static sal_Bool printPaths(const OUString& sPathFile);

#ifdef MACOSX
#define HELP_TEXT    \
"\njavaldx is necessary to make Java work on some UNIX platforms." \
"It prints a string to std out that consists of directories which " \
"have to be included into the DYLD_LIBRARY_PATH variable.The setting of " \
"the variable usually occurs in a shell script that runs javaldx.\n" \
"The directories are from the chosen java installation. \n" \
"Options are: \n"\
"--help or -h\n"
#else
#define HELP_TEXT    \
"\njavaldx is necessary to make Java work on some UNIX platforms." \
"It prints a string to std out that consists of directories which " \
"have to be included into the LD_LIBRARY_PATH variable.The setting of " \
"the variable usually occurs in a shell script that runs javaldx.\n" \
"The directories are from the chosen java installation. \n" \
"Options are: \n"\
"--help or -h\n"
#endif

SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
    if( hasOption("--help",argc, argv) || hasOption("-h", argc, argv))
    {
        fprintf(stdout, HELP_TEXT);// default
        return 0;
    }
    javaFrameworkError errcode = JFW_E_NONE;
    sal_Bool bEnabled = sal_False;
    errcode = jfw_getEnabled( & bEnabled);
    if (errcode == JFW_E_NONE && bEnabled == sal_False)
    {
            //Do not do any preparation because that may only slow startup time.
        return 0;
    }
    else if (errcode != JFW_E_NONE && errcode != JFW_E_DIRECT_MODE)
    {
        fprintf(stderr,"javaldx failed! \n");
        return -1;
    }

    JavaInfo * pInfo = NULL;
    errcode = jfw_getSelectedJRE( & pInfo);

    if (errcode == JFW_E_INVALID_SETTINGS)
    {
        fprintf(stderr,"javaldx failed. User must select a JRE from options dialog!");
        return -1;
    }
    else if (errcode != JFW_E_NONE)
    {
        fprintf(stderr,"javaldx failed! \n");
        return -1;
    }

    if (pInfo == NULL)
    {
        errcode = jfw_findAndSelectJRE( & pInfo);
        if (errcode == JFW_E_NO_JAVA_FOUND)
        {
            fprintf(stderr,"javaldx: Could not find a Java Runtime Environment! \n");
            return 0;
        }
        else if (errcode != JFW_E_NONE && errcode != JFW_E_DIRECT_MODE)
        {
            fprintf(stderr,"javaldx failed!\n");
            return -1;
        }
    }

    //Only do something if the sunjavaplugin created this JavaInfo
    rtl::OUString sVendor1(RTL_CONSTASCII_USTRINGPARAM("Sun Microsystems Inc."));
    rtl::OUString sVendor2(RTL_CONSTASCII_USTRINGPARAM("IBM Corporation"));
    rtl::OUString sVendor3(RTL_CONSTASCII_USTRINGPARAM("Blackdown Java-Linux Team"));
    rtl::OUString sVendor4(RTL_CONSTASCII_USTRINGPARAM("Apple Computer, Inc."));
    rtl::OUString sVendor5(RTL_CONSTASCII_USTRINGPARAM("BEA Systems, Inc."));
    if ( ! (sVendor1.equals(pInfo->sVendor) == sal_True
            || sVendor2.equals(pInfo->sVendor) == sal_True
            || sVendor3.equals(pInfo->sVendor) == sal_True
            || sVendor4.equals(pInfo->sVendor) == sal_True
            || sVendor5.equals(pInfo->sVendor) == sal_True))
        return 0;

    rtl::OString sPaths = getLD_LIBRARY_PATH(pInfo->arVendorData);
    fprintf(stdout, "%s\n", sPaths.getStr());
    jfw_freeJavaInfo(pInfo);

    return 0;
}

rtl::OString getLD_LIBRARY_PATH(const rtl::ByteSequence & vendorData)
{
    const sal_Unicode* chars = (sal_Unicode*) vendorData.getConstArray();
    sal_Int32 len = vendorData.getLength();
    rtl::OUString sData(chars, len / 2);
    //the runtime lib is on the first line
    sal_Int32 index = 0;
    rtl::OUString aToken = sData.getToken( 1, '\n', index);

    rtl::OString paths =
        rtl::OUStringToOString(aToken, osl_getThreadTextEncoding());
    return paths;
}

static sal_Bool hasOption(char* szOption, int argc, char** argv)
{
    sal_Bool retVal= sal_False;
    for(sal_Int16 i= 1; i < argc; i++)
    {
        if( ! strcmp(argv[i], szOption))
        {
            retVal= sal_True;
            break;
        }
    }
    return retVal;
}

<commit_msg>INTEGRATION: CWS warnings01 (1.9.6); FILE MERGED 2005/11/07 18:54:26 pl 1.9.6.2: RESYNC: (1.9-1.10); FILE MERGED 2005/10/28 10:13:54 sb 1.9.6.1: #i53898# Made code warning-free.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: javaldx.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 00:08:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sal/main.h"
#include "sal/types.h"
#include "osl/thread.h"
#include "rtl/ustring.hxx"
#include "rtl/byteseq.hxx"
#include "jvmfwk/framework.h"

using namespace rtl;

#define OUSTR(x) OUString(RTL_CONSTASCII_USTRINGPARAM( x ))

static sal_Bool hasOption(char const * szOption, int argc, char** argv);
static rtl::OString getLD_LIBRARY_PATH(const rtl::ByteSequence & vendorData);
//static sal_Bool printPaths(const OUString& sPathFile);

#ifdef MACOSX
#define HELP_TEXT    \
"\njavaldx is necessary to make Java work on some UNIX platforms." \
"It prints a string to std out that consists of directories which " \
"have to be included into the DYLD_LIBRARY_PATH variable.The setting of " \
"the variable usually occurs in a shell script that runs javaldx.\n" \
"The directories are from the chosen java installation. \n" \
"Options are: \n"\
"--help or -h\n"
#else
#define HELP_TEXT    \
"\njavaldx is necessary to make Java work on some UNIX platforms." \
"It prints a string to std out that consists of directories which " \
"have to be included into the LD_LIBRARY_PATH variable.The setting of " \
"the variable usually occurs in a shell script that runs javaldx.\n" \
"The directories are from the chosen java installation. \n" \
"Options are: \n"\
"--help or -h\n"
#endif

SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
    if( hasOption("--help",argc, argv) || hasOption("-h", argc, argv))
    {
        fprintf(stdout, HELP_TEXT);// default
        return 0;
    }
    javaFrameworkError errcode = JFW_E_NONE;
    sal_Bool bEnabled = sal_False;
    errcode = jfw_getEnabled( & bEnabled);
    if (errcode == JFW_E_NONE && bEnabled == sal_False)
    {
            //Do not do any preparation because that may only slow startup time.
        return 0;
    }
    else if (errcode != JFW_E_NONE && errcode != JFW_E_DIRECT_MODE)
    {
        fprintf(stderr,"javaldx failed! \n");
        return -1;
    }

    JavaInfo * pInfo = NULL;
    errcode = jfw_getSelectedJRE( & pInfo);

    if (errcode == JFW_E_INVALID_SETTINGS)
    {
        fprintf(stderr,"javaldx failed. User must select a JRE from options dialog!");
        return -1;
    }
    else if (errcode != JFW_E_NONE)
    {
        fprintf(stderr,"javaldx failed! \n");
        return -1;
    }

    if (pInfo == NULL)
    {
        errcode = jfw_findAndSelectJRE( & pInfo);
        if (errcode == JFW_E_NO_JAVA_FOUND)
        {
            fprintf(stderr,"javaldx: Could not find a Java Runtime Environment! \n");
            return 0;
        }
        else if (errcode != JFW_E_NONE && errcode != JFW_E_DIRECT_MODE)
        {
            fprintf(stderr,"javaldx failed!\n");
            return -1;
        }
    }

    //Only do something if the sunjavaplugin created this JavaInfo
    rtl::OUString sVendor1(RTL_CONSTASCII_USTRINGPARAM("Sun Microsystems Inc."));
    rtl::OUString sVendor2(RTL_CONSTASCII_USTRINGPARAM("IBM Corporation"));
    rtl::OUString sVendor3(RTL_CONSTASCII_USTRINGPARAM("Blackdown Java-Linux Team"));
    rtl::OUString sVendor4(RTL_CONSTASCII_USTRINGPARAM("Apple Computer, Inc."));
    rtl::OUString sVendor5(RTL_CONSTASCII_USTRINGPARAM("BEA Systems, Inc."));
    if ( ! (sVendor1.equals(pInfo->sVendor) == sal_True
            || sVendor2.equals(pInfo->sVendor) == sal_True
            || sVendor3.equals(pInfo->sVendor) == sal_True
            || sVendor4.equals(pInfo->sVendor) == sal_True
            || sVendor5.equals(pInfo->sVendor) == sal_True))
        return 0;

    rtl::OString sPaths = getLD_LIBRARY_PATH(pInfo->arVendorData);
    fprintf(stdout, "%s\n", sPaths.getStr());
    jfw_freeJavaInfo(pInfo);

    return 0;
}

rtl::OString getLD_LIBRARY_PATH(const rtl::ByteSequence & vendorData)
{
    const sal_Unicode* chars = (sal_Unicode*) vendorData.getConstArray();
    sal_Int32 len = vendorData.getLength();
    rtl::OUString sData(chars, len / 2);
    //the runtime lib is on the first line
    sal_Int32 index = 0;
    rtl::OUString aToken = sData.getToken( 1, '\n', index);

    rtl::OString paths =
        rtl::OUStringToOString(aToken, osl_getThreadTextEncoding());
    return paths;
}

static sal_Bool hasOption(char const * szOption, int argc, char** argv)
{
    sal_Bool retVal= sal_False;
    for(sal_Int16 i= 1; i < argc; i++)
    {
        if( ! strcmp(argv[i], szOption))
        {
            retVal= sal_True;
            break;
        }
    }
    return retVal;
}

<|endoftext|>


<commit_before>// Copyright (c) 2016-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <support/lockedpool.h>
#include <support/cleanse.h>

#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <sys/mman.h> // for mmap
#include <sys/resource.h> // for getrlimit
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

#include <algorithm>
#ifdef ARENA_DEBUG
#include <iomanip>
#include <iostream>
#endif

LockedPoolManager* LockedPoolManager::_instance = nullptr;
std::once_flag LockedPoolManager::init_flag;

/*******************************************************************************/
// Utilities
//
/** Align up to power of 2 */
static inline size_t align_up(size_t x, size_t align)
{
    return (x + align - 1) & ~(align - 1);
}

/*******************************************************************************/
// Implementation: Arena

Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
    base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
{
    // Start with one free chunk that covers the entire arena
    auto it = size_to_free_chunk.emplace(size_in, base);
    chunks_free.emplace(base, it);
    chunks_free_end.emplace(base + size_in, it);
}

Arena::~Arena()
{
}

void* Arena::alloc(size_t size)
{
    // Round to next multiple of alignment
    size = align_up(size, alignment);

    // Don't handle zero-sized chunks
    if (size == 0)
        return nullptr;

    // Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key.
    // This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review",
    // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit
    // policies seem to work well in practice.
    auto size_ptr_it = size_to_free_chunk.lower_bound(size);
    if (size_ptr_it == size_to_free_chunk.end())
        return nullptr;

    // Create the used-chunk, taking its space from the end of the free-chunk
    const size_t size_remaining = size_ptr_it->first - size;
    auto allocated = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first;
    chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first);
    if (size_ptr_it->first == size) {
        // whole chunk is used up
        chunks_free.erase(size_ptr_it->second);
    } else {
        // still some memory left in the chunk
        auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second);
        chunks_free[size_ptr_it->second] = it_remaining;
        chunks_free_end.emplace(size_ptr_it->second + size_remaining, it_remaining);
    }
    size_to_free_chunk.erase(size_ptr_it);

    return reinterpret_cast<void*>(allocated->first);
}

void Arena::free(void *ptr)
{
    // Freeing the nullptr pointer is OK.
    if (ptr == nullptr) {
        return;
    }

    // Remove chunk from used map
    auto i = chunks_used.find(static_cast<char*>(ptr));
    if (i == chunks_used.end()) {
        throw std::runtime_error("Arena: invalid or double free");
    }
    std::pair<char*, size_t> freed = *i;
    chunks_used.erase(i);

    // coalesce freed with previous chunk
    auto prev = chunks_free_end.find(freed.first);
    if (prev != chunks_free_end.end()) {
        freed.first -= prev->second->first;
        freed.second += prev->second->first;
        size_to_free_chunk.erase(prev->second);
        chunks_free_end.erase(prev);
    }

    // coalesce freed with chunk after freed
    auto next = chunks_free.find(freed.first + freed.second);
    if (next != chunks_free.end()) {
        freed.second += next->second->first;
        size_to_free_chunk.erase(next->second);
        chunks_free.erase(next);
    }

    // Add/set space with coalesced free chunk
    auto it = size_to_free_chunk.emplace(freed.second, freed.first);
    chunks_free[freed.first] = it;
    chunks_free_end[freed.first + freed.second] = it;
}

Arena::Stats Arena::stats() const
{
    Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };
    for (const auto& chunk: chunks_used)
        r.used += chunk.second;
    for (const auto& chunk: chunks_free)
        r.free += chunk.second->first;
    r.total = r.used + r.free;
    return r;
}

#ifdef ARENA_DEBUG
static void printchunk(void* base, size_t sz, bool used) {
    std::cout <<
        "0x" << std::hex << std::setw(16) << std::setfill('0') << base <<
        " 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<
        " 0x" << used << std::endl;
}
void Arena::walk() const
{
    for (const auto& chunk: chunks_used)
        printchunk(chunk.first, chunk.second, true);
    std::cout << std::endl;
    for (const auto& chunk: chunks_free)
        printchunk(chunk.first, chunk.second->first, false);
    std::cout << std::endl;
}
#endif

/*******************************************************************************/
// Implementation: Win32LockedPageAllocator

#ifdef WIN32
/** LockedPageAllocator specialized for Windows.
 */
class Win32LockedPageAllocator: public LockedPageAllocator
{
public:
    Win32LockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess) override;
    void FreeLocked(void* addr, size_t len) override;
    size_t GetLimit() override;
private:
    size_t page_size;
};

Win32LockedPageAllocator::Win32LockedPageAllocator()
{
    // Determine system page size in bytes
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
}
void *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    len = align_up(len, page_size);
    void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (addr) {
        // VirtualLock is used to attempt to keep keying material out of swap. Note
        // that it does not provide this as a guarantee, but, in practice, memory
        // that has been VirtualLock'd almost never gets written to the pagefile
        // except in rare circumstances where memory is extremely low.
        *lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;
    }
    return addr;
}
void Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    VirtualUnlock(const_cast<void*>(addr), len);
}

size_t Win32LockedPageAllocator::GetLimit()
{
    // TODO is there a limit on Windows, how to get it?
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: PosixLockedPageAllocator

#ifndef WIN32
/** LockedPageAllocator specialized for OSes that don't try to be
 * special snowflakes.
 */
class PosixLockedPageAllocator: public LockedPageAllocator
{
public:
    PosixLockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess) override;
    void FreeLocked(void* addr, size_t len) override;
    size_t GetLimit() override;
private:
    size_t page_size;
};

PosixLockedPageAllocator::PosixLockedPageAllocator()
{
    // Determine system page size in bytes
#if defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else                   // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
}

// Some systems (at least OS X) do not define MAP_ANONYMOUS yet and define
// MAP_ANON which is deprecated
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif

void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    void *addr;
    len = align_up(len, page_size);
    addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED) {
        return nullptr;
    }
    if (addr) {
        *lockingSuccess = mlock(addr, len) == 0;
    }
    return addr;
}
void PosixLockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    munlock(addr, len);
    munmap(addr, len);
}
size_t PosixLockedPageAllocator::GetLimit()
{
#ifdef RLIMIT_MEMLOCK
    struct rlimit rlim;
    if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
        if (rlim.rlim_cur != RLIM_INFINITY) {
            return rlim.rlim_cur;
        }
    }
#endif
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: LockedPool

LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):
    allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)
{
}

LockedPool::~LockedPool()
{
}
void* LockedPool::alloc(size_t size)
{
    std::lock_guard<std::mutex> lock(mutex);

    // Don't handle impossible sizes
    if (size == 0 || size > ARENA_SIZE)
        return nullptr;

    // Try allocating from each current arena
    for (auto &arena: arenas) {
        void *addr = arena.alloc(size);
        if (addr) {
            return addr;
        }
    }
    // If that fails, create a new one
    if (new_arena(ARENA_SIZE, ARENA_ALIGN)) {
        return arenas.back().alloc(size);
    }
    return nullptr;
}

void LockedPool::free(void *ptr)
{
    std::lock_guard<std::mutex> lock(mutex);
    // TODO we can do better than this linear search by keeping a map of arena
    // extents to arena, and looking up the address.
    for (auto &arena: arenas) {
        if (arena.addressInArena(ptr)) {
            arena.free(ptr);
            return;
        }
    }
    throw std::runtime_error("LockedPool: invalid address not pointing to any arena");
}

LockedPool::Stats LockedPool::stats() const
{
    std::lock_guard<std::mutex> lock(mutex);
    LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};
    for (const auto &arena: arenas) {
        Arena::Stats i = arena.stats();
        r.used += i.used;
        r.free += i.free;
        r.total += i.total;
        r.chunks_used += i.chunks_used;
        r.chunks_free += i.chunks_free;
    }
    return r;
}

bool LockedPool::new_arena(size_t size, size_t align)
{
    bool locked;
    // If this is the first arena, handle this specially: Cap the upper size
    // by the process limit. This makes sure that the first arena will at least
    // be locked. An exception to this is if the process limit is 0:
    // in this case no memory can be locked at all so we'll skip past this logic.
    if (arenas.empty()) {
        size_t limit = allocator->GetLimit();
        if (limit > 0) {
            size = std::min(size, limit);
        }
    }
    void *addr = allocator->AllocateLocked(size, &locked);
    if (!addr) {
        return false;
    }
    if (locked) {
        cumulative_bytes_locked += size;
    } else if (lf_cb) { // Call the locking-failed callback if locking failed
        if (!lf_cb()) { // If the callback returns false, free the memory and fail, otherwise consider the user warned and proceed.
            allocator->FreeLocked(addr, size);
            return false;
        }
    }
    arenas.emplace_back(allocator.get(), addr, size, align);
    return true;
}

LockedPool::LockedPageArena::LockedPageArena(LockedPageAllocator *allocator_in, void *base_in, size_t size_in, size_t align_in):
    Arena(base_in, size_in, align_in), base(base_in), size(size_in), allocator(allocator_in)
{
}
LockedPool::LockedPageArena::~LockedPageArena()
{
    allocator->FreeLocked(base, size);
}

/*******************************************************************************/
// Implementation: LockedPoolManager
//
LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator_in):
    LockedPool(std::move(allocator_in), &LockedPoolManager::LockingFailed)
{
}

bool LockedPoolManager::LockingFailed()
{
    // TODO: log something but how? without including util.h
    return true;
}

void LockedPoolManager::CreateInstance()
{
    // Using a local static instance guarantees that the object is initialized
    // when it's first needed and also deinitialized after all objects that use
    // it are done with it.  I can think of one unlikely scenario where we may
    // have a static deinitialization order/problem, but the check in
    // LockedPoolManagerBase's destructor helps us detect if that ever happens.
#ifdef WIN32
    std::unique_ptr<LockedPageAllocator> allocator(new Win32LockedPageAllocator());
#else
    std::unique_ptr<LockedPageAllocator> allocator(new PosixLockedPageAllocator());
#endif
    static LockedPoolManager instance(std::move(allocator));
    LockedPoolManager::_instance = &instance;
}
<commit_msg>lockedpool: When possible, use madvise to avoid including sensitive information in core dumps<commit_after>// Copyright (c) 2016-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <support/lockedpool.h>
#include <support/cleanse.h>

#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <sys/mman.h> // for mmap
#include <sys/resource.h> // for getrlimit
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

#include <algorithm>
#ifdef ARENA_DEBUG
#include <iomanip>
#include <iostream>
#endif

LockedPoolManager* LockedPoolManager::_instance = nullptr;
std::once_flag LockedPoolManager::init_flag;

/*******************************************************************************/
// Utilities
//
/** Align up to power of 2 */
static inline size_t align_up(size_t x, size_t align)
{
    return (x + align - 1) & ~(align - 1);
}

/*******************************************************************************/
// Implementation: Arena

Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
    base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
{
    // Start with one free chunk that covers the entire arena
    auto it = size_to_free_chunk.emplace(size_in, base);
    chunks_free.emplace(base, it);
    chunks_free_end.emplace(base + size_in, it);
}

Arena::~Arena()
{
}

void* Arena::alloc(size_t size)
{
    // Round to next multiple of alignment
    size = align_up(size, alignment);

    // Don't handle zero-sized chunks
    if (size == 0)
        return nullptr;

    // Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key.
    // This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review",
    // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit
    // policies seem to work well in practice.
    auto size_ptr_it = size_to_free_chunk.lower_bound(size);
    if (size_ptr_it == size_to_free_chunk.end())
        return nullptr;

    // Create the used-chunk, taking its space from the end of the free-chunk
    const size_t size_remaining = size_ptr_it->first - size;
    auto allocated = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first;
    chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first);
    if (size_ptr_it->first == size) {
        // whole chunk is used up
        chunks_free.erase(size_ptr_it->second);
    } else {
        // still some memory left in the chunk
        auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second);
        chunks_free[size_ptr_it->second] = it_remaining;
        chunks_free_end.emplace(size_ptr_it->second + size_remaining, it_remaining);
    }
    size_to_free_chunk.erase(size_ptr_it);

    return reinterpret_cast<void*>(allocated->first);
}

void Arena::free(void *ptr)
{
    // Freeing the nullptr pointer is OK.
    if (ptr == nullptr) {
        return;
    }

    // Remove chunk from used map
    auto i = chunks_used.find(static_cast<char*>(ptr));
    if (i == chunks_used.end()) {
        throw std::runtime_error("Arena: invalid or double free");
    }
    std::pair<char*, size_t> freed = *i;
    chunks_used.erase(i);

    // coalesce freed with previous chunk
    auto prev = chunks_free_end.find(freed.first);
    if (prev != chunks_free_end.end()) {
        freed.first -= prev->second->first;
        freed.second += prev->second->first;
        size_to_free_chunk.erase(prev->second);
        chunks_free_end.erase(prev);
    }

    // coalesce freed with chunk after freed
    auto next = chunks_free.find(freed.first + freed.second);
    if (next != chunks_free.end()) {
        freed.second += next->second->first;
        size_to_free_chunk.erase(next->second);
        chunks_free.erase(next);
    }

    // Add/set space with coalesced free chunk
    auto it = size_to_free_chunk.emplace(freed.second, freed.first);
    chunks_free[freed.first] = it;
    chunks_free_end[freed.first + freed.second] = it;
}

Arena::Stats Arena::stats() const
{
    Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };
    for (const auto& chunk: chunks_used)
        r.used += chunk.second;
    for (const auto& chunk: chunks_free)
        r.free += chunk.second->first;
    r.total = r.used + r.free;
    return r;
}

#ifdef ARENA_DEBUG
static void printchunk(void* base, size_t sz, bool used) {
    std::cout <<
        "0x" << std::hex << std::setw(16) << std::setfill('0') << base <<
        " 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<
        " 0x" << used << std::endl;
}
void Arena::walk() const
{
    for (const auto& chunk: chunks_used)
        printchunk(chunk.first, chunk.second, true);
    std::cout << std::endl;
    for (const auto& chunk: chunks_free)
        printchunk(chunk.first, chunk.second->first, false);
    std::cout << std::endl;
}
#endif

/*******************************************************************************/
// Implementation: Win32LockedPageAllocator

#ifdef WIN32
/** LockedPageAllocator specialized for Windows.
 */
class Win32LockedPageAllocator: public LockedPageAllocator
{
public:
    Win32LockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess) override;
    void FreeLocked(void* addr, size_t len) override;
    size_t GetLimit() override;
private:
    size_t page_size;
};

Win32LockedPageAllocator::Win32LockedPageAllocator()
{
    // Determine system page size in bytes
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
}
void *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    len = align_up(len, page_size);
    void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (addr) {
        // VirtualLock is used to attempt to keep keying material out of swap. Note
        // that it does not provide this as a guarantee, but, in practice, memory
        // that has been VirtualLock'd almost never gets written to the pagefile
        // except in rare circumstances where memory is extremely low.
        *lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;
    }
    return addr;
}
void Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    VirtualUnlock(const_cast<void*>(addr), len);
}

size_t Win32LockedPageAllocator::GetLimit()
{
    // TODO is there a limit on Windows, how to get it?
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: PosixLockedPageAllocator

#ifndef WIN32
/** LockedPageAllocator specialized for OSes that don't try to be
 * special snowflakes.
 */
class PosixLockedPageAllocator: public LockedPageAllocator
{
public:
    PosixLockedPageAllocator();
    void* AllocateLocked(size_t len, bool *lockingSuccess) override;
    void FreeLocked(void* addr, size_t len) override;
    size_t GetLimit() override;
private:
    size_t page_size;
};

PosixLockedPageAllocator::PosixLockedPageAllocator()
{
    // Determine system page size in bytes
#if defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else                   // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
}

// Some systems (at least OS X) do not define MAP_ANONYMOUS yet and define
// MAP_ANON which is deprecated
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif

void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
{
    void *addr;
    len = align_up(len, page_size);
    addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED) {
        return nullptr;
    }
    if (addr) {
        *lockingSuccess = mlock(addr, len) == 0;
#ifdef MADV_DONTDUMP
        madvise(addr, len, MADV_DONTDUMP);
#endif
    }
    return addr;
}
void PosixLockedPageAllocator::FreeLocked(void* addr, size_t len)
{
    len = align_up(len, page_size);
    memory_cleanse(addr, len);
    munlock(addr, len);
    munmap(addr, len);
}
size_t PosixLockedPageAllocator::GetLimit()
{
#ifdef RLIMIT_MEMLOCK
    struct rlimit rlim;
    if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
        if (rlim.rlim_cur != RLIM_INFINITY) {
            return rlim.rlim_cur;
        }
    }
#endif
    return std::numeric_limits<size_t>::max();
}
#endif

/*******************************************************************************/
// Implementation: LockedPool

LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):
    allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)
{
}

LockedPool::~LockedPool()
{
}
void* LockedPool::alloc(size_t size)
{
    std::lock_guard<std::mutex> lock(mutex);

    // Don't handle impossible sizes
    if (size == 0 || size > ARENA_SIZE)
        return nullptr;

    // Try allocating from each current arena
    for (auto &arena: arenas) {
        void *addr = arena.alloc(size);
        if (addr) {
            return addr;
        }
    }
    // If that fails, create a new one
    if (new_arena(ARENA_SIZE, ARENA_ALIGN)) {
        return arenas.back().alloc(size);
    }
    return nullptr;
}

void LockedPool::free(void *ptr)
{
    std::lock_guard<std::mutex> lock(mutex);
    // TODO we can do better than this linear search by keeping a map of arena
    // extents to arena, and looking up the address.
    for (auto &arena: arenas) {
        if (arena.addressInArena(ptr)) {
            arena.free(ptr);
            return;
        }
    }
    throw std::runtime_error("LockedPool: invalid address not pointing to any arena");
}

LockedPool::Stats LockedPool::stats() const
{
    std::lock_guard<std::mutex> lock(mutex);
    LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};
    for (const auto &arena: arenas) {
        Arena::Stats i = arena.stats();
        r.used += i.used;
        r.free += i.free;
        r.total += i.total;
        r.chunks_used += i.chunks_used;
        r.chunks_free += i.chunks_free;
    }
    return r;
}

bool LockedPool::new_arena(size_t size, size_t align)
{
    bool locked;
    // If this is the first arena, handle this specially: Cap the upper size
    // by the process limit. This makes sure that the first arena will at least
    // be locked. An exception to this is if the process limit is 0:
    // in this case no memory can be locked at all so we'll skip past this logic.
    if (arenas.empty()) {
        size_t limit = allocator->GetLimit();
        if (limit > 0) {
            size = std::min(size, limit);
        }
    }
    void *addr = allocator->AllocateLocked(size, &locked);
    if (!addr) {
        return false;
    }
    if (locked) {
        cumulative_bytes_locked += size;
    } else if (lf_cb) { // Call the locking-failed callback if locking failed
        if (!lf_cb()) { // If the callback returns false, free the memory and fail, otherwise consider the user warned and proceed.
            allocator->FreeLocked(addr, size);
            return false;
        }
    }
    arenas.emplace_back(allocator.get(), addr, size, align);
    return true;
}

LockedPool::LockedPageArena::LockedPageArena(LockedPageAllocator *allocator_in, void *base_in, size_t size_in, size_t align_in):
    Arena(base_in, size_in, align_in), base(base_in), size(size_in), allocator(allocator_in)
{
}
LockedPool::LockedPageArena::~LockedPageArena()
{
    allocator->FreeLocked(base, size);
}

/*******************************************************************************/
// Implementation: LockedPoolManager
//
LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator_in):
    LockedPool(std::move(allocator_in), &LockedPoolManager::LockingFailed)
{
}

bool LockedPoolManager::LockingFailed()
{
    // TODO: log something but how? without including util.h
    return true;
}

void LockedPoolManager::CreateInstance()
{
    // Using a local static instance guarantees that the object is initialized
    // when it's first needed and also deinitialized after all objects that use
    // it are done with it.  I can think of one unlikely scenario where we may
    // have a static deinitialization order/problem, but the check in
    // LockedPoolManagerBase's destructor helps us detect if that ever happens.
#ifdef WIN32
    std::unique_ptr<LockedPageAllocator> allocator(new Win32LockedPageAllocator());
#else
    std::unique_ptr<LockedPageAllocator> allocator(new PosixLockedPageAllocator());
#endif
    static LockedPoolManager instance(std::move(allocator));
    LockedPoolManager::_instance = &instance;
}
<|endoftext|>


<commit_before>#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif

#include <cassert>
#include <cerrno>
#include <cinttypes>
#include <climits>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <dlfcn.h>
#include <sys/syscall.h>
#include <sys/types.h>

#if defined(__APPLE__)
#include <execinfo.h>
#include <pthread.h>
#endif

#include <limits>
#include <mutex>
#include <new>
#include <unordered_map>

typedef void* (*Malloc)(size_t size);
typedef void (*Free)(void* pointer);

#if !defined(__APPLE__)
static Malloc native_malloc = NULL;
static Free native_free = NULL;
#endif

void* nonFailingMalloc(size_t size);
void nonFailingFree(void* pointer);

#define STRATEGY_RANDOM 0
#define STRATEGY_STEP 1
#define STRATEGY_PULSE 2

#define MIN_DUTY_CYCLE 1
#define MAX_DUTY_CYCLE 4096

#define MIN_DELAY 0
#define MAX_DELAY 1000

#define MIN_DURATION 1
#define MAX_DURATION 100

static const char* strategy_names[3] = { "random", "step", "pulse" };

static unsigned int activated = 0;
static unsigned int paused = 0;
static unsigned int strategy = STRATEGY_RANDOM;
static unsigned int seed = 0;
static unsigned int duty_cycle = 1024;
static unsigned delay = MIN_DELAY;
static unsigned duration = MIN_DURATION;
static unsigned int malloc_number = 0;
static unsigned int malloc_seq_num = 0;

#if defined(__APPLE__)
template<typename T>
class ThreadLocal final {
public:
    ThreadLocal() { pthread_key_create(&key, NULL); }
    ~ThreadLocal() { pthread_key_delete(key); }

    void operator=(const T* value) { set(value); }

    const T* operator*() const { return get(); }
    T* operator->() const { return get(); }
    operator bool() const { return get(); }
    operator T*() const { return get(); }

private:
    void set(const T* value) { pthread_setspecific(key, value); }
    T* get() const { return reinterpret_cast<T*>(pthread_getspecific(key)); }

    pthread_key_t key;
};

static ThreadLocal<void> is_tracing;
#endif

template<class T>
class mallocFreeAllocator {
public:
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T value_type;

    template<class U>
    struct rebind {
        typedef mallocFreeAllocator<U> other;
    };

    mallocFreeAllocator() throw() {}
    mallocFreeAllocator(const mallocFreeAllocator&) throw() {}

    template<class U>
    mallocFreeAllocator(const mallocFreeAllocator<U>&) throw()
    {
    }

    ~mallocFreeAllocator() throw() {}

    pointer address(reference x) const { return &x; }
    const_pointer address(const_reference x) const { return &x; }

    pointer allocate(size_type s, void const* = 0)
    {
        if (0 == s)
            return NULL;
        pointer temp = (pointer)nonFailingMalloc(s * sizeof(T));
        if (temp == NULL)
            throw std::bad_alloc();
        return temp;
    }

    void deallocate(pointer p, size_type) { nonFailingFree(p); }
    size_type max_size() const throw() { return std::numeric_limits<size_t>::max() / sizeof(T); }
    void construct(pointer p, const T& val) { new ((void*)p) T(val); }
    void destroy(pointer p) { p->~T(); }
};

static std::mutex mutex;
static std::unordered_map<void*, unsigned int, std::hash<void*>, std::equal_to<void*>, mallocFreeAllocator<std::pair<void* const, unsigned int>>> allocated;

__attribute__((constructor)) static void banner()
{
    fprintf(stderr, "overthrower is waiting for the activation signal ...\n");
    fprintf(stderr, "Invoke activateOverthrower and overthrower will start his job.\n");
}

#if !defined(__APPLE__)
static void initialize()
{
    if (native_malloc == NULL) {
        native_malloc = (Malloc)dlsym(RTLD_NEXT, "malloc");
        native_free = (Free)dlsym(RTLD_NEXT, "free");
    }
}
#endif

static int strToUnsignedLongInt(const char* str, unsigned long int* value)
{
    char* end_ptr;
    *value = strtoul(str, &end_ptr, 10);

    if (end_ptr[0] != '\0')
        return -1;

    if ((*value == 0 || *value == ULONG_MAX) && errno == ERANGE)
        return -1;

    return 0;
}

static unsigned int generateRandomValue(const unsigned int min_val, const unsigned int max_val)
{
    unsigned int value = (min_val + max_val) / 2;
    FILE* file = fopen("/dev/urandom", "rb");
    if (file != NULL) {
        if (fread(&value, 1, sizeof(int), file) != sizeof(int))
            value = (min_val + max_val) / 2;
        fclose(file);
    }
    value = value % (max_val - min_val + (max_val == UINT_MAX ? 0 : 1));
    value += min_val;
    return value;
}

static unsigned int readValFromEnvVar(const char* env_var_name, const unsigned int min_val, const unsigned int max_val)
{
    const char* env_var_val = getenv(env_var_name);
    unsigned long int value;

    if (env_var_val == NULL) {
        const unsigned int random_value = generateRandomValue(min_val, max_val);
        fprintf(stderr, "%s environment variable not set. Using a random value (%u).\n", env_var_name, random_value);
        return random_value;
    }
    else if (strToUnsignedLongInt(env_var_val, &value) || value < min_val || value > max_val) {
        const unsigned int random_value = generateRandomValue(min_val, max_val);
        fprintf(stderr, "%s has incorrect value (%s). Using a random value (%u).\n", env_var_name, env_var_val, random_value);
        return random_value;
    }

    return (unsigned int)value;
}

extern "C" void activateOverthrower()
{
#if defined(__APPLE__)
    // Mac OS X implementation uses malloc inside printf.
    // To prevent crashes we have to force printf to do all his allocations before
    // we activated the overthrower.
    static const int integer_number = 22708089;
    static const double floating_point_number = 22708089.862725008;
    char tmp_buf[1024];
    for (int i = 0; i < 1000; ++i)
        sprintf(tmp_buf, "%d%f\n", integer_number * i * i, floating_point_number * i * i);
    printf("overthrower have to print useless string to force printf to do all preallocations: %s", tmp_buf);
#endif

    fprintf(stderr, "overthrower got activation signal.\n");
    fprintf(stderr, "overthrower will use following parameters for failing allocations:\n");
    strategy = readValFromEnvVar("OVERTHROWER_STRATEGY", STRATEGY_RANDOM, STRATEGY_PULSE);
    fprintf(stderr, "Strategy = %s\n", strategy_names[strategy]);
    if (strategy == STRATEGY_RANDOM) {
        seed = readValFromEnvVar("OVERTHROWER_SEED", 0, UINT_MAX);
        duty_cycle = readValFromEnvVar("OVERTHROWER_DUTY_CYCLE", MIN_DUTY_CYCLE, MAX_DUTY_CYCLE);
        srand(seed);
        fprintf(stderr, "Duty cycle = %u\n", duty_cycle);
        fprintf(stderr, "Seed = %u\n", seed);
    }
    else {
        delay = readValFromEnvVar("OVERTHROWER_DELAY", MIN_DELAY, MAX_DELAY);
        fprintf(stderr, "Delay = %u\n", delay);
        if (strategy == STRATEGY_PULSE) {
            duration = readValFromEnvVar("OVERTHROWER_DURATION", MIN_DURATION, MAX_DURATION);
            fprintf(stderr, "Duration = %u\n", duration);
        }
    }
    activated = 1;
}

extern "C" int deactivateOverthrower()
{
    activated = 0;

    fprintf(stderr, "overthrower got deactivation signal.\n");
    fprintf(stderr, "overthrower will not fail allocations anymore.\n");

    if (!allocated.empty()) {
        fprintf(stderr, "overthrower has detected not freed memory blocks with following addresses:\n");
        for (const auto& v : allocated)
            fprintf(stderr, "0x%016" PRIxPTR " - %6d\n", (uintptr_t)v.first, v.second);
    }
    return allocated.size();
}

extern "C" void pauseOverthrower(unsigned int duration)
{
    paused = duration == 0 ? UINT_MAX : duration;
}

extern "C" void resumeOverthrower()
{
    paused = 0;
}

static int isTimeToFail()
{
    switch (strategy) {
        case STRATEGY_RANDOM:
            return ((unsigned int)rand() % duty_cycle == 0) ? 1 : 0;
        case STRATEGY_STEP:
            return (__sync_add_and_fetch(&malloc_number, 1) + 1 > delay) ? 1 : 0;
        case STRATEGY_PULSE: {
            unsigned int number = __sync_add_and_fetch(&malloc_number, 1) + 1;
            return (number > delay && number < delay + duration) ? 1 : 0;
        }
        default:
            assert(0);
            return 0;
    }
}

void* nonFailingMalloc(size_t size)
{
#if defined(__APPLE__)
    return malloc(size);
#else
    return native_malloc ? native_malloc(size) : malloc(size);
#endif
}

void nonFailingFree(void* pointer)
{
#if defined(__APPLE__)
    return free(pointer);
#else
    return native_free(pointer);
#endif
}

#if defined(__APPLE__)
static bool isInWhiteList()
{
    void* callstack[4];
    const int count = backtrace(callstack, 4);
    char** symbols = backtrace_symbols(callstack, count);

    if (!symbols)
        return true;

    bool is_in_white_list = false;

    if (count >= 4 && strstr(symbols[3], "__cxa_allocate_exception"))
        is_in_white_list = true;

#if 0
    for (int i = 1; i < count; ++i )
        printf("%s\n", symbols[i]);
#endif

    free(symbols);

    return is_in_white_list;
}
#endif

#if defined(__APPLE__)
void* my_malloc(size_t size)
#else
void* malloc(size_t size)
#endif
{
#if !defined(__APPLE__)
    static const bool is_in_white_list = false;
#endif
    void* pointer;

#if !defined(__APPLE__)
    if (native_malloc == NULL)
        initialize();
#endif

#if defined(__APPLE__)
    bool is_in_white_list = is_tracing;

    if (!is_tracing) {
        is_tracing = reinterpret_cast<void*>(-1);
        const unsigned int old_paused = paused;
        pauseOverthrower(0);
        is_in_white_list = isInWhiteList();
        paused = old_paused;
        is_tracing = nullptr;
    }
#endif

    if (!is_in_white_list && (activated != 0) && (paused == 0) && (size != 0) && isTimeToFail()) {
        errno = ENOMEM;
        return NULL;
    }

    pointer = nonFailingMalloc(size);

    if (activated != 0 && pointer != NULL && paused == 0) {
        std::lock_guard<std::mutex> lock(mutex);
        malloc_seq_num++;
        allocated.insert({ pointer, malloc_seq_num });
    }

    if (paused)
        --paused;

    return pointer;
}

#if defined(__APPLE__)
void my_free(void* pointer)
#else
void free(void* pointer)
#endif
{
    int old_errno = errno;
    if (activated != 0 && pointer != NULL) {
        std::lock_guard<std::mutex> lock(mutex);
        allocated.erase(pointer);
    }

#if defined(__APPLE__)
    free(pointer);
#else
    native_free(pointer);
#endif
    errno = old_errno;
}

#if defined(__APPLE__)
typedef struct interpose_s {
    void* substitute;
    void* original;
} interpose_t;

__attribute__((used)) static const interpose_t interposing_functions[]
    __attribute__((section("__DATA, __interpose"))) = { { (void*)my_malloc, (void*)malloc }, { (void*)my_free, (void*)free } };
#endif
<commit_msg>Add strategy none which does not fail allocations. Only checks for memory leaks.<commit_after>#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif

#include <cassert>
#include <cerrno>
#include <cinttypes>
#include <climits>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <dlfcn.h>
#include <sys/syscall.h>
#include <sys/types.h>

#if defined(__APPLE__)
#include <execinfo.h>
#include <pthread.h>
#endif

#include <limits>
#include <mutex>
#include <new>
#include <unordered_map>

typedef void* (*Malloc)(size_t size);
typedef void (*Free)(void* pointer);

#if !defined(__APPLE__)
static Malloc native_malloc = NULL;
static Free native_free = NULL;
#endif

void* nonFailingMalloc(size_t size);
void nonFailingFree(void* pointer);

#define STRATEGY_RANDOM 0
#define STRATEGY_STEP 1
#define STRATEGY_PULSE 2
#define STRATEGY_NONE 3

#define MIN_DUTY_CYCLE 1
#define MAX_DUTY_CYCLE 4096

#define MIN_DELAY 0
#define MAX_DELAY 1000

#define MIN_DURATION 1
#define MAX_DURATION 100

static const char* strategy_names[4] = { "random", "step", "pulse", "none" };

static unsigned int activated = 0;
static unsigned int paused = 0;
static unsigned int strategy = STRATEGY_RANDOM;
static unsigned int seed = 0;
static unsigned int duty_cycle = 1024;
static unsigned delay = MIN_DELAY;
static unsigned duration = MIN_DURATION;
static unsigned int malloc_number = 0;
static unsigned int malloc_seq_num = 0;

#if defined(__APPLE__)
template<typename T>
class ThreadLocal final {
public:
    ThreadLocal() { pthread_key_create(&key, NULL); }
    ~ThreadLocal() { pthread_key_delete(key); }

    void operator=(const T* value) { set(value); }

    const T* operator*() const { return get(); }
    T* operator->() const { return get(); }
    operator bool() const { return get(); }
    operator T*() const { return get(); }

private:
    void set(const T* value) { pthread_setspecific(key, value); }
    T* get() const { return reinterpret_cast<T*>(pthread_getspecific(key)); }

    pthread_key_t key;
};

static ThreadLocal<void> is_tracing;
#endif

template<class T>
class mallocFreeAllocator {
public:
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T value_type;

    template<class U>
    struct rebind {
        typedef mallocFreeAllocator<U> other;
    };

    mallocFreeAllocator() throw() {}
    mallocFreeAllocator(const mallocFreeAllocator&) throw() {}

    template<class U>
    mallocFreeAllocator(const mallocFreeAllocator<U>&) throw()
    {
    }

    ~mallocFreeAllocator() throw() {}

    pointer address(reference x) const { return &x; }
    const_pointer address(const_reference x) const { return &x; }

    pointer allocate(size_type s, void const* = 0)
    {
        if (0 == s)
            return NULL;
        pointer temp = (pointer)nonFailingMalloc(s * sizeof(T));
        if (temp == NULL)
            throw std::bad_alloc();
        return temp;
    }

    void deallocate(pointer p, size_type) { nonFailingFree(p); }
    size_type max_size() const throw() { return std::numeric_limits<size_t>::max() / sizeof(T); }
    void construct(pointer p, const T& val) { new ((void*)p) T(val); }
    void destroy(pointer p) { p->~T(); }
};

static std::mutex mutex;
static std::unordered_map<void*, unsigned int, std::hash<void*>, std::equal_to<void*>, mallocFreeAllocator<std::pair<void* const, unsigned int>>> allocated;

__attribute__((constructor)) static void banner()
{
    fprintf(stderr, "overthrower is waiting for the activation signal ...\n");
    fprintf(stderr, "Invoke activateOverthrower and overthrower will start his job.\n");
}

#if !defined(__APPLE__)
static void initialize()
{
    if (native_malloc == NULL) {
        native_malloc = (Malloc)dlsym(RTLD_NEXT, "malloc");
        native_free = (Free)dlsym(RTLD_NEXT, "free");
    }
}
#endif

static int strToUnsignedLongInt(const char* str, unsigned long int* value)
{
    char* end_ptr;
    *value = strtoul(str, &end_ptr, 10);

    if (end_ptr[0] != '\0')
        return -1;

    if ((*value == 0 || *value == ULONG_MAX) && errno == ERANGE)
        return -1;

    return 0;
}

static unsigned int generateRandomValue(const unsigned int min_val, const unsigned int max_val)
{
    unsigned int value = (min_val + max_val) / 2;
    FILE* file = fopen("/dev/urandom", "rb");
    if (file != NULL) {
        if (fread(&value, 1, sizeof(int), file) != sizeof(int))
            value = (min_val + max_val) / 2;
        fclose(file);
    }
    value = value % (max_val - min_val + (max_val == UINT_MAX ? 0 : 1));
    value += min_val;
    return value;
}

static unsigned int readValFromEnvVar(const char* env_var_name, const unsigned int min_val, const unsigned int max_val)
{
    const char* env_var_val = getenv(env_var_name);
    unsigned long int value;

    if (env_var_val == NULL) {
        const unsigned int random_value = generateRandomValue(min_val, max_val);
        fprintf(stderr, "%s environment variable not set. Using a random value (%u).\n", env_var_name, random_value);
        return random_value;
    }
    else if (strToUnsignedLongInt(env_var_val, &value) || value < min_val || value > max_val) {
        const unsigned int random_value = generateRandomValue(min_val, max_val);
        fprintf(stderr, "%s has incorrect value (%s). Using a random value (%u).\n", env_var_name, env_var_val, random_value);
        return random_value;
    }

    return (unsigned int)value;
}

extern "C" void activateOverthrower()
{
#if defined(__APPLE__)
    // Mac OS X implementation uses malloc inside printf.
    // To prevent crashes we have to force printf to do all his allocations before
    // we activated the overthrower.
    static const int integer_number = 22708089;
    static const double floating_point_number = 22708089.862725008;
    char tmp_buf[1024];
    for (int i = 0; i < 1000; ++i)
        sprintf(tmp_buf, "%d%f\n", integer_number * i * i, floating_point_number * i * i);
    printf("overthrower have to print useless string to force printf to do all preallocations: %s", tmp_buf);
#endif

    fprintf(stderr, "overthrower got activation signal.\n");
    fprintf(stderr, "overthrower will use following parameters for failing allocations:\n");
    strategy = readValFromEnvVar("OVERTHROWER_STRATEGY", STRATEGY_RANDOM, STRATEGY_NONE);
    fprintf(stderr, "Strategy = %s\n", strategy_names[strategy]);
    if (strategy == STRATEGY_RANDOM) {
        seed = readValFromEnvVar("OVERTHROWER_SEED", 0, UINT_MAX);
        duty_cycle = readValFromEnvVar("OVERTHROWER_DUTY_CYCLE", MIN_DUTY_CYCLE, MAX_DUTY_CYCLE);
        srand(seed);
        fprintf(stderr, "Duty cycle = %u\n", duty_cycle);
        fprintf(stderr, "Seed = %u\n", seed);
    }
    else if (strategy != STRATEGY_NONE) {
        delay = readValFromEnvVar("OVERTHROWER_DELAY", MIN_DELAY, MAX_DELAY);
        fprintf(stderr, "Delay = %u\n", delay);
        if (strategy == STRATEGY_PULSE) {
            duration = readValFromEnvVar("OVERTHROWER_DURATION", MIN_DURATION, MAX_DURATION);
            fprintf(stderr, "Duration = %u\n", duration);
        }
    }
    activated = 1;
}

extern "C" int deactivateOverthrower()
{
    activated = 0;

    fprintf(stderr, "overthrower got deactivation signal.\n");
    fprintf(stderr, "overthrower will not fail allocations anymore.\n");

    if (!allocated.empty()) {
        fprintf(stderr, "overthrower has detected not freed memory blocks with following addresses:\n");
        for (const auto& v : allocated)
            fprintf(stderr, "0x%016" PRIxPTR " - %6d\n", (uintptr_t)v.first, v.second);
    }
    return allocated.size();
}

extern "C" void pauseOverthrower(unsigned int duration)
{
    paused = duration == 0 ? UINT_MAX : duration;
}

extern "C" void resumeOverthrower()
{
    paused = 0;
}

static int isTimeToFail()
{
    switch (strategy) {
        case STRATEGY_RANDOM:
            return ((unsigned int)rand() % duty_cycle == 0) ? 1 : 0;
        case STRATEGY_STEP:
            return (__sync_add_and_fetch(&malloc_number, 1) + 1 > delay) ? 1 : 0;
        case STRATEGY_PULSE: {
            unsigned int number = __sync_add_and_fetch(&malloc_number, 1) + 1;
            return (number > delay && number < delay + duration) ? 1 : 0;
        }
        case STRATEGY_NONE:
            return 0;
        default:
            assert(0);
            return 0;
    }
}

void* nonFailingMalloc(size_t size)
{
#if defined(__APPLE__)
    return malloc(size);
#else
    return native_malloc ? native_malloc(size) : malloc(size);
#endif
}

void nonFailingFree(void* pointer)
{
#if defined(__APPLE__)
    return free(pointer);
#else
    return native_free(pointer);
#endif
}

#if defined(__APPLE__)
static bool isInWhiteList()
{
    void* callstack[4];
    const int count = backtrace(callstack, 4);
    char** symbols = backtrace_symbols(callstack, count);

    if (!symbols)
        return true;

    bool is_in_white_list = false;

    if (count >= 4 && strstr(symbols[3], "__cxa_allocate_exception"))
        is_in_white_list = true;

#if 0
    for (int i = 1; i < count; ++i )
        printf("%s\n", symbols[i]);
#endif

    free(symbols);

    return is_in_white_list;
}
#endif

#if defined(__APPLE__)
void* my_malloc(size_t size)
#else
void* malloc(size_t size)
#endif
{
#if !defined(__APPLE__)
    static const bool is_in_white_list = false;
#endif
    void* pointer;

#if !defined(__APPLE__)
    if (native_malloc == NULL)
        initialize();
#endif

#if defined(__APPLE__)
    bool is_in_white_list = is_tracing;

    if (!is_tracing) {
        is_tracing = reinterpret_cast<void*>(-1);
        const unsigned int old_paused = paused;
        pauseOverthrower(0);
        is_in_white_list = isInWhiteList();
        paused = old_paused;
        is_tracing = nullptr;
    }
#endif

    if (!is_in_white_list && (activated != 0) && (paused == 0) && (size != 0) && isTimeToFail()) {
        errno = ENOMEM;
        return NULL;
    }

    pointer = nonFailingMalloc(size);

    if (activated != 0 && pointer != NULL && paused == 0) {
        std::lock_guard<std::mutex> lock(mutex);
        malloc_seq_num++;
        allocated.insert({ pointer, malloc_seq_num });
    }

    if (paused)
        --paused;

    return pointer;
}

#if defined(__APPLE__)
void my_free(void* pointer)
#else
void free(void* pointer)
#endif
{
    int old_errno = errno;
    if (activated != 0 && pointer != NULL) {
        std::lock_guard<std::mutex> lock(mutex);
        allocated.erase(pointer);
    }

#if defined(__APPLE__)
    free(pointer);
#else
    native_free(pointer);
#endif
    errno = old_errno;
}

#if defined(__APPLE__)
typedef struct interpose_s {
    void* substitute;
    void* original;
} interpose_t;

__attribute__((used)) static const interpose_t interposing_functions[]
    __attribute__((section("__DATA, __interpose"))) = { { (void*)my_malloc, (void*)malloc }, { (void*)my_free, (void*)free } };
#endif
<|endoftext|>